Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / tools / clang / blink_gc_plugin / BlinkGCPlugin.cpp
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This clang plugin checks various invariants of the Blink garbage
6 // collection infrastructure.
7 //
8 // Errors are described at:
9 // http://www.chromium.org/developers/blink-gc-plugin-errors
10
11 #include "Config.h"
12 #include "JsonWriter.h"
13 #include "RecordInfo.h"
14
15 #include "clang/AST/AST.h"
16 #include "clang/AST/ASTConsumer.h"
17 #include "clang/AST/RecursiveASTVisitor.h"
18 #include "clang/Frontend/CompilerInstance.h"
19 #include "clang/Frontend/FrontendPluginRegistry.h"
20
21 using namespace clang;
22 using std::string;
23
24 namespace {
25
26 const char kClassMustLeftMostlyDeriveGC[] =
27     "[blink-gc] Class %0 must derive its GC base in the left-most position.";
28
29 const char kClassRequiresTraceMethod[] =
30     "[blink-gc] Class %0 requires a trace method"
31     " because it contains fields that require tracing.";
32
33 const char kBaseRequiresTracing[] =
34     "[blink-gc] Base class %0 of derived class %1 requires tracing.";
35
36 const char kFieldsRequireTracing[] =
37     "[blink-gc] Class %0 has untraced fields that require tracing.";
38
39 const char kFieldRequiresTracingNote[] =
40     "[blink-gc] Untraced field %0 declared here:";
41
42 const char kClassContainsInvalidFields[] =
43     "[blink-gc] Class %0 contains invalid fields.";
44
45 const char kClassContainsGCRoot[] =
46     "[blink-gc] Class %0 contains GC root in field %1.";
47
48 const char kClassRequiresFinalization[] =
49     "[blink-gc] Class %0 requires finalization.";
50
51 const char kFinalizerAccessesFinalizedField[] =
52     "[blink-gc] Finalizer %0 accesses potentially finalized field %1.";
53
54 const char kRawPtrToGCManagedClassNote[] =
55     "[blink-gc] Raw pointer field %0 to a GC managed class declared here:";
56
57 const char kRefPtrToGCManagedClassNote[] =
58     "[blink-gc] RefPtr field %0 to a GC managed class declared here:";
59
60 const char kOwnPtrToGCManagedClassNote[] =
61     "[blink-gc] OwnPtr field %0 to a GC managed class declared here:";
62
63 const char kStackAllocatedFieldNote[] =
64     "[blink-gc] Stack-allocated field %0 declared here:";
65
66 const char kMemberInUnmanagedClassNote[] =
67     "[blink-gc] Member field %0 in unmanaged class declared here:";
68
69 const char kPartObjectContainsGCRoot[] =
70     "[blink-gc] Field %0 with embedded GC root in %1 declared here:";
71
72 const char kFieldContainsGCRoot[] =
73     "[blink-gc] Field %0 defining a GC root declared here:";
74
75 const char kOverriddenNonVirtualTrace[] =
76     "[blink-gc] Class %0 overrides non-virtual trace of base class %1.";
77
78 const char kOverriddenNonVirtualTraceNote[] =
79     "[blink-gc] Non-virtual trace method declared here:";
80
81 const char kMissingTraceDispatchMethod[] =
82     "[blink-gc] Class %0 is missing manual trace dispatch.";
83
84 const char kMissingFinalizeDispatchMethod[] =
85     "[blink-gc] Class %0 is missing manual finalize dispatch.";
86
87 const char kVirtualAndManualDispatch[] =
88     "[blink-gc] Class %0 contains or inherits virtual methods"
89     " but implements manual dispatching.";
90
91 const char kMissingTraceDispatch[] =
92     "[blink-gc] Missing dispatch to class %0 in manual trace dispatch.";
93
94 const char kMissingFinalizeDispatch[] =
95     "[blink-gc] Missing dispatch to class %0 in manual finalize dispatch.";
96
97 const char kFinalizedFieldNote[] =
98     "[blink-gc] Potentially finalized field %0 declared here:";
99
100 const char kUserDeclaredDestructorNote[] =
101     "[blink-gc] User-declared destructor declared here:";
102
103 const char kUserDeclaredFinalizerNote[] =
104     "[blink-gc] User-declared finalizer declared here:";
105
106 const char kBaseRequiresFinalizationNote[] =
107     "[blink-gc] Base class %0 requiring finalization declared here:";
108
109 const char kFieldRequiresFinalizationNote[] =
110     "[blink-gc] Field %0 requiring finalization declared here:";
111
112 const char kManualDispatchMethodNote[] =
113     "[blink-gc] Manual dispatch %0 declared here:";
114
115 const char kDerivesNonStackAllocated[] =
116     "[blink-gc] Stack-allocated class %0 derives class %1"
117     " which is not stack allocated.";
118
119 const char kClassOverridesNew[] =
120     "[blink-gc] Garbage collected class %0"
121     " is not permitted to override its new operator.";
122
123 struct BlinkGCPluginOptions {
124   BlinkGCPluginOptions() : enable_oilpan(false), dump_graph(false) {}
125   bool enable_oilpan;
126   bool dump_graph;
127   std::set<std::string> ignored_classes;
128   std::set<std::string> checked_namespaces;
129   std::vector<std::string> ignored_directories;
130 };
131
132 typedef std::vector<CXXRecordDecl*> RecordVector;
133 typedef std::vector<CXXMethodDecl*> MethodVector;
134
135 // Test if a template specialization is an instantiation.
136 static bool IsTemplateInstantiation(CXXRecordDecl* record) {
137   ClassTemplateSpecializationDecl* spec =
138       dyn_cast<ClassTemplateSpecializationDecl>(record);
139   if (!spec)
140     return false;
141   switch (spec->getTemplateSpecializationKind()) {
142     case TSK_ImplicitInstantiation:
143     case TSK_ExplicitInstantiationDefinition:
144       return true;
145     case TSK_Undeclared:
146     case TSK_ExplicitSpecialization:
147       return false;
148     // TODO: unsupported cases.
149     case TSK_ExplicitInstantiationDeclaration:
150       return false;
151   }
152   assert(false && "Unknown template specialization kind");
153 }
154
155 // This visitor collects the entry points for the checker.
156 class CollectVisitor : public RecursiveASTVisitor<CollectVisitor> {
157  public:
158   CollectVisitor() {}
159
160   RecordVector& record_decls() { return record_decls_; }
161   MethodVector& trace_decls() { return trace_decls_; }
162
163   bool shouldVisitTemplateInstantiations() { return false; }
164
165   // Collect record declarations, including nested declarations.
166   bool VisitCXXRecordDecl(CXXRecordDecl* record) {
167     if (record->hasDefinition() && record->isCompleteDefinition())
168       record_decls_.push_back(record);
169     return true;
170   }
171
172   // Collect tracing method definitions, but don't traverse method bodies.
173   bool TraverseCXXMethodDecl(CXXMethodDecl* method) {
174     if (method->isThisDeclarationADefinition() && Config::IsTraceMethod(method))
175       trace_decls_.push_back(method);
176     return true;
177   }
178
179  private:
180   RecordVector record_decls_;
181   MethodVector trace_decls_;
182 };
183
184 // This visitor checks that a finalizer method does not have invalid access to
185 // fields that are potentially finalized. A potentially finalized field is
186 // either a Member, a heap-allocated collection or an off-heap collection that
187 // contains Members.  Invalid uses are currently identified as passing the field
188 // as the argument of a procedure call or using the -> or [] operators on it.
189 class CheckFinalizerVisitor
190     : public RecursiveASTVisitor<CheckFinalizerVisitor> {
191  private:
192   // Simple visitor to determine if the content of a field might be collected
193   // during finalization.
194   class MightBeCollectedVisitor : public EdgeVisitor {
195    public:
196     MightBeCollectedVisitor() : might_be_collected_(false) {}
197     bool might_be_collected() { return might_be_collected_; }
198     void VisitMember(Member* edge) override { might_be_collected_ = true; }
199     void VisitCollection(Collection* edge) override {
200       if (edge->on_heap()) {
201         might_be_collected_ = !edge->is_root();
202       } else {
203         edge->AcceptMembers(this);
204       }
205     }
206
207    private:
208     bool might_be_collected_;
209   };
210
211  public:
212   typedef std::vector<std::pair<MemberExpr*, FieldPoint*> > Errors;
213
214   CheckFinalizerVisitor(RecordCache* cache)
215       : blacklist_context_(false), cache_(cache) {}
216
217   Errors& finalized_fields() { return finalized_fields_; }
218
219   bool WalkUpFromCXXOperatorCallExpr(CXXOperatorCallExpr* expr) {
220     // Only continue the walk-up if the operator is a blacklisted one.
221     switch (expr->getOperator()) {
222       case OO_Arrow:
223       case OO_Subscript:
224         this->WalkUpFromCallExpr(expr);
225       default:
226         return true;
227     }
228   }
229
230   // We consider all non-operator calls to be blacklisted contexts.
231   bool WalkUpFromCallExpr(CallExpr* expr) {
232     bool prev_blacklist_context = blacklist_context_;
233     blacklist_context_ = true;
234     for (size_t i = 0; i < expr->getNumArgs(); ++i)
235       this->TraverseStmt(expr->getArg(i));
236     blacklist_context_ = prev_blacklist_context;
237     return true;
238   }
239
240   bool VisitMemberExpr(MemberExpr* member) {
241     FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl());
242     if (!field)
243       return true;
244
245     RecordInfo* info = cache_->Lookup(field->getParent());
246     if (!info)
247       return true;
248
249     RecordInfo::Fields::iterator it = info->GetFields().find(field);
250     if (it == info->GetFields().end())
251       return true;
252
253     if (blacklist_context_ && MightBeCollected(&it->second))
254       finalized_fields_.push_back(std::make_pair(member, &it->second));
255     return true;
256   }
257
258   bool MightBeCollected(FieldPoint* point) {
259     MightBeCollectedVisitor visitor;
260     point->edge()->Accept(&visitor);
261     return visitor.might_be_collected();
262   }
263
264  private:
265   bool blacklist_context_;
266   Errors finalized_fields_;
267   RecordCache* cache_;
268 };
269
270 // This visitor checks that a method contains within its body, a call to a
271 // method on the provided receiver class. This is used to check manual
272 // dispatching for trace and finalize methods.
273 class CheckDispatchVisitor : public RecursiveASTVisitor<CheckDispatchVisitor> {
274  public:
275   CheckDispatchVisitor(RecordInfo* receiver)
276       : receiver_(receiver), dispatched_to_receiver_(false) {}
277
278   bool dispatched_to_receiver() { return dispatched_to_receiver_; }
279
280   bool VisitMemberExpr(MemberExpr* member) {
281     if (CXXMethodDecl* fn = dyn_cast<CXXMethodDecl>(member->getMemberDecl())) {
282       if (fn->getParent() == receiver_->record())
283         dispatched_to_receiver_ = true;
284     }
285     return true;
286   }
287
288  private:
289   RecordInfo* receiver_;
290   bool dispatched_to_receiver_;
291 };
292
293 // This visitor checks a tracing method by traversing its body.
294 // - A member field is considered traced if it is referenced in the body.
295 // - A base is traced if a base-qualified call to a trace method is found.
296 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> {
297  public:
298   CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info)
299       : trace_(trace), info_(info) {}
300
301   // Allow recursive traversal by using VisitMemberExpr.
302   bool VisitMemberExpr(MemberExpr* member) {
303     // If this member expression references a field decl, mark it as traced.
304     if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) {
305       if (IsTemplateInstantiation(info_->record())) {
306         // Pointer equality on fields does not work for template instantiations.
307         // The trace method refers to fields of the template definition which
308         // are different from the instantiated fields that need to be traced.
309         const string& name = field->getNameAsString();
310         for (RecordInfo::Fields::iterator it = info_->GetFields().begin();
311              it != info_->GetFields().end();
312              ++it) {
313           if (it->first->getNameAsString() == name) {
314             MarkTraced(it);
315             break;
316           }
317         }
318       } else {
319         RecordInfo::Fields::iterator it = info_->GetFields().find(field);
320         if (it != info_->GetFields().end())
321           MarkTraced(it);
322       }
323       return true;
324     }
325
326     // If this is a weak callback function we only check field tracing.
327     if (IsWeakCallback())
328       return true;
329
330     // For method calls, check tracing of bases and other special GC methods.
331     if (CXXMethodDecl* fn = dyn_cast<CXXMethodDecl>(member->getMemberDecl())) {
332       const string& name = fn->getNameAsString();
333       // Check weak callbacks.
334       if (name == kRegisterWeakMembersName) {
335         if (fn->isTemplateInstantiation()) {
336           const TemplateArgumentList& args =
337               *fn->getTemplateSpecializationInfo()->TemplateArguments;
338           // The second template argument is the callback method.
339           if (args.size() > 1 &&
340               args[1].getKind() == TemplateArgument::Declaration) {
341             if (FunctionDecl* callback =
342                     dyn_cast<FunctionDecl>(args[1].getAsDecl())) {
343               if (callback->hasBody()) {
344                 CheckTraceVisitor nested_visitor(info_);
345                 nested_visitor.TraverseStmt(callback->getBody());
346               }
347             }
348           }
349         }
350         return true;
351       }
352
353       // TODO: It is possible to have multiple bases, where one must be traced
354       // using a traceAfterDispatch. In such a case we should also check that
355       // the mixin does not add a vtable.
356       if (Config::IsTraceMethod(fn) && member->hasQualifier()) {
357         if (const Type* type = member->getQualifier()->getAsType()) {
358           if (CXXRecordDecl* decl = type->getAsCXXRecordDecl()) {
359             RecordInfo::Bases::iterator it = info_->GetBases().find(decl);
360             if (it != info_->GetBases().end())
361               it->second.MarkTraced();
362           }
363         }
364       }
365     }
366     return true;
367   }
368
369  private:
370   // Nested checking for weak callbacks.
371   CheckTraceVisitor(RecordInfo* info) : trace_(0), info_(info) {}
372
373   bool IsWeakCallback() { return !trace_; }
374
375   void MarkTraced(RecordInfo::Fields::iterator it) {
376     // In a weak callback we can't mark strong fields as traced.
377     if (IsWeakCallback() && !it->second.edge()->IsWeakMember())
378       return;
379     it->second.MarkTraced();
380   }
381
382   CXXMethodDecl* trace_;
383   RecordInfo* info_;
384 };
385
386 // This visitor checks that the fields of a class and the fields of
387 // its part objects don't define GC roots.
388 class CheckGCRootsVisitor : public RecursiveEdgeVisitor {
389  public:
390   typedef std::vector<FieldPoint*> RootPath;
391   typedef std::vector<RootPath> Errors;
392
393   CheckGCRootsVisitor() {}
394
395   Errors& gc_roots() { return gc_roots_; }
396
397   bool ContainsGCRoots(RecordInfo* info) {
398     for (RecordInfo::Fields::iterator it = info->GetFields().begin();
399          it != info->GetFields().end();
400          ++it) {
401       current_.push_back(&it->second);
402       it->second.edge()->Accept(this);
403       current_.pop_back();
404     }
405     return !gc_roots_.empty();
406   }
407
408   void VisitValue(Value* edge) override {
409     // TODO: what should we do to check unions?
410     if (edge->value()->record()->isUnion())
411       return;
412
413     // If the value is a part object, then continue checking for roots.
414     for (Context::iterator it = context().begin();
415          it != context().end();
416          ++it) {
417       if (!(*it)->IsCollection())
418         return;
419     }
420     ContainsGCRoots(edge->value());
421   }
422
423   void VisitPersistent(Persistent* edge) override {
424     gc_roots_.push_back(current_);
425   }
426
427   void AtCollection(Collection* edge) override {
428     if (edge->is_root())
429       gc_roots_.push_back(current_);
430   }
431
432  protected:
433   RootPath current_;
434   Errors gc_roots_;
435 };
436
437 // This visitor checks that the fields of a class are "well formed".
438 // - OwnPtr, RefPtr and RawPtr must not point to a GC derived types.
439 // - An on-heap class must never contain GC roots.
440 // - Only stack-allocated types may point to stack-allocated types.
441 class CheckFieldsVisitor : public RecursiveEdgeVisitor {
442  public:
443   typedef std::vector<std::pair<FieldPoint*, Edge*> > Errors;
444
445   CheckFieldsVisitor(const BlinkGCPluginOptions& options)
446       : options_(options), current_(0), stack_allocated_host_(false) {}
447
448   Errors& invalid_fields() { return invalid_fields_; }
449
450   bool ContainsInvalidFields(RecordInfo* info) {
451     stack_allocated_host_ = info->IsStackAllocated();
452     managed_host_ = stack_allocated_host_ ||
453                     info->IsGCAllocated() ||
454                     info->IsNonNewable() ||
455                     info->IsOnlyPlacementNewable();
456     for (RecordInfo::Fields::iterator it = info->GetFields().begin();
457          it != info->GetFields().end();
458          ++it) {
459       context().clear();
460       current_ = &it->second;
461       current_->edge()->Accept(this);
462     }
463     return !invalid_fields_.empty();
464   }
465
466   void VisitMember(Member* edge) override {
467     if (managed_host_)
468       return;
469     // A member is allowed to appear in the context of a root.
470     for (Context::iterator it = context().begin();
471          it != context().end();
472          ++it) {
473       if ((*it)->Kind() == Edge::kRoot)
474         return;
475     }
476     invalid_fields_.push_back(std::make_pair(current_, edge));
477   }
478
479   void VisitValue(Value* edge) override {
480     // TODO: what should we do to check unions?
481     if (edge->value()->record()->isUnion())
482       return;
483
484     if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) {
485       invalid_fields_.push_back(std::make_pair(current_, edge));
486       return;
487     }
488
489     if (!Parent() || !edge->value()->IsGCAllocated())
490       return;
491
492     // In transition mode, disallow  OwnPtr<T>, RawPtr<T> to GC allocated T's,
493     // also disallow T* in stack-allocated types.
494     if (options_.enable_oilpan) {
495       if (Parent()->IsOwnPtr() ||
496           Parent()->IsRawPtrClass() ||
497           (stack_allocated_host_ && Parent()->IsRawPtr() &&
498            // TODO: Remove this exception once the node hierarchy is moved.
499            !edge->value()->IsTreeShared())) {
500         invalid_fields_.push_back(std::make_pair(current_, Parent()));
501         return;
502       }
503
504       return;
505     }
506
507     if (Parent()->IsRawPtr() || Parent()->IsRefPtr() || Parent()->IsOwnPtr()) {
508       invalid_fields_.push_back(std::make_pair(current_, Parent()));
509       return;
510     }
511   }
512
513  private:
514   const BlinkGCPluginOptions& options_;
515   FieldPoint* current_;
516   bool stack_allocated_host_;
517   bool managed_host_;
518   Errors invalid_fields_;
519 };
520
521 // Main class containing checks for various invariants of the Blink
522 // garbage collection infrastructure.
523 class BlinkGCPluginConsumer : public ASTConsumer {
524  public:
525   BlinkGCPluginConsumer(CompilerInstance& instance,
526                         const BlinkGCPluginOptions& options)
527       : instance_(instance),
528         diagnostic_(instance.getDiagnostics()),
529         options_(options),
530         json_(0) {
531
532     // Only check structures in the blink, WebCore and WebKit namespaces.
533     options_.checked_namespaces.insert("blink");
534     options_.checked_namespaces.insert("WebCore");
535     options_.checked_namespaces.insert("WebKit");
536
537     // Ignore GC implementation files.
538     options_.ignored_directories.push_back("/heap/");
539
540     // Register warning/error messages.
541     diag_class_must_left_mostly_derive_gc_ = diagnostic_.getCustomDiagID(
542         getErrorLevel(), kClassMustLeftMostlyDeriveGC);
543     diag_class_requires_trace_method_ =
544         diagnostic_.getCustomDiagID(getErrorLevel(), kClassRequiresTraceMethod);
545     diag_base_requires_tracing_ =
546         diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresTracing);
547     diag_fields_require_tracing_ =
548         diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing);
549     diag_class_contains_invalid_fields_ = diagnostic_.getCustomDiagID(
550         getErrorLevel(), kClassContainsInvalidFields);
551     diag_class_contains_gc_root_ =
552         diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRoot);
553     diag_class_requires_finalization_ = diagnostic_.getCustomDiagID(
554         getErrorLevel(), kClassRequiresFinalization);
555     diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID(
556         getErrorLevel(), kFinalizerAccessesFinalizedField);
557     diag_overridden_non_virtual_trace_ = diagnostic_.getCustomDiagID(
558         getErrorLevel(), kOverriddenNonVirtualTrace);
559     diag_missing_trace_dispatch_method_ = diagnostic_.getCustomDiagID(
560         getErrorLevel(), kMissingTraceDispatchMethod);
561     diag_missing_finalize_dispatch_method_ = diagnostic_.getCustomDiagID(
562         getErrorLevel(), kMissingFinalizeDispatchMethod);
563     diag_virtual_and_manual_dispatch_ =
564         diagnostic_.getCustomDiagID(getErrorLevel(), kVirtualAndManualDispatch);
565     diag_missing_trace_dispatch_ =
566         diagnostic_.getCustomDiagID(getErrorLevel(), kMissingTraceDispatch);
567     diag_missing_finalize_dispatch_ =
568         diagnostic_.getCustomDiagID(getErrorLevel(), kMissingFinalizeDispatch);
569     diag_derives_non_stack_allocated_ =
570         diagnostic_.getCustomDiagID(getErrorLevel(), kDerivesNonStackAllocated);
571     diag_class_overrides_new_ =
572         diagnostic_.getCustomDiagID(getErrorLevel(), kClassOverridesNew);
573
574     // Register note messages.
575     diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID(
576         DiagnosticsEngine::Note, kFieldRequiresTracingNote);
577     diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
578         DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote);
579     diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
580         DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote);
581     diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
582         DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote);
583     diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID(
584         DiagnosticsEngine::Note, kStackAllocatedFieldNote);
585     diag_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
586         DiagnosticsEngine::Note, kMemberInUnmanagedClassNote);
587     diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
588         DiagnosticsEngine::Note, kPartObjectContainsGCRoot);
589     diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
590         DiagnosticsEngine::Note, kFieldContainsGCRoot);
591     diag_finalized_field_note_ = diagnostic_.getCustomDiagID(
592         DiagnosticsEngine::Note, kFinalizedFieldNote);
593     diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID(
594         DiagnosticsEngine::Note, kUserDeclaredDestructorNote);
595     diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID(
596         DiagnosticsEngine::Note, kUserDeclaredFinalizerNote);
597     diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID(
598         DiagnosticsEngine::Note, kBaseRequiresFinalizationNote);
599     diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID(
600         DiagnosticsEngine::Note, kFieldRequiresFinalizationNote);
601     diag_overridden_non_virtual_trace_note_ = diagnostic_.getCustomDiagID(
602         DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote);
603     diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID(
604         DiagnosticsEngine::Note, kManualDispatchMethodNote);
605   }
606
607   void HandleTranslationUnit(ASTContext& context) override {
608     CollectVisitor visitor;
609     visitor.TraverseDecl(context.getTranslationUnitDecl());
610
611     if (options_.dump_graph) {
612       string err;
613       // TODO: Make createDefaultOutputFile or a shorter createOutputFile work.
614       json_ = JsonWriter::from(instance_.createOutputFile(
615           "",                                      // OutputPath
616           err,                                     // Errors
617           true,                                    // Binary
618           true,                                    // RemoveFileOnSignal
619           instance_.getFrontendOpts().OutputFile,  // BaseInput
620           "graph.json",                            // Extension
621           false,                                   // UseTemporary
622           false,                                   // CreateMissingDirectories
623           0,                                       // ResultPathName
624           0));                                     // TempPathName
625       if (err.empty() && json_) {
626         json_->OpenList();
627       } else {
628         json_ = 0;
629         llvm::errs()
630             << "[blink-gc] "
631             << "Failed to create an output file for the object graph.\n";
632       }
633     }
634
635     for (RecordVector::iterator it = visitor.record_decls().begin();
636          it != visitor.record_decls().end();
637          ++it) {
638       CheckRecord(cache_.Lookup(*it));
639     }
640
641     for (MethodVector::iterator it = visitor.trace_decls().begin();
642          it != visitor.trace_decls().end();
643          ++it) {
644       CheckTracingMethod(*it);
645     }
646
647     if (json_) {
648       json_->CloseList();
649       delete json_;
650       json_ = 0;
651     }
652   }
653
654   // Main entry for checking a record declaration.
655   void CheckRecord(RecordInfo* info) {
656     if (IsIgnored(info))
657       return;
658
659     CXXRecordDecl* record = info->record();
660
661     // TODO: what should we do to check unions?
662     if (record->isUnion())
663       return;
664
665     // If this is the primary template declaration, check its specializations.
666     if (record->isThisDeclarationADefinition() &&
667         record->getDescribedClassTemplate()) {
668       ClassTemplateDecl* tmpl = record->getDescribedClassTemplate();
669       for (ClassTemplateDecl::spec_iterator it = tmpl->spec_begin();
670            it != tmpl->spec_end();
671            ++it) {
672         CheckClass(cache_.Lookup(*it));
673       }
674       return;
675     }
676
677     CheckClass(info);
678   }
679
680   // Check a class-like object (eg, class, specialization, instantiation).
681   void CheckClass(RecordInfo* info) {
682     if (!info)
683       return;
684
685     // Check consistency of stack-allocated hierarchies.
686     if (info->IsStackAllocated()) {
687       for (RecordInfo::Bases::iterator it = info->GetBases().begin();
688            it != info->GetBases().end();
689            ++it) {
690         if (!it->second.info()->IsStackAllocated())
691           ReportDerivesNonStackAllocated(info, &it->second);
692       }
693     }
694
695     if (info->RequiresTraceMethod() && !info->GetTraceMethod())
696       ReportClassRequiresTraceMethod(info);
697
698     {
699       CheckFieldsVisitor visitor(options_);
700       if (visitor.ContainsInvalidFields(info))
701         ReportClassContainsInvalidFields(info, &visitor.invalid_fields());
702     }
703
704     if (info->IsGCDerived()) {
705       CheckLeftMostDerived(info);
706
707       CheckDispatch(info);
708
709       if (CXXMethodDecl* newop = info->DeclaresNewOperator())
710         ReportClassOverridesNew(info, newop);
711
712       // TODO: Remove this exception once TreeShared is properly traced.
713       if (!info->IsTreeShared()) {
714         CheckGCRootsVisitor visitor;
715         if (visitor.ContainsGCRoots(info))
716           ReportClassContainsGCRoots(info, &visitor.gc_roots());
717       }
718
719       if (info->NeedsFinalization())
720         CheckFinalization(info);
721     }
722
723     DumpClass(info);
724   }
725
726   void CheckLeftMostDerived(RecordInfo* info) {
727     CXXRecordDecl* left_most = info->record();
728     CXXRecordDecl::base_class_iterator it = left_most->bases_begin();
729     while (it != left_most->bases_end()) {
730       left_most = it->getType()->getAsCXXRecordDecl();
731       it = left_most->bases_begin();
732     }
733     if (!Config::IsGCBase(left_most->getName()))
734       ReportClassMustLeftMostlyDeriveGC(info);
735   }
736
737   void CheckDispatch(RecordInfo* info) {
738     bool finalized = info->IsGCFinalized();
739     CXXMethodDecl* trace_dispatch = info->GetTraceDispatchMethod();
740     CXXMethodDecl* finalize_dispatch = info->GetFinalizeDispatchMethod();
741     if (!trace_dispatch && !finalize_dispatch)
742       return;
743
744     CXXRecordDecl* base = trace_dispatch ? trace_dispatch->getParent()
745                                          : finalize_dispatch->getParent();
746
747     // Check that dispatch methods are defined at the base.
748     if (base == info->record()) {
749       if (!trace_dispatch)
750         ReportMissingTraceDispatchMethod(info);
751       if (finalized && !finalize_dispatch)
752         ReportMissingFinalizeDispatchMethod(info);
753       if (!finalized && finalize_dispatch) {
754         ReportClassRequiresFinalization(info);
755         NoteUserDeclaredFinalizer(finalize_dispatch);
756       }
757     }
758
759     // Check that classes implementing manual dispatch do not have vtables.
760     if (info->record()->isPolymorphic())
761       ReportVirtualAndManualDispatch(
762           info, trace_dispatch ? trace_dispatch : finalize_dispatch);
763
764     // If this is a non-abstract class check that it is dispatched to.
765     // TODO: Create a global variant of this local check. We can only check if
766     // the dispatch body is known in this compilation unit.
767     if (info->IsConsideredAbstract())
768       return;
769
770     const FunctionDecl* defn;
771
772     if (trace_dispatch && trace_dispatch->isDefined(defn)) {
773       CheckDispatchVisitor visitor(info);
774       visitor.TraverseStmt(defn->getBody());
775       if (!visitor.dispatched_to_receiver())
776         ReportMissingTraceDispatch(defn, info);
777     }
778
779     if (finalized && finalize_dispatch && finalize_dispatch->isDefined(defn)) {
780       CheckDispatchVisitor visitor(info);
781       visitor.TraverseStmt(defn->getBody());
782       if (!visitor.dispatched_to_receiver())
783         ReportMissingFinalizeDispatch(defn, info);
784     }
785   }
786
787   // TODO: Should we collect destructors similar to trace methods?
788   void CheckFinalization(RecordInfo* info) {
789     CXXDestructorDecl* dtor = info->record()->getDestructor();
790
791     // For finalized classes, check the finalization method if possible.
792     if (info->IsGCFinalized()) {
793       if (dtor && dtor->hasBody()) {
794         CheckFinalizerVisitor visitor(&cache_);
795         visitor.TraverseCXXMethodDecl(dtor);
796         if (!visitor.finalized_fields().empty()) {
797           ReportFinalizerAccessesFinalizedFields(
798               dtor, &visitor.finalized_fields());
799         }
800       }
801       return;
802     }
803
804     // Don't require finalization of a mixin that has not yet been "mixed in".
805     if (info->IsGCMixin())
806       return;
807
808     // Report the finalization error, and proceed to print possible causes for
809     // the finalization requirement.
810     ReportClassRequiresFinalization(info);
811
812     if (dtor && dtor->isUserProvided())
813       NoteUserDeclaredDestructor(dtor);
814
815     for (RecordInfo::Bases::iterator it = info->GetBases().begin();
816          it != info->GetBases().end();
817          ++it) {
818       if (it->second.info()->NeedsFinalization())
819         NoteBaseRequiresFinalization(&it->second);
820     }
821
822     for (RecordInfo::Fields::iterator it = info->GetFields().begin();
823          it != info->GetFields().end();
824          ++it) {
825       if (it->second.edge()->NeedsFinalization())
826         NoteField(&it->second, diag_field_requires_finalization_note_);
827     }
828   }
829
830   // This is the main entry for tracing method definitions.
831   void CheckTracingMethod(CXXMethodDecl* method) {
832     RecordInfo* parent = cache_.Lookup(method->getParent());
833     if (IsIgnored(parent))
834       return;
835
836     // Check templated tracing methods by checking the template instantiations.
837     // Specialized templates are handled as ordinary classes.
838     if (ClassTemplateDecl* tmpl =
839             parent->record()->getDescribedClassTemplate()) {
840       for (ClassTemplateDecl::spec_iterator it = tmpl->spec_begin();
841            it != tmpl->spec_end();
842            ++it) {
843         // Check trace using each template instantiation as the holder.
844         if (IsTemplateInstantiation(*it))
845           CheckTraceOrDispatchMethod(cache_.Lookup(*it), method);
846       }
847       return;
848     }
849
850     CheckTraceOrDispatchMethod(parent, method);
851   }
852
853   // Determine what type of tracing method this is (dispatch or trace).
854   void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) {
855     bool isTraceAfterDispatch;
856     if (Config::IsTraceMethod(method, &isTraceAfterDispatch)) {
857       if (isTraceAfterDispatch || !parent->GetTraceDispatchMethod()) {
858         CheckTraceMethod(parent, method, isTraceAfterDispatch);
859       }
860       // Dispatch methods are checked when we identify subclasses.
861     }
862   }
863
864   // Check an actual trace method.
865   void CheckTraceMethod(RecordInfo* parent,
866                         CXXMethodDecl* trace,
867                         bool isTraceAfterDispatch) {
868     // A non-virtual trace method must not override another trace.
869     if (!isTraceAfterDispatch && !trace->isVirtual()) {
870       for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
871            it != parent->GetBases().end();
872            ++it) {
873         RecordInfo* base = it->second.info();
874         // We allow mixin bases to contain a non-virtual trace since it will
875         // never be used for dispatching.
876         if (base->IsGCMixin())
877           continue;
878         if (CXXMethodDecl* other = base->InheritsNonVirtualTrace())
879           ReportOverriddenNonVirtualTrace(parent, trace, other);
880       }
881     }
882
883     CheckTraceVisitor visitor(trace, parent);
884     visitor.TraverseCXXMethodDecl(trace);
885
886     for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
887          it != parent->GetBases().end();
888          ++it) {
889       if (!it->second.IsProperlyTraced())
890         ReportBaseRequiresTracing(parent, trace, it->first);
891     }
892
893     for (RecordInfo::Fields::iterator it = parent->GetFields().begin();
894          it != parent->GetFields().end();
895          ++it) {
896       if (!it->second.IsProperlyTraced()) {
897         // Discontinue once an untraced-field error is found.
898         ReportFieldsRequireTracing(parent, trace);
899         break;
900       }
901     }
902   }
903
904   void DumpClass(RecordInfo* info) {
905     if (!json_)
906       return;
907
908     json_->OpenObject();
909     json_->Write("name", info->record()->getQualifiedNameAsString());
910     json_->Write("loc", GetLocString(info->record()->getLocStart()));
911     json_->CloseObject();
912
913     class DumpEdgeVisitor : public RecursiveEdgeVisitor {
914      public:
915       DumpEdgeVisitor(JsonWriter* json) : json_(json) {}
916       void DumpEdge(RecordInfo* src,
917                     RecordInfo* dst,
918                     const string& lbl,
919                     const Edge::LivenessKind& kind,
920                     const string& loc) {
921         json_->OpenObject();
922         json_->Write("src", src->record()->getQualifiedNameAsString());
923         json_->Write("dst", dst->record()->getQualifiedNameAsString());
924         json_->Write("lbl", lbl);
925         json_->Write("kind", kind);
926         json_->Write("loc", loc);
927         json_->Write("ptr",
928                      !Parent() ? "val" :
929                      Parent()->IsRawPtr() ? "raw" :
930                      Parent()->IsRefPtr() ? "ref" :
931                      Parent()->IsOwnPtr() ? "own" :
932                      (Parent()->IsMember() ||
933                       Parent()->IsWeakMember()) ? "mem" :
934                      "val");
935         json_->CloseObject();
936       }
937
938       void DumpField(RecordInfo* src, FieldPoint* point, const string& loc) {
939         src_ = src;
940         point_ = point;
941         loc_ = loc;
942         point_->edge()->Accept(this);
943       }
944
945       void AtValue(Value* e) override {
946         // The liveness kind of a path from the point to this value
947         // is given by the innermost place that is non-strong.
948         Edge::LivenessKind kind = Edge::kStrong;
949         if (Config::IsIgnoreCycleAnnotated(point_->field())) {
950           kind = Edge::kWeak;
951         } else {
952           for (Context::iterator it = context().begin();
953                it != context().end();
954                ++it) {
955             Edge::LivenessKind pointer_kind = (*it)->Kind();
956             if (pointer_kind != Edge::kStrong) {
957               kind = pointer_kind;
958               break;
959             }
960           }
961         }
962         DumpEdge(
963             src_, e->value(), point_->field()->getNameAsString(), kind, loc_);
964       }
965
966      private:
967       JsonWriter* json_;
968       RecordInfo* src_;
969       FieldPoint* point_;
970       string loc_;
971     };
972
973     DumpEdgeVisitor visitor(json_);
974
975     RecordInfo::Bases& bases = info->GetBases();
976     for (RecordInfo::Bases::iterator it = bases.begin();
977          it != bases.end();
978          ++it) {
979       visitor.DumpEdge(info,
980                        it->second.info(),
981                        "<super>",
982                        Edge::kStrong,
983                        GetLocString(it->second.spec().getLocStart()));
984     }
985
986     RecordInfo::Fields& fields = info->GetFields();
987     for (RecordInfo::Fields::iterator it = fields.begin();
988          it != fields.end();
989          ++it) {
990       visitor.DumpField(info,
991                         &it->second,
992                         GetLocString(it->second.field()->getLocStart()));
993     }
994   }
995
996   // Adds either a warning or error, based on the current handling of -Werror.
997   DiagnosticsEngine::Level getErrorLevel() {
998     return diagnostic_.getWarningsAsErrors() ? DiagnosticsEngine::Error
999                                              : DiagnosticsEngine::Warning;
1000   }
1001
1002   const string GetLocString(SourceLocation loc) {
1003     const SourceManager& source_manager = instance_.getSourceManager();
1004     PresumedLoc ploc = source_manager.getPresumedLoc(loc);
1005     if (ploc.isInvalid())
1006       return "";
1007     string loc_str;
1008     llvm::raw_string_ostream OS(loc_str);
1009     OS << ploc.getFilename()
1010        << ":" << ploc.getLine()
1011        << ":" << ploc.getColumn();
1012     return OS.str();
1013   }
1014
1015   bool IsIgnored(RecordInfo* record) {
1016     return !record ||
1017            !InCheckedNamespace(record) ||
1018            IsIgnoredClass(record) ||
1019            InIgnoredDirectory(record);
1020   }
1021
1022   bool IsIgnoredClass(RecordInfo* info) {
1023     // Ignore any class prefixed by SameSizeAs. These are used in
1024     // Blink to verify class sizes and don't need checking.
1025     const string SameSizeAs = "SameSizeAs";
1026     if (info->name().compare(0, SameSizeAs.size(), SameSizeAs) == 0)
1027       return true;
1028     return options_.ignored_classes.find(info->name()) !=
1029            options_.ignored_classes.end();
1030   }
1031
1032   bool InIgnoredDirectory(RecordInfo* info) {
1033     string filename;
1034     if (!GetFilename(info->record()->getLocStart(), &filename))
1035       return false;  // TODO: should we ignore non-existing file locations?
1036     std::vector<string>::iterator it = options_.ignored_directories.begin();
1037     for (; it != options_.ignored_directories.end(); ++it)
1038       if (filename.find(*it) != string::npos)
1039         return true;
1040     return false;
1041   }
1042
1043   bool InCheckedNamespace(RecordInfo* info) {
1044     if (!info)
1045       return false;
1046     DeclContext* context = info->record()->getDeclContext();
1047     if (context->isRecord())
1048       return InCheckedNamespace(cache_.Lookup(context));
1049     if (context->isNamespace()) {
1050       const NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context);
1051       if (decl->isAnonymousNamespace())
1052         return false;
1053       return options_.checked_namespaces.find(decl->getNameAsString()) !=
1054           options_.checked_namespaces.end();
1055     }
1056     return false;
1057   }
1058
1059   bool GetFilename(SourceLocation loc, string* filename) {
1060     const SourceManager& source_manager = instance_.getSourceManager();
1061     SourceLocation spelling_location = source_manager.getSpellingLoc(loc);
1062     PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location);
1063     if (ploc.isInvalid()) {
1064       // If we're in an invalid location, we're looking at things that aren't
1065       // actually stated in the source.
1066       return false;
1067     }
1068     *filename = ploc.getFilename();
1069     return true;
1070   }
1071
1072   void ReportClassMustLeftMostlyDeriveGC(RecordInfo* info) {
1073     SourceLocation loc = info->record()->getInnerLocStart();
1074     SourceManager& manager = instance_.getSourceManager();
1075     FullSourceLoc full_loc(loc, manager);
1076     diagnostic_.Report(full_loc, diag_class_must_left_mostly_derive_gc_)
1077         << info->record();
1078   }
1079
1080   void ReportClassRequiresTraceMethod(RecordInfo* info) {
1081     SourceLocation loc = info->record()->getInnerLocStart();
1082     SourceManager& manager = instance_.getSourceManager();
1083     FullSourceLoc full_loc(loc, manager);
1084     diagnostic_.Report(full_loc, diag_class_requires_trace_method_)
1085         << info->record();
1086     for (RecordInfo::Fields::iterator it = info->GetFields().begin();
1087          it != info->GetFields().end();
1088          ++it) {
1089       if (!it->second.IsProperlyTraced())
1090         NoteFieldRequiresTracing(info, it->first);
1091     }
1092   }
1093
1094   void ReportBaseRequiresTracing(RecordInfo* derived,
1095                                  CXXMethodDecl* trace,
1096                                  CXXRecordDecl* base) {
1097     SourceLocation loc = trace->getLocStart();
1098     SourceManager& manager = instance_.getSourceManager();
1099     FullSourceLoc full_loc(loc, manager);
1100     diagnostic_.Report(full_loc, diag_base_requires_tracing_)
1101         << base << derived->record();
1102   }
1103
1104   void ReportFieldsRequireTracing(RecordInfo* info, CXXMethodDecl* trace) {
1105     SourceLocation loc = trace->getLocStart();
1106     SourceManager& manager = instance_.getSourceManager();
1107     FullSourceLoc full_loc(loc, manager);
1108     diagnostic_.Report(full_loc, diag_fields_require_tracing_)
1109         << info->record();
1110     for (RecordInfo::Fields::iterator it = info->GetFields().begin();
1111          it != info->GetFields().end();
1112          ++it) {
1113       if (!it->second.IsProperlyTraced())
1114         NoteFieldRequiresTracing(info, it->first);
1115     }
1116   }
1117
1118   void ReportClassContainsInvalidFields(RecordInfo* info,
1119                                         CheckFieldsVisitor::Errors* errors) {
1120     SourceLocation loc = info->record()->getLocStart();
1121     SourceManager& manager = instance_.getSourceManager();
1122     FullSourceLoc full_loc(loc, manager);
1123     diagnostic_.Report(full_loc, diag_class_contains_invalid_fields_)
1124         << info->record();
1125     for (CheckFieldsVisitor::Errors::iterator it = errors->begin();
1126          it != errors->end();
1127          ++it) {
1128       if (it->second->IsRawPtr()) {
1129         NoteField(it->first, diag_raw_ptr_to_gc_managed_class_note_);
1130       } else if (it->second->IsRefPtr()) {
1131         NoteField(it->first, diag_ref_ptr_to_gc_managed_class_note_);
1132       } else if (it->second->IsOwnPtr()) {
1133         NoteField(it->first, diag_own_ptr_to_gc_managed_class_note_);
1134       } else if (it->second->IsMember()) {
1135         NoteField(it->first, diag_member_in_unmanaged_class_note_);
1136       } else if (it->second->IsValue()) {
1137         NoteField(it->first, diag_stack_allocated_field_note_);
1138       }
1139     }
1140   }
1141
1142   void ReportClassContainsGCRoots(RecordInfo* info,
1143                                   CheckGCRootsVisitor::Errors* errors) {
1144     SourceLocation loc = info->record()->getLocStart();
1145     SourceManager& manager = instance_.getSourceManager();
1146     FullSourceLoc full_loc(loc, manager);
1147     for (CheckGCRootsVisitor::Errors::iterator it = errors->begin();
1148          it != errors->end();
1149          ++it) {
1150       CheckGCRootsVisitor::RootPath::iterator path = it->begin();
1151       FieldPoint* point = *path;
1152       diagnostic_.Report(full_loc, diag_class_contains_gc_root_)
1153           << info->record() << point->field();
1154       while (++path != it->end()) {
1155         NotePartObjectContainsGCRoot(point);
1156         point = *path;
1157       }
1158       NoteFieldContainsGCRoot(point);
1159     }
1160   }
1161
1162   void ReportFinalizerAccessesFinalizedFields(
1163       CXXMethodDecl* dtor,
1164       CheckFinalizerVisitor::Errors* fields) {
1165     for (CheckFinalizerVisitor::Errors::iterator it = fields->begin();
1166          it != fields->end();
1167          ++it) {
1168       SourceLocation loc = it->first->getLocStart();
1169       SourceManager& manager = instance_.getSourceManager();
1170       FullSourceLoc full_loc(loc, manager);
1171       diagnostic_.Report(full_loc, diag_finalizer_accesses_finalized_field_)
1172           << dtor << it->second->field();
1173       NoteField(it->second, diag_finalized_field_note_);
1174     }
1175   }
1176
1177   void ReportClassRequiresFinalization(RecordInfo* info) {
1178     SourceLocation loc = info->record()->getInnerLocStart();
1179     SourceManager& manager = instance_.getSourceManager();
1180     FullSourceLoc full_loc(loc, manager);
1181     diagnostic_.Report(full_loc, diag_class_requires_finalization_)
1182         << info->record();
1183   }
1184
1185   void ReportOverriddenNonVirtualTrace(RecordInfo* info,
1186                                        CXXMethodDecl* trace,
1187                                        CXXMethodDecl* overridden) {
1188     SourceLocation loc = trace->getLocStart();
1189     SourceManager& manager = instance_.getSourceManager();
1190     FullSourceLoc full_loc(loc, manager);
1191     diagnostic_.Report(full_loc, diag_overridden_non_virtual_trace_)
1192         << info->record() << overridden->getParent();
1193     NoteOverriddenNonVirtualTrace(overridden);
1194   }
1195
1196   void ReportMissingTraceDispatchMethod(RecordInfo* info) {
1197     ReportMissingDispatchMethod(info, diag_missing_trace_dispatch_method_);
1198   }
1199
1200   void ReportMissingFinalizeDispatchMethod(RecordInfo* info) {
1201     ReportMissingDispatchMethod(info, diag_missing_finalize_dispatch_method_);
1202   }
1203
1204   void ReportMissingDispatchMethod(RecordInfo* info, unsigned error) {
1205     SourceLocation loc = info->record()->getInnerLocStart();
1206     SourceManager& manager = instance_.getSourceManager();
1207     FullSourceLoc full_loc(loc, manager);
1208     diagnostic_.Report(full_loc, error) << info->record();
1209   }
1210
1211   void ReportVirtualAndManualDispatch(RecordInfo* info,
1212                                       CXXMethodDecl* dispatch) {
1213     SourceLocation loc = info->record()->getInnerLocStart();
1214     SourceManager& manager = instance_.getSourceManager();
1215     FullSourceLoc full_loc(loc, manager);
1216     diagnostic_.Report(full_loc, diag_virtual_and_manual_dispatch_)
1217         << info->record();
1218     NoteManualDispatchMethod(dispatch);
1219   }
1220
1221   void ReportMissingTraceDispatch(const FunctionDecl* dispatch,
1222                                   RecordInfo* receiver) {
1223     ReportMissingDispatch(dispatch, receiver, diag_missing_trace_dispatch_);
1224   }
1225
1226   void ReportMissingFinalizeDispatch(const FunctionDecl* dispatch,
1227                                      RecordInfo* receiver) {
1228     ReportMissingDispatch(dispatch, receiver, diag_missing_finalize_dispatch_);
1229   }
1230
1231   void ReportMissingDispatch(const FunctionDecl* dispatch,
1232                              RecordInfo* receiver,
1233                              unsigned error) {
1234     SourceLocation loc = dispatch->getLocStart();
1235     SourceManager& manager = instance_.getSourceManager();
1236     FullSourceLoc full_loc(loc, manager);
1237     diagnostic_.Report(full_loc, error) << receiver->record();
1238   }
1239
1240   void ReportDerivesNonStackAllocated(RecordInfo* info, BasePoint* base) {
1241     SourceLocation loc = base->spec().getLocStart();
1242     SourceManager& manager = instance_.getSourceManager();
1243     FullSourceLoc full_loc(loc, manager);
1244     diagnostic_.Report(full_loc, diag_derives_non_stack_allocated_)
1245         << info->record() << base->info()->record();
1246   }
1247
1248   void ReportClassOverridesNew(RecordInfo* info, CXXMethodDecl* newop) {
1249     SourceLocation loc = newop->getLocStart();
1250     SourceManager& manager = instance_.getSourceManager();
1251     FullSourceLoc full_loc(loc, manager);
1252     diagnostic_.Report(full_loc, diag_class_overrides_new_) << info->record();
1253   }
1254
1255   void NoteManualDispatchMethod(CXXMethodDecl* dispatch) {
1256     SourceLocation loc = dispatch->getLocStart();
1257     SourceManager& manager = instance_.getSourceManager();
1258     FullSourceLoc full_loc(loc, manager);
1259     diagnostic_.Report(full_loc, diag_manual_dispatch_method_note_) << dispatch;
1260   }
1261
1262   void NoteFieldRequiresTracing(RecordInfo* holder, FieldDecl* field) {
1263     NoteField(field, diag_field_requires_tracing_note_);
1264   }
1265
1266   void NotePartObjectContainsGCRoot(FieldPoint* point) {
1267     FieldDecl* field = point->field();
1268     SourceLocation loc = field->getLocStart();
1269     SourceManager& manager = instance_.getSourceManager();
1270     FullSourceLoc full_loc(loc, manager);
1271     diagnostic_.Report(full_loc, diag_part_object_contains_gc_root_note_)
1272         << field << field->getParent();
1273   }
1274
1275   void NoteFieldContainsGCRoot(FieldPoint* point) {
1276     NoteField(point, diag_field_contains_gc_root_note_);
1277   }
1278
1279   void NoteUserDeclaredDestructor(CXXMethodDecl* dtor) {
1280     SourceLocation loc = dtor->getLocStart();
1281     SourceManager& manager = instance_.getSourceManager();
1282     FullSourceLoc full_loc(loc, manager);
1283     diagnostic_.Report(full_loc, diag_user_declared_destructor_note_);
1284   }
1285
1286   void NoteUserDeclaredFinalizer(CXXMethodDecl* dtor) {
1287     SourceLocation loc = dtor->getLocStart();
1288     SourceManager& manager = instance_.getSourceManager();
1289     FullSourceLoc full_loc(loc, manager);
1290     diagnostic_.Report(full_loc, diag_user_declared_finalizer_note_);
1291   }
1292
1293   void NoteBaseRequiresFinalization(BasePoint* base) {
1294     SourceLocation loc = base->spec().getLocStart();
1295     SourceManager& manager = instance_.getSourceManager();
1296     FullSourceLoc full_loc(loc, manager);
1297     diagnostic_.Report(full_loc, diag_base_requires_finalization_note_)
1298         << base->info()->record();
1299   }
1300
1301   void NoteField(FieldPoint* point, unsigned note) {
1302     NoteField(point->field(), note);
1303   }
1304
1305   void NoteField(FieldDecl* field, unsigned note) {
1306     SourceLocation loc = field->getLocStart();
1307     SourceManager& manager = instance_.getSourceManager();
1308     FullSourceLoc full_loc(loc, manager);
1309     diagnostic_.Report(full_loc, note) << field;
1310   }
1311
1312   void NoteOverriddenNonVirtualTrace(CXXMethodDecl* overridden) {
1313     SourceLocation loc = overridden->getLocStart();
1314     SourceManager& manager = instance_.getSourceManager();
1315     FullSourceLoc full_loc(loc, manager);
1316     diagnostic_.Report(full_loc, diag_overridden_non_virtual_trace_note_)
1317         << overridden;
1318   }
1319
1320   unsigned diag_class_must_left_mostly_derive_gc_;
1321   unsigned diag_class_requires_trace_method_;
1322   unsigned diag_base_requires_tracing_;
1323   unsigned diag_fields_require_tracing_;
1324   unsigned diag_class_contains_invalid_fields_;
1325   unsigned diag_class_contains_gc_root_;
1326   unsigned diag_class_requires_finalization_;
1327   unsigned diag_finalizer_accesses_finalized_field_;
1328   unsigned diag_overridden_non_virtual_trace_;
1329   unsigned diag_missing_trace_dispatch_method_;
1330   unsigned diag_missing_finalize_dispatch_method_;
1331   unsigned diag_virtual_and_manual_dispatch_;
1332   unsigned diag_missing_trace_dispatch_;
1333   unsigned diag_missing_finalize_dispatch_;
1334   unsigned diag_derives_non_stack_allocated_;
1335   unsigned diag_class_overrides_new_;
1336
1337   unsigned diag_field_requires_tracing_note_;
1338   unsigned diag_raw_ptr_to_gc_managed_class_note_;
1339   unsigned diag_ref_ptr_to_gc_managed_class_note_;
1340   unsigned diag_own_ptr_to_gc_managed_class_note_;
1341   unsigned diag_stack_allocated_field_note_;
1342   unsigned diag_member_in_unmanaged_class_note_;
1343   unsigned diag_part_object_contains_gc_root_note_;
1344   unsigned diag_field_contains_gc_root_note_;
1345   unsigned diag_finalized_field_note_;
1346   unsigned diag_user_declared_destructor_note_;
1347   unsigned diag_user_declared_finalizer_note_;
1348   unsigned diag_base_requires_finalization_note_;
1349   unsigned diag_field_requires_finalization_note_;
1350   unsigned diag_overridden_non_virtual_trace_note_;
1351   unsigned diag_manual_dispatch_method_note_;
1352
1353   CompilerInstance& instance_;
1354   DiagnosticsEngine& diagnostic_;
1355   BlinkGCPluginOptions options_;
1356   RecordCache cache_;
1357   JsonWriter* json_;
1358 };
1359
1360 class BlinkGCPluginAction : public PluginASTAction {
1361  public:
1362   BlinkGCPluginAction() {}
1363
1364  protected:
1365   // Overridden from PluginASTAction:
1366   virtual ASTConsumer* CreateASTConsumer(CompilerInstance& instance,
1367                                          llvm::StringRef ref) {
1368     return new BlinkGCPluginConsumer(instance, options_);
1369   }
1370
1371   virtual bool ParseArgs(const CompilerInstance& instance,
1372                          const std::vector<string>& args) {
1373     bool parsed = true;
1374
1375     for (size_t i = 0; i < args.size() && parsed; ++i) {
1376       if (args[i] == "enable-oilpan") {
1377         options_.enable_oilpan = true;
1378       } else if (args[i] == "dump-graph") {
1379         options_.dump_graph = true;
1380       } else {
1381         parsed = false;
1382         llvm::errs() << "Unknown blink-gc-plugin argument: " << args[i] << "\n";
1383       }
1384     }
1385
1386     return parsed;
1387   }
1388
1389  private:
1390   BlinkGCPluginOptions options_;
1391 };
1392
1393 }  // namespace
1394
1395 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X(
1396     "blink-gc-plugin",
1397     "Check Blink GC invariants");