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.
5 // This clang plugin checks various invariants of the Blink garbage
6 // collection infrastructure.
8 // Errors are described at:
9 // http://www.chromium.org/developers/blink-gc-plugin-errors
12 #include "JsonWriter.h"
13 #include "RecordInfo.h"
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"
21 using namespace clang;
26 const char kClassMustLeftMostlyDeriveGC[] =
27 "[blink-gc] Class %0 must derive its GC base in the left-most position.";
29 const char kClassRequiresTraceMethod[] =
30 "[blink-gc] Class %0 requires a trace method.";
32 const char kBaseRequiresTracing[] =
33 "[blink-gc] Base class %0 of derived class %1 requires tracing.";
35 const char kBaseRequiresTracingNote[] =
36 "[blink-gc] Untraced base class %0 declared here:";
38 const char kFieldsRequireTracing[] =
39 "[blink-gc] Class %0 has untraced fields that require tracing.";
41 const char kFieldRequiresTracingNote[] =
42 "[blink-gc] Untraced field %0 declared here:";
44 const char kClassContainsInvalidFields[] =
45 "[blink-gc] Class %0 contains invalid fields.";
47 const char kClassContainsGCRoot[] =
48 "[blink-gc] Class %0 contains GC root in field %1.";
50 const char kClassRequiresFinalization[] =
51 "[blink-gc] Class %0 requires finalization.";
53 const char kClassDoesNotRequireFinalization[] =
54 "[blink-gc] Class %0 may not require finalization.";
56 const char kFinalizerAccessesFinalizedField[] =
57 "[blink-gc] Finalizer %0 accesses potentially finalized field %1.";
59 const char kRawPtrToGCManagedClassNote[] =
60 "[blink-gc] Raw pointer field %0 to a GC managed class declared here:";
62 const char kRefPtrToGCManagedClassNote[] =
63 "[blink-gc] RefPtr field %0 to a GC managed class declared here:";
65 const char kOwnPtrToGCManagedClassNote[] =
66 "[blink-gc] OwnPtr field %0 to a GC managed class declared here:";
68 const char kStackAllocatedFieldNote[] =
69 "[blink-gc] Stack-allocated field %0 declared here:";
71 const char kMemberInUnmanagedClassNote[] =
72 "[blink-gc] Member field %0 in unmanaged class declared here:";
74 const char kPartObjectToGCDerivedClassNote[] =
75 "[blink-gc] Part-object field %0 to a GC derived class declared here:";
77 const char kPartObjectContainsGCRootNote[] =
78 "[blink-gc] Field %0 with embedded GC root in %1 declared here:";
80 const char kFieldContainsGCRootNote[] =
81 "[blink-gc] Field %0 defining a GC root declared here:";
83 const char kOverriddenNonVirtualTrace[] =
84 "[blink-gc] Class %0 overrides non-virtual trace of base class %1.";
86 const char kOverriddenNonVirtualTraceNote[] =
87 "[blink-gc] Non-virtual trace method declared here:";
89 const char kMissingTraceDispatchMethod[] =
90 "[blink-gc] Class %0 is missing manual trace dispatch.";
92 const char kMissingFinalizeDispatchMethod[] =
93 "[blink-gc] Class %0 is missing manual finalize dispatch.";
95 const char kVirtualAndManualDispatch[] =
96 "[blink-gc] Class %0 contains or inherits virtual methods"
97 " but implements manual dispatching.";
99 const char kMissingTraceDispatch[] =
100 "[blink-gc] Missing dispatch to class %0 in manual trace dispatch.";
102 const char kMissingFinalizeDispatch[] =
103 "[blink-gc] Missing dispatch to class %0 in manual finalize dispatch.";
105 const char kFinalizedFieldNote[] =
106 "[blink-gc] Potentially finalized field %0 declared here:";
108 const char kUserDeclaredDestructorNote[] =
109 "[blink-gc] User-declared destructor declared here:";
111 const char kUserDeclaredFinalizerNote[] =
112 "[blink-gc] User-declared finalizer declared here:";
114 const char kBaseRequiresFinalizationNote[] =
115 "[blink-gc] Base class %0 requiring finalization declared here:";
117 const char kFieldRequiresFinalizationNote[] =
118 "[blink-gc] Field %0 requiring finalization declared here:";
120 const char kManualDispatchMethodNote[] =
121 "[blink-gc] Manual dispatch %0 declared here:";
123 const char kDerivesNonStackAllocated[] =
124 "[blink-gc] Stack-allocated class %0 derives class %1"
125 " which is not stack allocated.";
127 const char kClassOverridesNew[] =
128 "[blink-gc] Garbage collected class %0"
129 " is not permitted to override its new operator.";
131 const char kClassDeclaresPureVirtualTrace[] =
132 "[blink-gc] Garbage collected class %0"
133 " is not permitted to declare a pure-virtual trace method.";
135 const char kLeftMostBaseMustBePolymorphic[] =
136 "[blink-gc] Left-most base class %0 of derived class %1"
137 " must be polymorphic.";
139 const char kBaseClassMustDeclareVirtualTrace[] =
140 "[blink-gc] Left-most base class %0 of derived class %1"
141 " must define a virtual trace method.";
143 struct BlinkGCPluginOptions {
144 BlinkGCPluginOptions()
145 : enable_oilpan(false)
147 , warn_raw_ptr(false)
148 , warn_unneeded_finalizer(false) {}
152 bool warn_unneeded_finalizer;
153 std::set<std::string> ignored_classes;
154 std::set<std::string> checked_namespaces;
155 std::vector<std::string> ignored_directories;
158 typedef std::vector<CXXRecordDecl*> RecordVector;
159 typedef std::vector<CXXMethodDecl*> MethodVector;
161 // Test if a template specialization is an instantiation.
162 static bool IsTemplateInstantiation(CXXRecordDecl* record) {
163 ClassTemplateSpecializationDecl* spec =
164 dyn_cast<ClassTemplateSpecializationDecl>(record);
167 switch (spec->getTemplateSpecializationKind()) {
168 case TSK_ImplicitInstantiation:
169 case TSK_ExplicitInstantiationDefinition:
172 case TSK_ExplicitSpecialization:
174 // TODO: unsupported cases.
175 case TSK_ExplicitInstantiationDeclaration:
178 assert(false && "Unknown template specialization kind");
181 // This visitor collects the entry points for the checker.
182 class CollectVisitor : public RecursiveASTVisitor<CollectVisitor> {
186 RecordVector& record_decls() { return record_decls_; }
187 MethodVector& trace_decls() { return trace_decls_; }
189 bool shouldVisitTemplateInstantiations() { return false; }
191 // Collect record declarations, including nested declarations.
192 bool VisitCXXRecordDecl(CXXRecordDecl* record) {
193 if (record->hasDefinition() && record->isCompleteDefinition())
194 record_decls_.push_back(record);
198 // Collect tracing method definitions, but don't traverse method bodies.
199 bool TraverseCXXMethodDecl(CXXMethodDecl* method) {
200 if (method->isThisDeclarationADefinition() && Config::IsTraceMethod(method))
201 trace_decls_.push_back(method);
206 RecordVector record_decls_;
207 MethodVector trace_decls_;
210 // This visitor checks that a finalizer method does not have invalid access to
211 // fields that are potentially finalized. A potentially finalized field is
212 // either a Member, a heap-allocated collection or an off-heap collection that
213 // contains Members. Invalid uses are currently identified as passing the field
214 // as the argument of a procedure call or using the -> or [] operators on it.
215 class CheckFinalizerVisitor
216 : public RecursiveASTVisitor<CheckFinalizerVisitor> {
218 // Simple visitor to determine if the content of a field might be collected
219 // during finalization.
220 class MightBeCollectedVisitor : public EdgeVisitor {
222 MightBeCollectedVisitor() : might_be_collected_(false) {}
223 bool might_be_collected() { return might_be_collected_; }
224 void VisitMember(Member* edge) override { might_be_collected_ = true; }
225 void VisitCollection(Collection* edge) override {
226 if (edge->on_heap()) {
227 might_be_collected_ = !edge->is_root();
229 edge->AcceptMembers(this);
234 bool might_be_collected_;
238 typedef std::vector<std::pair<MemberExpr*, FieldPoint*> > Errors;
240 CheckFinalizerVisitor(RecordCache* cache)
241 : blacklist_context_(false), cache_(cache) {}
243 Errors& finalized_fields() { return finalized_fields_; }
245 bool WalkUpFromCXXOperatorCallExpr(CXXOperatorCallExpr* expr) {
246 // Only continue the walk-up if the operator is a blacklisted one.
247 switch (expr->getOperator()) {
250 this->WalkUpFromCallExpr(expr);
256 // We consider all non-operator calls to be blacklisted contexts.
257 bool WalkUpFromCallExpr(CallExpr* expr) {
258 bool prev_blacklist_context = blacklist_context_;
259 blacklist_context_ = true;
260 for (size_t i = 0; i < expr->getNumArgs(); ++i)
261 this->TraverseStmt(expr->getArg(i));
262 blacklist_context_ = prev_blacklist_context;
266 bool VisitMemberExpr(MemberExpr* member) {
267 FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl());
271 RecordInfo* info = cache_->Lookup(field->getParent());
275 RecordInfo::Fields::iterator it = info->GetFields().find(field);
276 if (it == info->GetFields().end())
279 if (blacklist_context_ && MightBeCollected(&it->second))
280 finalized_fields_.push_back(std::make_pair(member, &it->second));
284 bool MightBeCollected(FieldPoint* point) {
285 MightBeCollectedVisitor visitor;
286 point->edge()->Accept(&visitor);
287 return visitor.might_be_collected();
291 bool blacklist_context_;
292 Errors finalized_fields_;
296 // This visitor checks that a method contains within its body, a call to a
297 // method on the provided receiver class. This is used to check manual
298 // dispatching for trace and finalize methods.
299 class CheckDispatchVisitor : public RecursiveASTVisitor<CheckDispatchVisitor> {
301 CheckDispatchVisitor(RecordInfo* receiver)
302 : receiver_(receiver), dispatched_to_receiver_(false) {}
304 bool dispatched_to_receiver() { return dispatched_to_receiver_; }
306 bool VisitMemberExpr(MemberExpr* member) {
307 if (CXXMethodDecl* fn = dyn_cast<CXXMethodDecl>(member->getMemberDecl())) {
308 if (fn->getParent() == receiver_->record())
309 dispatched_to_receiver_ = true;
315 RecordInfo* receiver_;
316 bool dispatched_to_receiver_;
319 // This visitor checks a tracing method by traversing its body.
320 // - A member field is considered traced if it is referenced in the body.
321 // - A base is traced if a base-qualified call to a trace method is found.
322 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> {
324 CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info)
325 : trace_(trace), info_(info) {}
327 bool VisitMemberExpr(MemberExpr* member) {
328 // In weak callbacks, consider any occurrence as a correct usage.
329 // TODO: We really want to require that isAlive is checked on manually
330 // processed weak fields.
331 if (IsWeakCallback()) {
332 if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl()))
338 bool VisitCallExpr(CallExpr* call) {
339 // In weak callbacks we don't check calls (see VisitMemberExpr).
340 if (IsWeakCallback())
343 Expr* callee = call->getCallee();
345 // Trace calls from a templated derived class result in a
346 // DependentScopeMemberExpr because the concrete trace call depends on the
347 // instantiation of any shared template parameters. In this case the call is
348 // "unresolved" and we resort to comparing the syntactic type names.
349 if (CXXDependentScopeMemberExpr* expr =
350 dyn_cast<CXXDependentScopeMemberExpr>(callee)) {
351 CheckCXXDependentScopeMemberExpr(call, expr);
355 // A tracing call will have either a |visitor| or a |m_field| argument.
356 // A registerWeakMembers call will have a |this| argument.
357 if (call->getNumArgs() != 1)
359 Expr* arg = call->getArg(0);
361 if (UnresolvedMemberExpr* expr = dyn_cast<UnresolvedMemberExpr>(callee)) {
362 // If we find a call to registerWeakMembers which is unresolved we
363 // unsoundly consider all weak members as traced.
364 // TODO: Find out how to validate weak member tracing for unresolved call.
365 if (expr->getMemberName().getAsString() == kRegisterWeakMembersName) {
366 for (RecordInfo::Fields::iterator it = info_->GetFields().begin();
367 it != info_->GetFields().end();
369 if (it->second.edge()->IsWeakMember())
370 it->second.MarkTraced();
374 QualType base = expr->getBaseType();
375 if (!base->isPointerType())
377 CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl();
379 CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg);
383 if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) {
384 if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr))
388 CheckTraceBaseCall(call);
394 CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) {
395 NestedNameSpecifier* qual = expr->getQualifier();
399 const Type* type = qual->getAsType();
403 const TemplateSpecializationType* tmpl_type =
404 type->getAs<TemplateSpecializationType>();
408 TemplateDecl* tmpl_decl = tmpl_type->getTemplateName().getAsTemplateDecl();
412 return dyn_cast<CXXRecordDecl>(tmpl_decl->getTemplatedDecl());
415 void CheckCXXDependentScopeMemberExpr(CallExpr* call,
416 CXXDependentScopeMemberExpr* expr) {
417 string fn_name = expr->getMember().getAsString();
418 CXXRecordDecl* tmpl = GetDependentTemplatedDecl(expr);
422 // Check for Super<T>::trace(visitor)
423 if (call->getNumArgs() == 1 && fn_name == trace_->getName()) {
424 RecordInfo::Bases::iterator it = info_->GetBases().begin();
425 for (; it != info_->GetBases().end(); ++it) {
426 if (it->first->getName() == tmpl->getName())
427 it->second.MarkTraced();
432 // Check for TraceIfNeeded<T>::trace(visitor, &field)
433 if (call->getNumArgs() == 2 && fn_name == kTraceName &&
434 tmpl->getName() == kTraceIfNeededName) {
435 FindFieldVisitor finder;
436 finder.TraverseStmt(call->getArg(1));
438 FoundField(finder.field());
442 bool CheckTraceBaseCall(CallExpr* call) {
443 MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee());
447 FunctionDecl* fn = dyn_cast<FunctionDecl>(callee->getMemberDecl());
448 if (!fn || !Config::IsTraceMethod(fn))
451 // Currently, a manually dispatched class cannot have mixin bases (having
452 // one would add a vtable which we explicitly check against). This means
453 // that we can only make calls to a trace method of the same name. Revisit
454 // this if our mixin/vtable assumption changes.
455 if (fn->getName() != trace_->getName())
458 CXXRecordDecl* decl = 0;
459 if (callee && callee->hasQualifier()) {
460 if (const Type* type = callee->getQualifier()->getAsType())
461 decl = type->getAsCXXRecordDecl();
466 RecordInfo::Bases::iterator it = info_->GetBases().find(decl);
467 if (it != info_->GetBases().end()) {
468 it->second.MarkTraced();
474 bool CheckTraceFieldCall(CXXMemberCallExpr* call) {
475 return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(),
476 call->getRecordDecl(),
480 bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) {
481 if (name != kTraceName || !Config::IsVisitor(callee->getName()))
484 FindFieldVisitor finder;
485 finder.TraverseStmt(arg);
487 FoundField(finder.field());
492 bool CheckRegisterWeakMembers(CXXMemberCallExpr* call) {
493 CXXMethodDecl* fn = call->getMethodDecl();
494 if (fn->getName() != kRegisterWeakMembersName)
497 if (fn->isTemplateInstantiation()) {
498 const TemplateArgumentList& args =
499 *fn->getTemplateSpecializationInfo()->TemplateArguments;
500 // The second template argument is the callback method.
501 if (args.size() > 1 &&
502 args[1].getKind() == TemplateArgument::Declaration) {
503 if (FunctionDecl* callback =
504 dyn_cast<FunctionDecl>(args[1].getAsDecl())) {
505 if (callback->hasBody()) {
506 CheckTraceVisitor nested_visitor(info_);
507 nested_visitor.TraverseStmt(callback->getBody());
515 class FindFieldVisitor : public RecursiveASTVisitor<FindFieldVisitor> {
517 FindFieldVisitor() : member_(0), field_(0) {}
518 MemberExpr* member() const { return member_; }
519 FieldDecl* field() const { return field_; }
520 bool TraverseMemberExpr(MemberExpr* member) {
521 if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) {
533 // Nested checking for weak callbacks.
534 CheckTraceVisitor(RecordInfo* info) : trace_(0), info_(info) {}
536 bool IsWeakCallback() { return !trace_; }
538 void MarkTraced(RecordInfo::Fields::iterator it) {
539 // In a weak callback we can't mark strong fields as traced.
540 if (IsWeakCallback() && !it->second.edge()->IsWeakMember())
542 it->second.MarkTraced();
545 void FoundField(FieldDecl* field) {
546 if (IsTemplateInstantiation(info_->record())) {
547 // Pointer equality on fields does not work for template instantiations.
548 // The trace method refers to fields of the template definition which
549 // are different from the instantiated fields that need to be traced.
550 const string& name = field->getNameAsString();
551 for (RecordInfo::Fields::iterator it = info_->GetFields().begin();
552 it != info_->GetFields().end();
554 if (it->first->getNameAsString() == name) {
560 RecordInfo::Fields::iterator it = info_->GetFields().find(field);
561 if (it != info_->GetFields().end())
566 CXXMethodDecl* trace_;
570 // This visitor checks that the fields of a class and the fields of
571 // its part objects don't define GC roots.
572 class CheckGCRootsVisitor : public RecursiveEdgeVisitor {
574 typedef std::vector<FieldPoint*> RootPath;
575 typedef std::vector<RootPath> Errors;
577 CheckGCRootsVisitor() {}
579 Errors& gc_roots() { return gc_roots_; }
581 bool ContainsGCRoots(RecordInfo* info) {
582 for (RecordInfo::Fields::iterator it = info->GetFields().begin();
583 it != info->GetFields().end();
585 current_.push_back(&it->second);
586 it->second.edge()->Accept(this);
589 return !gc_roots_.empty();
592 void VisitValue(Value* edge) override {
593 // TODO: what should we do to check unions?
594 if (edge->value()->record()->isUnion())
597 // If the value is a part object, then continue checking for roots.
598 for (Context::iterator it = context().begin();
599 it != context().end();
601 if (!(*it)->IsCollection())
604 ContainsGCRoots(edge->value());
607 void VisitPersistent(Persistent* edge) override {
608 gc_roots_.push_back(current_);
611 void AtCollection(Collection* edge) override {
613 gc_roots_.push_back(current_);
621 // This visitor checks that the fields of a class are "well formed".
622 // - OwnPtr, RefPtr and RawPtr must not point to a GC derived types.
623 // - Part objects must not be GC derived types.
624 // - An on-heap class must never contain GC roots.
625 // - Only stack-allocated types may point to stack-allocated types.
626 class CheckFieldsVisitor : public RecursiveEdgeVisitor {
631 kRawPtrToGCManagedWarning,
639 typedef std::vector<std::pair<FieldPoint*, Error> > Errors;
641 CheckFieldsVisitor(const BlinkGCPluginOptions& options)
642 : options_(options), current_(0), stack_allocated_host_(false) {}
644 Errors& invalid_fields() { return invalid_fields_; }
646 bool ContainsInvalidFields(RecordInfo* info) {
647 stack_allocated_host_ = info->IsStackAllocated();
648 managed_host_ = stack_allocated_host_ ||
649 info->IsGCAllocated() ||
650 info->IsNonNewable() ||
651 info->IsOnlyPlacementNewable();
652 for (RecordInfo::Fields::iterator it = info->GetFields().begin();
653 it != info->GetFields().end();
656 current_ = &it->second;
657 current_->edge()->Accept(this);
659 return !invalid_fields_.empty();
662 void AtMember(Member* edge) override {
665 // A member is allowed to appear in the context of a root.
666 for (Context::iterator it = context().begin();
667 it != context().end();
669 if ((*it)->Kind() == Edge::kRoot)
672 invalid_fields_.push_back(std::make_pair(current_, kMemberInUnmanaged));
675 void AtValue(Value* edge) override {
676 // TODO: what should we do to check unions?
677 if (edge->value()->record()->isUnion())
680 if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) {
681 invalid_fields_.push_back(std::make_pair(current_, kPtrFromHeapToStack));
686 edge->value()->IsGCDerived() &&
687 !edge->value()->IsGCMixin()) {
688 invalid_fields_.push_back(std::make_pair(current_, kGCDerivedPartObject));
692 if (!Parent() || !edge->value()->IsGCAllocated())
695 // In transition mode, disallow OwnPtr<T>, RawPtr<T> to GC allocated T's,
696 // also disallow T* in stack-allocated types.
697 if (options_.enable_oilpan) {
698 if (Parent()->IsOwnPtr() ||
699 Parent()->IsRawPtrClass() ||
700 (stack_allocated_host_ && Parent()->IsRawPtr())) {
701 invalid_fields_.push_back(std::make_pair(
702 current_, InvalidSmartPtr(Parent())));
705 if (options_.warn_raw_ptr && Parent()->IsRawPtr()) {
706 invalid_fields_.push_back(std::make_pair(
707 current_, kRawPtrToGCManagedWarning));
712 if (Parent()->IsRawPtr() || Parent()->IsRefPtr() || Parent()->IsOwnPtr()) {
713 invalid_fields_.push_back(std::make_pair(
714 current_, InvalidSmartPtr(Parent())));
719 void AtCollection(Collection* edge) override {
720 if (edge->on_heap() && Parent() && Parent()->IsOwnPtr())
721 invalid_fields_.push_back(std::make_pair(current_, kOwnPtrToGCManaged));
725 Error InvalidSmartPtr(Edge* ptr) {
727 return kRawPtrToGCManaged;
729 return kRefPtrToGCManaged;
731 return kOwnPtrToGCManaged;
732 assert(false && "Unknown smart pointer kind");
735 const BlinkGCPluginOptions& options_;
736 FieldPoint* current_;
737 bool stack_allocated_host_;
739 Errors invalid_fields_;
742 class EmptyStmtVisitor
743 : public RecursiveASTVisitor<EmptyStmtVisitor> {
745 static bool isEmpty(Stmt* stmt) {
746 EmptyStmtVisitor visitor;
747 visitor.TraverseStmt(stmt);
748 return visitor.empty_;
751 bool WalkUpFromCompoundStmt(CompoundStmt* stmt) {
752 empty_ = stmt->body_empty();
755 bool VisitStmt(Stmt*) {
760 EmptyStmtVisitor() : empty_(true) {}
764 // Main class containing checks for various invariants of the Blink
765 // garbage collection infrastructure.
766 class BlinkGCPluginConsumer : public ASTConsumer {
768 BlinkGCPluginConsumer(CompilerInstance& instance,
769 const BlinkGCPluginOptions& options)
770 : instance_(instance),
771 diagnostic_(instance.getDiagnostics()),
775 // Only check structures in the blink and WebKit namespaces.
776 options_.checked_namespaces.insert("blink");
777 options_.checked_namespaces.insert("WebKit");
779 // Ignore GC implementation files.
780 options_.ignored_directories.push_back("/heap/");
782 // Register warning/error messages.
783 diag_class_must_left_mostly_derive_gc_ = diagnostic_.getCustomDiagID(
784 getErrorLevel(), kClassMustLeftMostlyDeriveGC);
785 diag_class_requires_trace_method_ =
786 diagnostic_.getCustomDiagID(getErrorLevel(), kClassRequiresTraceMethod);
787 diag_base_requires_tracing_ =
788 diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresTracing);
789 diag_fields_require_tracing_ =
790 diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing);
791 diag_class_contains_invalid_fields_ = diagnostic_.getCustomDiagID(
792 getErrorLevel(), kClassContainsInvalidFields);
793 diag_class_contains_invalid_fields_warning_ = diagnostic_.getCustomDiagID(
794 DiagnosticsEngine::Warning, kClassContainsInvalidFields);
795 diag_class_contains_gc_root_ =
796 diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRoot);
797 diag_class_requires_finalization_ = diagnostic_.getCustomDiagID(
798 getErrorLevel(), kClassRequiresFinalization);
799 diag_class_does_not_require_finalization_ = diagnostic_.getCustomDiagID(
800 DiagnosticsEngine::Warning, kClassDoesNotRequireFinalization);
801 diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID(
802 getErrorLevel(), kFinalizerAccessesFinalizedField);
803 diag_overridden_non_virtual_trace_ = diagnostic_.getCustomDiagID(
804 getErrorLevel(), kOverriddenNonVirtualTrace);
805 diag_missing_trace_dispatch_method_ = diagnostic_.getCustomDiagID(
806 getErrorLevel(), kMissingTraceDispatchMethod);
807 diag_missing_finalize_dispatch_method_ = diagnostic_.getCustomDiagID(
808 getErrorLevel(), kMissingFinalizeDispatchMethod);
809 diag_virtual_and_manual_dispatch_ =
810 diagnostic_.getCustomDiagID(getErrorLevel(), kVirtualAndManualDispatch);
811 diag_missing_trace_dispatch_ =
812 diagnostic_.getCustomDiagID(getErrorLevel(), kMissingTraceDispatch);
813 diag_missing_finalize_dispatch_ =
814 diagnostic_.getCustomDiagID(getErrorLevel(), kMissingFinalizeDispatch);
815 diag_derives_non_stack_allocated_ =
816 diagnostic_.getCustomDiagID(getErrorLevel(), kDerivesNonStackAllocated);
817 diag_class_overrides_new_ =
818 diagnostic_.getCustomDiagID(getErrorLevel(), kClassOverridesNew);
819 diag_class_declares_pure_virtual_trace_ = diagnostic_.getCustomDiagID(
820 getErrorLevel(), kClassDeclaresPureVirtualTrace);
821 diag_left_most_base_must_be_polymorphic_ = diagnostic_.getCustomDiagID(
822 getErrorLevel(), kLeftMostBaseMustBePolymorphic);
823 diag_base_class_must_declare_virtual_trace_ = diagnostic_.getCustomDiagID(
824 getErrorLevel(), kBaseClassMustDeclareVirtualTrace);
826 // Register note messages.
827 diag_base_requires_tracing_note_ = diagnostic_.getCustomDiagID(
828 DiagnosticsEngine::Note, kBaseRequiresTracingNote);
829 diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID(
830 DiagnosticsEngine::Note, kFieldRequiresTracingNote);
831 diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
832 DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote);
833 diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
834 DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote);
835 diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
836 DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote);
837 diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID(
838 DiagnosticsEngine::Note, kStackAllocatedFieldNote);
839 diag_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
840 DiagnosticsEngine::Note, kMemberInUnmanagedClassNote);
841 diag_part_object_to_gc_derived_class_note_ = diagnostic_.getCustomDiagID(
842 DiagnosticsEngine::Note, kPartObjectToGCDerivedClassNote);
843 diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
844 DiagnosticsEngine::Note, kPartObjectContainsGCRootNote);
845 diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
846 DiagnosticsEngine::Note, kFieldContainsGCRootNote);
847 diag_finalized_field_note_ = diagnostic_.getCustomDiagID(
848 DiagnosticsEngine::Note, kFinalizedFieldNote);
849 diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID(
850 DiagnosticsEngine::Note, kUserDeclaredDestructorNote);
851 diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID(
852 DiagnosticsEngine::Note, kUserDeclaredFinalizerNote);
853 diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID(
854 DiagnosticsEngine::Note, kBaseRequiresFinalizationNote);
855 diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID(
856 DiagnosticsEngine::Note, kFieldRequiresFinalizationNote);
857 diag_overridden_non_virtual_trace_note_ = diagnostic_.getCustomDiagID(
858 DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote);
859 diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID(
860 DiagnosticsEngine::Note, kManualDispatchMethodNote);
863 void HandleTranslationUnit(ASTContext& context) override {
864 CollectVisitor visitor;
865 visitor.TraverseDecl(context.getTranslationUnitDecl());
867 if (options_.dump_graph) {
869 // TODO: Make createDefaultOutputFile or a shorter createOutputFile work.
870 json_ = JsonWriter::from(instance_.createOutputFile(
874 true, // RemoveFileOnSignal
875 instance_.getFrontendOpts().OutputFile, // BaseInput
876 "graph.json", // Extension
877 false, // UseTemporary
878 false, // CreateMissingDirectories
887 << "Failed to create an output file for the object graph.\n";
891 for (RecordVector::iterator it = visitor.record_decls().begin();
892 it != visitor.record_decls().end();
894 CheckRecord(cache_.Lookup(*it));
897 for (MethodVector::iterator it = visitor.trace_decls().begin();
898 it != visitor.trace_decls().end();
900 CheckTracingMethod(*it);
910 // Main entry for checking a record declaration.
911 void CheckRecord(RecordInfo* info) {
915 CXXRecordDecl* record = info->record();
917 // TODO: what should we do to check unions?
918 if (record->isUnion())
921 // If this is the primary template declaration, check its specializations.
922 if (record->isThisDeclarationADefinition() &&
923 record->getDescribedClassTemplate()) {
924 ClassTemplateDecl* tmpl = record->getDescribedClassTemplate();
925 for (ClassTemplateDecl::spec_iterator it = tmpl->spec_begin();
926 it != tmpl->spec_end();
928 CheckClass(cache_.Lookup(*it));
936 // Check a class-like object (eg, class, specialization, instantiation).
937 void CheckClass(RecordInfo* info) {
941 // Check consistency of stack-allocated hierarchies.
942 if (info->IsStackAllocated()) {
943 for (RecordInfo::Bases::iterator it = info->GetBases().begin();
944 it != info->GetBases().end();
946 if (!it->second.info()->IsStackAllocated())
947 ReportDerivesNonStackAllocated(info, &it->second);
951 if (CXXMethodDecl* trace = info->GetTraceMethod()) {
953 ReportClassDeclaresPureVirtualTrace(info, trace);
954 } else if (info->RequiresTraceMethod()) {
955 ReportClassRequiresTraceMethod(info);
958 // Check polymorphic classes that are GC-derived or have a trace method.
959 if (info->record()->hasDefinition() && info->record()->isPolymorphic()) {
960 CXXMethodDecl* trace = info->GetTraceMethod();
961 if (trace || info->IsGCDerived())
962 CheckPolymorphicClass(info, trace);
966 CheckFieldsVisitor visitor(options_);
967 if (visitor.ContainsInvalidFields(info))
968 ReportClassContainsInvalidFields(info, &visitor.invalid_fields());
971 if (info->IsGCDerived()) {
973 if (!info->IsGCMixin()) {
974 CheckLeftMostDerived(info);
976 if (CXXMethodDecl* newop = info->DeclaresNewOperator())
977 ReportClassOverridesNew(info, newop);
981 CheckGCRootsVisitor visitor;
982 if (visitor.ContainsGCRoots(info))
983 ReportClassContainsGCRoots(info, &visitor.gc_roots());
986 if (info->NeedsFinalization())
987 CheckFinalization(info);
989 if (options_.warn_unneeded_finalizer && info->IsGCFinalized())
990 CheckUnneededFinalization(info);
996 CXXRecordDecl* GetDependentTemplatedDecl(const Type& type) {
997 const TemplateSpecializationType* tmpl_type =
998 type.getAs<TemplateSpecializationType>();
1002 TemplateDecl* tmpl_decl = tmpl_type->getTemplateName().getAsTemplateDecl();
1006 return dyn_cast<CXXRecordDecl>(tmpl_decl->getTemplatedDecl());
1009 // The GC infrastructure assumes that if the vtable of a polymorphic
1010 // base-class is not initialized for a given object (ie, it is partially
1011 // initialized) then the object does not need to be traced. Thus, we must
1012 // ensure that any polymorphic class with a trace method does not have any
1013 // tractable fields that are initialized before we are sure that the vtable
1014 // and the trace method are both defined. There are two cases that need to
1015 // hold to satisfy that assumption:
1017 // 1. If trace is virtual, then it must be defined in the left-most base.
1018 // This ensures that if the vtable is initialized then it contains a pointer
1019 // to the trace method.
1021 // 2. If trace is non-virtual, then the trace method is defined and we must
1022 // ensure that the left-most base defines a vtable. This ensures that the
1023 // first thing to be initialized when constructing the object is the vtable
1025 void CheckPolymorphicClass(RecordInfo* info, CXXMethodDecl* trace) {
1026 CXXRecordDecl* left_most = info->record();
1027 CXXRecordDecl::base_class_iterator it = left_most->bases_begin();
1028 CXXRecordDecl* left_most_base = 0;
1029 while (it != left_most->bases_end()) {
1030 left_most_base = it->getType()->getAsCXXRecordDecl();
1031 if (!left_most_base && it->getType()->isDependentType())
1032 left_most_base = GetDependentTemplatedDecl(*it->getType());
1034 // TODO: Find a way to correctly check actual instantiations
1035 // for dependent types. The escape below will be hit, eg, when
1036 // we have a primary template with no definition and
1037 // specializations for each case (such as SupplementBase) in
1038 // which case we don't succeed in checking the required
1040 if (!left_most_base || !left_most_base->hasDefinition())
1043 StringRef name = left_most_base->getName();
1044 // We know GCMixin base defines virtual trace.
1045 if (Config::IsGCMixinBase(name))
1048 // Stop with the left-most prior to a safe polymorphic base (a safe base
1049 // is non-polymorphic and contains no fields).
1050 if (Config::IsSafePolymorphicBase(name))
1053 left_most = left_most_base;
1054 it = left_most->bases_begin();
1057 if (RecordInfo* left_most_info = cache_.Lookup(left_most)) {
1059 // Check condition (1):
1060 if (trace && trace->isVirtual()) {
1061 if (CXXMethodDecl* trace = left_most_info->GetTraceMethod()) {
1062 if (trace->isVirtual())
1065 ReportBaseClassMustDeclareVirtualTrace(info, left_most);
1069 // Check condition (2):
1070 if (DeclaresVirtualMethods(left_most))
1072 if (left_most_base) {
1073 ++it; // Get the base next to the "safe polymorphic base"
1074 if (it != left_most->bases_end()) {
1075 if (CXXRecordDecl* next_base = it->getType()->getAsCXXRecordDecl()) {
1076 if (CXXRecordDecl* next_left_most = GetLeftMostBase(next_base)) {
1077 if (DeclaresVirtualMethods(next_left_most))
1079 ReportLeftMostBaseMustBePolymorphic(info, next_left_most);
1085 ReportLeftMostBaseMustBePolymorphic(info, left_most);
1089 CXXRecordDecl* GetLeftMostBase(CXXRecordDecl* left_most) {
1090 CXXRecordDecl::base_class_iterator it = left_most->bases_begin();
1091 while (it != left_most->bases_end()) {
1092 if (it->getType()->isDependentType())
1093 left_most = GetDependentTemplatedDecl(*it->getType());
1095 left_most = it->getType()->getAsCXXRecordDecl();
1096 if (!left_most || !left_most->hasDefinition())
1098 it = left_most->bases_begin();
1103 bool DeclaresVirtualMethods(CXXRecordDecl* decl) {
1104 CXXRecordDecl::method_iterator it = decl->method_begin();
1105 for (; it != decl->method_end(); ++it)
1106 if (it->isVirtual() && !it->isPure())
1111 void CheckLeftMostDerived(RecordInfo* info) {
1112 CXXRecordDecl* left_most = info->record();
1113 CXXRecordDecl::base_class_iterator it = left_most->bases_begin();
1114 while (it != left_most->bases_end()) {
1115 left_most = it->getType()->getAsCXXRecordDecl();
1116 it = left_most->bases_begin();
1118 if (!Config::IsGCBase(left_most->getName()))
1119 ReportClassMustLeftMostlyDeriveGC(info);
1122 void CheckDispatch(RecordInfo* info) {
1123 bool finalized = info->IsGCFinalized();
1124 CXXMethodDecl* trace_dispatch = info->GetTraceDispatchMethod();
1125 CXXMethodDecl* finalize_dispatch = info->GetFinalizeDispatchMethod();
1126 if (!trace_dispatch && !finalize_dispatch)
1129 CXXRecordDecl* base = trace_dispatch ? trace_dispatch->getParent()
1130 : finalize_dispatch->getParent();
1132 // Check that dispatch methods are defined at the base.
1133 if (base == info->record()) {
1134 if (!trace_dispatch)
1135 ReportMissingTraceDispatchMethod(info);
1136 if (finalized && !finalize_dispatch)
1137 ReportMissingFinalizeDispatchMethod(info);
1138 if (!finalized && finalize_dispatch) {
1139 ReportClassRequiresFinalization(info);
1140 NoteUserDeclaredFinalizer(finalize_dispatch);
1144 // Check that classes implementing manual dispatch do not have vtables.
1145 if (info->record()->isPolymorphic())
1146 ReportVirtualAndManualDispatch(
1147 info, trace_dispatch ? trace_dispatch : finalize_dispatch);
1149 // If this is a non-abstract class check that it is dispatched to.
1150 // TODO: Create a global variant of this local check. We can only check if
1151 // the dispatch body is known in this compilation unit.
1152 if (info->IsConsideredAbstract())
1155 const FunctionDecl* defn;
1157 if (trace_dispatch && trace_dispatch->isDefined(defn)) {
1158 CheckDispatchVisitor visitor(info);
1159 visitor.TraverseStmt(defn->getBody());
1160 if (!visitor.dispatched_to_receiver())
1161 ReportMissingTraceDispatch(defn, info);
1164 if (finalized && finalize_dispatch && finalize_dispatch->isDefined(defn)) {
1165 CheckDispatchVisitor visitor(info);
1166 visitor.TraverseStmt(defn->getBody());
1167 if (!visitor.dispatched_to_receiver())
1168 ReportMissingFinalizeDispatch(defn, info);
1172 // TODO: Should we collect destructors similar to trace methods?
1173 void CheckFinalization(RecordInfo* info) {
1174 CXXDestructorDecl* dtor = info->record()->getDestructor();
1176 // For finalized classes, check the finalization method if possible.
1177 if (info->IsGCFinalized()) {
1178 if (dtor && dtor->hasBody()) {
1179 CheckFinalizerVisitor visitor(&cache_);
1180 visitor.TraverseCXXMethodDecl(dtor);
1181 if (!visitor.finalized_fields().empty()) {
1182 ReportFinalizerAccessesFinalizedFields(
1183 dtor, &visitor.finalized_fields());
1189 // Don't require finalization of a mixin that has not yet been "mixed in".
1190 if (info->IsGCMixin())
1193 // Report the finalization error, and proceed to print possible causes for
1194 // the finalization requirement.
1195 ReportClassRequiresFinalization(info);
1197 if (dtor && dtor->isUserProvided())
1198 NoteUserDeclaredDestructor(dtor);
1200 for (RecordInfo::Bases::iterator it = info->GetBases().begin();
1201 it != info->GetBases().end();
1203 if (it->second.info()->NeedsFinalization())
1204 NoteBaseRequiresFinalization(&it->second);
1207 for (RecordInfo::Fields::iterator it = info->GetFields().begin();
1208 it != info->GetFields().end();
1210 if (it->second.edge()->NeedsFinalization())
1211 NoteField(&it->second, diag_field_requires_finalization_note_);
1215 void CheckUnneededFinalization(RecordInfo* info) {
1216 if (!HasNonEmptyFinalizer(info))
1217 ReportClassDoesNotRequireFinalization(info);
1220 bool HasNonEmptyFinalizer(RecordInfo* info) {
1221 CXXDestructorDecl* dtor = info->record()->getDestructor();
1222 if (dtor && dtor->isUserProvided()) {
1223 if (!dtor->hasBody() || !EmptyStmtVisitor::isEmpty(dtor->getBody()))
1226 for (RecordInfo::Bases::iterator it = info->GetBases().begin();
1227 it != info->GetBases().end();
1229 if (HasNonEmptyFinalizer(it->second.info()))
1232 for (RecordInfo::Fields::iterator it = info->GetFields().begin();
1233 it != info->GetFields().end();
1235 if (it->second.edge()->NeedsFinalization())
1241 // This is the main entry for tracing method definitions.
1242 void CheckTracingMethod(CXXMethodDecl* method) {
1243 RecordInfo* parent = cache_.Lookup(method->getParent());
1244 if (IsIgnored(parent))
1247 // Check templated tracing methods by checking the template instantiations.
1248 // Specialized templates are handled as ordinary classes.
1249 if (ClassTemplateDecl* tmpl =
1250 parent->record()->getDescribedClassTemplate()) {
1251 for (ClassTemplateDecl::spec_iterator it = tmpl->spec_begin();
1252 it != tmpl->spec_end();
1254 // Check trace using each template instantiation as the holder.
1255 if (IsTemplateInstantiation(*it))
1256 CheckTraceOrDispatchMethod(cache_.Lookup(*it), method);
1261 CheckTraceOrDispatchMethod(parent, method);
1264 // Determine what type of tracing method this is (dispatch or trace).
1265 void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) {
1266 bool isTraceAfterDispatch;
1267 if (Config::IsTraceMethod(method, &isTraceAfterDispatch)) {
1268 if (isTraceAfterDispatch || !parent->GetTraceDispatchMethod()) {
1269 CheckTraceMethod(parent, method, isTraceAfterDispatch);
1271 // Dispatch methods are checked when we identify subclasses.
1275 // Check an actual trace method.
1276 void CheckTraceMethod(RecordInfo* parent,
1277 CXXMethodDecl* trace,
1278 bool isTraceAfterDispatch) {
1279 // A trace method must not override any non-virtual trace methods.
1280 if (!isTraceAfterDispatch) {
1281 for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
1282 it != parent->GetBases().end();
1284 RecordInfo* base = it->second.info();
1285 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace())
1286 ReportOverriddenNonVirtualTrace(parent, trace, other);
1290 CheckTraceVisitor visitor(trace, parent);
1291 visitor.TraverseCXXMethodDecl(trace);
1293 for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
1294 it != parent->GetBases().end();
1296 if (!it->second.IsProperlyTraced())
1297 ReportBaseRequiresTracing(parent, trace, it->first);
1300 for (RecordInfo::Fields::iterator it = parent->GetFields().begin();
1301 it != parent->GetFields().end();
1303 if (!it->second.IsProperlyTraced()) {
1304 // Discontinue once an untraced-field error is found.
1305 ReportFieldsRequireTracing(parent, trace);
1311 void DumpClass(RecordInfo* info) {
1315 json_->OpenObject();
1316 json_->Write("name", info->record()->getQualifiedNameAsString());
1317 json_->Write("loc", GetLocString(info->record()->getLocStart()));
1318 json_->CloseObject();
1320 class DumpEdgeVisitor : public RecursiveEdgeVisitor {
1322 DumpEdgeVisitor(JsonWriter* json) : json_(json) {}
1323 void DumpEdge(RecordInfo* src,
1326 const Edge::LivenessKind& kind,
1327 const string& loc) {
1328 json_->OpenObject();
1329 json_->Write("src", src->record()->getQualifiedNameAsString());
1330 json_->Write("dst", dst->record()->getQualifiedNameAsString());
1331 json_->Write("lbl", lbl);
1332 json_->Write("kind", kind);
1333 json_->Write("loc", loc);
1336 Parent()->IsRawPtr() ? "raw" :
1337 Parent()->IsRefPtr() ? "ref" :
1338 Parent()->IsOwnPtr() ? "own" :
1339 (Parent()->IsMember() ||
1340 Parent()->IsWeakMember()) ? "mem" :
1342 json_->CloseObject();
1345 void DumpField(RecordInfo* src, FieldPoint* point, const string& loc) {
1349 point_->edge()->Accept(this);
1352 void AtValue(Value* e) override {
1353 // The liveness kind of a path from the point to this value
1354 // is given by the innermost place that is non-strong.
1355 Edge::LivenessKind kind = Edge::kStrong;
1356 if (Config::IsIgnoreCycleAnnotated(point_->field())) {
1359 for (Context::iterator it = context().begin();
1360 it != context().end();
1362 Edge::LivenessKind pointer_kind = (*it)->Kind();
1363 if (pointer_kind != Edge::kStrong) {
1364 kind = pointer_kind;
1370 src_, e->value(), point_->field()->getNameAsString(), kind, loc_);
1380 DumpEdgeVisitor visitor(json_);
1382 RecordInfo::Bases& bases = info->GetBases();
1383 for (RecordInfo::Bases::iterator it = bases.begin();
1386 visitor.DumpEdge(info,
1390 GetLocString(it->second.spec().getLocStart()));
1393 RecordInfo::Fields& fields = info->GetFields();
1394 for (RecordInfo::Fields::iterator it = fields.begin();
1397 visitor.DumpField(info,
1399 GetLocString(it->second.field()->getLocStart()));
1403 // Adds either a warning or error, based on the current handling of -Werror.
1404 DiagnosticsEngine::Level getErrorLevel() {
1405 return diagnostic_.getWarningsAsErrors() ? DiagnosticsEngine::Error
1406 : DiagnosticsEngine::Warning;
1409 const string GetLocString(SourceLocation loc) {
1410 const SourceManager& source_manager = instance_.getSourceManager();
1411 PresumedLoc ploc = source_manager.getPresumedLoc(loc);
1412 if (ploc.isInvalid())
1415 llvm::raw_string_ostream OS(loc_str);
1416 OS << ploc.getFilename()
1417 << ":" << ploc.getLine()
1418 << ":" << ploc.getColumn();
1422 bool IsIgnored(RecordInfo* record) {
1424 !InCheckedNamespace(record) ||
1425 IsIgnoredClass(record) ||
1426 InIgnoredDirectory(record);
1429 bool IsIgnoredClass(RecordInfo* info) {
1430 // Ignore any class prefixed by SameSizeAs. These are used in
1431 // Blink to verify class sizes and don't need checking.
1432 const string SameSizeAs = "SameSizeAs";
1433 if (info->name().compare(0, SameSizeAs.size(), SameSizeAs) == 0)
1435 return options_.ignored_classes.find(info->name()) !=
1436 options_.ignored_classes.end();
1439 bool InIgnoredDirectory(RecordInfo* info) {
1441 if (!GetFilename(info->record()->getLocStart(), &filename))
1442 return false; // TODO: should we ignore non-existing file locations?
1443 std::vector<string>::iterator it = options_.ignored_directories.begin();
1444 for (; it != options_.ignored_directories.end(); ++it)
1445 if (filename.find(*it) != string::npos)
1450 bool InCheckedNamespace(RecordInfo* info) {
1453 for (DeclContext* context = info->record()->getDeclContext();
1454 !context->isTranslationUnit();
1455 context = context->getParent()) {
1456 if (NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context)) {
1457 if (options_.checked_namespaces.find(decl->getNameAsString()) !=
1458 options_.checked_namespaces.end()) {
1466 bool GetFilename(SourceLocation loc, string* filename) {
1467 const SourceManager& source_manager = instance_.getSourceManager();
1468 SourceLocation spelling_location = source_manager.getSpellingLoc(loc);
1469 PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location);
1470 if (ploc.isInvalid()) {
1471 // If we're in an invalid location, we're looking at things that aren't
1472 // actually stated in the source.
1475 *filename = ploc.getFilename();
1479 void ReportClassMustLeftMostlyDeriveGC(RecordInfo* info) {
1480 SourceLocation loc = info->record()->getInnerLocStart();
1481 SourceManager& manager = instance_.getSourceManager();
1482 FullSourceLoc full_loc(loc, manager);
1483 diagnostic_.Report(full_loc, diag_class_must_left_mostly_derive_gc_)
1487 void ReportClassRequiresTraceMethod(RecordInfo* info) {
1488 SourceLocation loc = info->record()->getInnerLocStart();
1489 SourceManager& manager = instance_.getSourceManager();
1490 FullSourceLoc full_loc(loc, manager);
1491 diagnostic_.Report(full_loc, diag_class_requires_trace_method_)
1494 for (RecordInfo::Bases::iterator it = info->GetBases().begin();
1495 it != info->GetBases().end();
1497 if (it->second.NeedsTracing().IsNeeded())
1498 NoteBaseRequiresTracing(&it->second);
1501 for (RecordInfo::Fields::iterator it = info->GetFields().begin();
1502 it != info->GetFields().end();
1504 if (!it->second.IsProperlyTraced())
1505 NoteFieldRequiresTracing(info, it->first);
1509 void ReportBaseRequiresTracing(RecordInfo* derived,
1510 CXXMethodDecl* trace,
1511 CXXRecordDecl* base) {
1512 SourceLocation loc = trace->getLocStart();
1513 SourceManager& manager = instance_.getSourceManager();
1514 FullSourceLoc full_loc(loc, manager);
1515 diagnostic_.Report(full_loc, diag_base_requires_tracing_)
1516 << base << derived->record();
1519 void ReportFieldsRequireTracing(RecordInfo* info, CXXMethodDecl* trace) {
1520 SourceLocation loc = trace->getLocStart();
1521 SourceManager& manager = instance_.getSourceManager();
1522 FullSourceLoc full_loc(loc, manager);
1523 diagnostic_.Report(full_loc, diag_fields_require_tracing_)
1525 for (RecordInfo::Fields::iterator it = info->GetFields().begin();
1526 it != info->GetFields().end();
1528 if (!it->second.IsProperlyTraced())
1529 NoteFieldRequiresTracing(info, it->first);
1533 void ReportClassContainsInvalidFields(RecordInfo* info,
1534 CheckFieldsVisitor::Errors* errors) {
1535 SourceLocation loc = info->record()->getLocStart();
1536 SourceManager& manager = instance_.getSourceManager();
1537 FullSourceLoc full_loc(loc, manager);
1538 bool only_warnings = options_.warn_raw_ptr;
1539 for (CheckFieldsVisitor::Errors::iterator it = errors->begin();
1540 only_warnings && it != errors->end();
1542 if (it->second != CheckFieldsVisitor::kRawPtrToGCManagedWarning)
1543 only_warnings = false;
1545 diagnostic_.Report(full_loc, only_warnings ?
1546 diag_class_contains_invalid_fields_warning_ :
1547 diag_class_contains_invalid_fields_)
1549 for (CheckFieldsVisitor::Errors::iterator it = errors->begin();
1550 it != errors->end();
1553 if (it->second == CheckFieldsVisitor::kRawPtrToGCManaged ||
1554 it->second == CheckFieldsVisitor::kRawPtrToGCManagedWarning) {
1555 error = diag_raw_ptr_to_gc_managed_class_note_;
1556 } else if (it->second == CheckFieldsVisitor::kRefPtrToGCManaged) {
1557 error = diag_ref_ptr_to_gc_managed_class_note_;
1558 } else if (it->second == CheckFieldsVisitor::kOwnPtrToGCManaged) {
1559 error = diag_own_ptr_to_gc_managed_class_note_;
1560 } else if (it->second == CheckFieldsVisitor::kMemberInUnmanaged) {
1561 error = diag_member_in_unmanaged_class_note_;
1562 } else if (it->second == CheckFieldsVisitor::kPtrFromHeapToStack) {
1563 error = diag_stack_allocated_field_note_;
1564 } else if (it->second == CheckFieldsVisitor::kGCDerivedPartObject) {
1565 error = diag_part_object_to_gc_derived_class_note_;
1567 assert(false && "Unknown field error");
1569 NoteField(it->first, error);
1573 void ReportClassContainsGCRoots(RecordInfo* info,
1574 CheckGCRootsVisitor::Errors* errors) {
1575 SourceLocation loc = info->record()->getLocStart();
1576 SourceManager& manager = instance_.getSourceManager();
1577 FullSourceLoc full_loc(loc, manager);
1578 for (CheckGCRootsVisitor::Errors::iterator it = errors->begin();
1579 it != errors->end();
1581 CheckGCRootsVisitor::RootPath::iterator path = it->begin();
1582 FieldPoint* point = *path;
1583 diagnostic_.Report(full_loc, diag_class_contains_gc_root_)
1584 << info->record() << point->field();
1585 while (++path != it->end()) {
1586 NotePartObjectContainsGCRoot(point);
1589 NoteFieldContainsGCRoot(point);
1593 void ReportFinalizerAccessesFinalizedFields(
1594 CXXMethodDecl* dtor,
1595 CheckFinalizerVisitor::Errors* fields) {
1596 for (CheckFinalizerVisitor::Errors::iterator it = fields->begin();
1597 it != fields->end();
1599 SourceLocation loc = it->first->getLocStart();
1600 SourceManager& manager = instance_.getSourceManager();
1601 FullSourceLoc full_loc(loc, manager);
1602 diagnostic_.Report(full_loc, diag_finalizer_accesses_finalized_field_)
1603 << dtor << it->second->field();
1604 NoteField(it->second, diag_finalized_field_note_);
1608 void ReportClassRequiresFinalization(RecordInfo* info) {
1609 SourceLocation loc = info->record()->getInnerLocStart();
1610 SourceManager& manager = instance_.getSourceManager();
1611 FullSourceLoc full_loc(loc, manager);
1612 diagnostic_.Report(full_loc, diag_class_requires_finalization_)
1616 void ReportClassDoesNotRequireFinalization(RecordInfo* info) {
1617 SourceLocation loc = info->record()->getInnerLocStart();
1618 SourceManager& manager = instance_.getSourceManager();
1619 FullSourceLoc full_loc(loc, manager);
1620 diagnostic_.Report(full_loc, diag_class_does_not_require_finalization_)
1624 void ReportOverriddenNonVirtualTrace(RecordInfo* info,
1625 CXXMethodDecl* trace,
1626 CXXMethodDecl* overridden) {
1627 SourceLocation loc = trace->getLocStart();
1628 SourceManager& manager = instance_.getSourceManager();
1629 FullSourceLoc full_loc(loc, manager);
1630 diagnostic_.Report(full_loc, diag_overridden_non_virtual_trace_)
1631 << info->record() << overridden->getParent();
1632 NoteOverriddenNonVirtualTrace(overridden);
1635 void ReportMissingTraceDispatchMethod(RecordInfo* info) {
1636 ReportMissingDispatchMethod(info, diag_missing_trace_dispatch_method_);
1639 void ReportMissingFinalizeDispatchMethod(RecordInfo* info) {
1640 ReportMissingDispatchMethod(info, diag_missing_finalize_dispatch_method_);
1643 void ReportMissingDispatchMethod(RecordInfo* info, unsigned error) {
1644 SourceLocation loc = info->record()->getInnerLocStart();
1645 SourceManager& manager = instance_.getSourceManager();
1646 FullSourceLoc full_loc(loc, manager);
1647 diagnostic_.Report(full_loc, error) << info->record();
1650 void ReportVirtualAndManualDispatch(RecordInfo* info,
1651 CXXMethodDecl* dispatch) {
1652 SourceLocation loc = info->record()->getInnerLocStart();
1653 SourceManager& manager = instance_.getSourceManager();
1654 FullSourceLoc full_loc(loc, manager);
1655 diagnostic_.Report(full_loc, diag_virtual_and_manual_dispatch_)
1657 NoteManualDispatchMethod(dispatch);
1660 void ReportMissingTraceDispatch(const FunctionDecl* dispatch,
1661 RecordInfo* receiver) {
1662 ReportMissingDispatch(dispatch, receiver, diag_missing_trace_dispatch_);
1665 void ReportMissingFinalizeDispatch(const FunctionDecl* dispatch,
1666 RecordInfo* receiver) {
1667 ReportMissingDispatch(dispatch, receiver, diag_missing_finalize_dispatch_);
1670 void ReportMissingDispatch(const FunctionDecl* dispatch,
1671 RecordInfo* receiver,
1673 SourceLocation loc = dispatch->getLocStart();
1674 SourceManager& manager = instance_.getSourceManager();
1675 FullSourceLoc full_loc(loc, manager);
1676 diagnostic_.Report(full_loc, error) << receiver->record();
1679 void ReportDerivesNonStackAllocated(RecordInfo* info, BasePoint* base) {
1680 SourceLocation loc = base->spec().getLocStart();
1681 SourceManager& manager = instance_.getSourceManager();
1682 FullSourceLoc full_loc(loc, manager);
1683 diagnostic_.Report(full_loc, diag_derives_non_stack_allocated_)
1684 << info->record() << base->info()->record();
1687 void ReportClassOverridesNew(RecordInfo* info, CXXMethodDecl* newop) {
1688 SourceLocation loc = newop->getLocStart();
1689 SourceManager& manager = instance_.getSourceManager();
1690 FullSourceLoc full_loc(loc, manager);
1691 diagnostic_.Report(full_loc, diag_class_overrides_new_) << info->record();
1694 void ReportClassDeclaresPureVirtualTrace(RecordInfo* info,
1695 CXXMethodDecl* trace) {
1696 SourceLocation loc = trace->getLocStart();
1697 SourceManager& manager = instance_.getSourceManager();
1698 FullSourceLoc full_loc(loc, manager);
1699 diagnostic_.Report(full_loc, diag_class_declares_pure_virtual_trace_)
1703 void ReportLeftMostBaseMustBePolymorphic(RecordInfo* derived,
1704 CXXRecordDecl* base) {
1705 SourceLocation loc = base->getLocStart();
1706 SourceManager& manager = instance_.getSourceManager();
1707 FullSourceLoc full_loc(loc, manager);
1708 diagnostic_.Report(full_loc, diag_left_most_base_must_be_polymorphic_)
1709 << base << derived->record();
1712 void ReportBaseClassMustDeclareVirtualTrace(RecordInfo* derived,
1713 CXXRecordDecl* base) {
1714 SourceLocation loc = base->getLocStart();
1715 SourceManager& manager = instance_.getSourceManager();
1716 FullSourceLoc full_loc(loc, manager);
1717 diagnostic_.Report(full_loc, diag_base_class_must_declare_virtual_trace_)
1718 << base << derived->record();
1721 void NoteManualDispatchMethod(CXXMethodDecl* dispatch) {
1722 SourceLocation loc = dispatch->getLocStart();
1723 SourceManager& manager = instance_.getSourceManager();
1724 FullSourceLoc full_loc(loc, manager);
1725 diagnostic_.Report(full_loc, diag_manual_dispatch_method_note_) << dispatch;
1728 void NoteBaseRequiresTracing(BasePoint* base) {
1729 SourceLocation loc = base->spec().getLocStart();
1730 SourceManager& manager = instance_.getSourceManager();
1731 FullSourceLoc full_loc(loc, manager);
1732 diagnostic_.Report(full_loc, diag_base_requires_tracing_note_)
1733 << base->info()->record();
1736 void NoteFieldRequiresTracing(RecordInfo* holder, FieldDecl* field) {
1737 NoteField(field, diag_field_requires_tracing_note_);
1740 void NotePartObjectContainsGCRoot(FieldPoint* point) {
1741 FieldDecl* field = point->field();
1742 SourceLocation loc = field->getLocStart();
1743 SourceManager& manager = instance_.getSourceManager();
1744 FullSourceLoc full_loc(loc, manager);
1745 diagnostic_.Report(full_loc, diag_part_object_contains_gc_root_note_)
1746 << field << field->getParent();
1749 void NoteFieldContainsGCRoot(FieldPoint* point) {
1750 NoteField(point, diag_field_contains_gc_root_note_);
1753 void NoteUserDeclaredDestructor(CXXMethodDecl* dtor) {
1754 SourceLocation loc = dtor->getLocStart();
1755 SourceManager& manager = instance_.getSourceManager();
1756 FullSourceLoc full_loc(loc, manager);
1757 diagnostic_.Report(full_loc, diag_user_declared_destructor_note_);
1760 void NoteUserDeclaredFinalizer(CXXMethodDecl* dtor) {
1761 SourceLocation loc = dtor->getLocStart();
1762 SourceManager& manager = instance_.getSourceManager();
1763 FullSourceLoc full_loc(loc, manager);
1764 diagnostic_.Report(full_loc, diag_user_declared_finalizer_note_);
1767 void NoteBaseRequiresFinalization(BasePoint* base) {
1768 SourceLocation loc = base->spec().getLocStart();
1769 SourceManager& manager = instance_.getSourceManager();
1770 FullSourceLoc full_loc(loc, manager);
1771 diagnostic_.Report(full_loc, diag_base_requires_finalization_note_)
1772 << base->info()->record();
1775 void NoteField(FieldPoint* point, unsigned note) {
1776 NoteField(point->field(), note);
1779 void NoteField(FieldDecl* field, unsigned note) {
1780 SourceLocation loc = field->getLocStart();
1781 SourceManager& manager = instance_.getSourceManager();
1782 FullSourceLoc full_loc(loc, manager);
1783 diagnostic_.Report(full_loc, note) << field;
1786 void NoteOverriddenNonVirtualTrace(CXXMethodDecl* overridden) {
1787 SourceLocation loc = overridden->getLocStart();
1788 SourceManager& manager = instance_.getSourceManager();
1789 FullSourceLoc full_loc(loc, manager);
1790 diagnostic_.Report(full_loc, diag_overridden_non_virtual_trace_note_)
1794 unsigned diag_class_must_left_mostly_derive_gc_;
1795 unsigned diag_class_requires_trace_method_;
1796 unsigned diag_base_requires_tracing_;
1797 unsigned diag_fields_require_tracing_;
1798 unsigned diag_class_contains_invalid_fields_;
1799 unsigned diag_class_contains_invalid_fields_warning_;
1800 unsigned diag_class_contains_gc_root_;
1801 unsigned diag_class_requires_finalization_;
1802 unsigned diag_class_does_not_require_finalization_;
1803 unsigned diag_finalizer_accesses_finalized_field_;
1804 unsigned diag_overridden_non_virtual_trace_;
1805 unsigned diag_missing_trace_dispatch_method_;
1806 unsigned diag_missing_finalize_dispatch_method_;
1807 unsigned diag_virtual_and_manual_dispatch_;
1808 unsigned diag_missing_trace_dispatch_;
1809 unsigned diag_missing_finalize_dispatch_;
1810 unsigned diag_derives_non_stack_allocated_;
1811 unsigned diag_class_overrides_new_;
1812 unsigned diag_class_declares_pure_virtual_trace_;
1813 unsigned diag_left_most_base_must_be_polymorphic_;
1814 unsigned diag_base_class_must_declare_virtual_trace_;
1816 unsigned diag_base_requires_tracing_note_;
1817 unsigned diag_field_requires_tracing_note_;
1818 unsigned diag_raw_ptr_to_gc_managed_class_note_;
1819 unsigned diag_ref_ptr_to_gc_managed_class_note_;
1820 unsigned diag_own_ptr_to_gc_managed_class_note_;
1821 unsigned diag_stack_allocated_field_note_;
1822 unsigned diag_member_in_unmanaged_class_note_;
1823 unsigned diag_part_object_to_gc_derived_class_note_;
1824 unsigned diag_part_object_contains_gc_root_note_;
1825 unsigned diag_field_contains_gc_root_note_;
1826 unsigned diag_finalized_field_note_;
1827 unsigned diag_user_declared_destructor_note_;
1828 unsigned diag_user_declared_finalizer_note_;
1829 unsigned diag_base_requires_finalization_note_;
1830 unsigned diag_field_requires_finalization_note_;
1831 unsigned diag_overridden_non_virtual_trace_note_;
1832 unsigned diag_manual_dispatch_method_note_;
1834 CompilerInstance& instance_;
1835 DiagnosticsEngine& diagnostic_;
1836 BlinkGCPluginOptions options_;
1841 class BlinkGCPluginAction : public PluginASTAction {
1843 BlinkGCPluginAction() {}
1846 // Overridden from PluginASTAction:
1847 virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(
1848 CompilerInstance& instance,
1849 llvm::StringRef ref) {
1850 return llvm::make_unique<BlinkGCPluginConsumer>(instance, options_);
1853 virtual bool ParseArgs(const CompilerInstance& instance,
1854 const std::vector<string>& args) {
1857 for (size_t i = 0; i < args.size() && parsed; ++i) {
1858 if (args[i] == "enable-oilpan") {
1859 options_.enable_oilpan = true;
1860 } else if (args[i] == "dump-graph") {
1861 options_.dump_graph = true;
1862 } else if (args[i] == "warn-raw-ptr") {
1863 options_.warn_raw_ptr = true;
1864 } else if (args[i] == "warn-unneeded-finalizer") {
1865 options_.warn_unneeded_finalizer = true;
1868 llvm::errs() << "Unknown blink-gc-plugin argument: " << args[i] << "\n";
1876 BlinkGCPluginOptions options_;
1881 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X(
1883 "Check Blink GC invariants");