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