OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This clang plugin checks various invariants of the Blink garbage | 5 // This clang plugin checks various invariants of the Blink garbage |
6 // collection infrastructure. | 6 // collection infrastructure. |
7 // | 7 // |
8 // Errors are described at: | 8 // Errors are described at: |
9 // http://www.chromium.org/developers/blink-gc-plugin-errors | 9 // http://www.chromium.org/developers/blink-gc-plugin-errors |
10 | 10 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
55 | 55 |
56 const char kOwnPtrToGCManagedClassNote[] = | 56 const char kOwnPtrToGCManagedClassNote[] = |
57 "[blink-gc] OwnPtr field %0 to a GC managed class declared here:"; | 57 "[blink-gc] OwnPtr field %0 to a GC managed class declared here:"; |
58 | 58 |
59 const char kPartObjectContainsGCRoot[] = | 59 const char kPartObjectContainsGCRoot[] = |
60 "[blink-gc] Field %0 with embedded GC root in %1 declared here:"; | 60 "[blink-gc] Field %0 with embedded GC root in %1 declared here:"; |
61 | 61 |
62 const char kFieldContainsGCRoot[] = | 62 const char kFieldContainsGCRoot[] = |
63 "[blink-gc] Field %0 defining a GC root declared here:"; | 63 "[blink-gc] Field %0 defining a GC root declared here:"; |
64 | 64 |
65 const char kOverriddenNonVirtualTrace[] = | |
66 "[blink-gc] Class %0 overrides non-virtual trace of base class %1."; | |
67 | |
68 const char kOverriddenNonVirtualTraceNote[] = | |
69 "[blink-gc] Non-virtual trace method declared here:"; | |
70 | |
71 const char kVirtualTraceAndManualDispatch[] = | |
72 "[blink-gc] Class %0 declares a virtual trace" | |
73 " but implements manual dispatching."; | |
74 | |
75 const char kVirtualAndManualDispatch[] = | |
76 "[blink-gc] Class %0 contains or inherits virtual methods" | |
77 " but implements manual dispatching."; | |
78 | |
79 const char kMissingTraceDispatch[] = | |
80 "[blink-gc] Missing dispatch to class %0 in manual trace dispatch."; | |
81 | |
82 const char kMissingFinalize[] = | |
83 "[blink-gc] Class %0 is missing manual finalize dispatch."; | |
84 | |
85 const char kMissingFinalizeDispatch[] = | |
86 "[blink-gc] Missing dispatch to class %0 in manual finalize dispatch."; | |
87 | |
65 const char kFinalizedFieldNote[] = | 88 const char kFinalizedFieldNote[] = |
66 "[blink-gc] Potentially finalized field %0 declared here:"; | 89 "[blink-gc] Potentially finalized field %0 declared here:"; |
67 | 90 |
68 const char kUserDeclaredDestructorNote[] = | 91 const char kUserDeclaredDestructorNote[] = |
69 "[blink-gc] User-declared destructor declared here:"; | 92 "[blink-gc] User-declared destructor declared here:"; |
70 | 93 |
71 const char kBaseRequiresFinalizationNote[] = | 94 const char kBaseRequiresFinalizationNote[] = |
72 "[blink-gc] Base class %0 requiring finalization declared here:"; | 95 "[blink-gc] Base class %0 requiring finalization declared here:"; |
73 | 96 |
74 const char kFieldRequiresFinalizationNote[] = | 97 const char kFieldRequiresFinalizationNote[] = |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
169 : blacklist_context_(false), cache_(cache) {} | 192 : blacklist_context_(false), cache_(cache) {} |
170 | 193 |
171 Errors& finalized_fields() { return finalized_fields_; } | 194 Errors& finalized_fields() { return finalized_fields_; } |
172 | 195 |
173 bool WalkUpFromCXXOperatorCallExpr(CXXOperatorCallExpr* expr) { | 196 bool WalkUpFromCXXOperatorCallExpr(CXXOperatorCallExpr* expr) { |
174 // Only continue the walk-up if the operator is a blacklisted one. | 197 // Only continue the walk-up if the operator is a blacklisted one. |
175 switch (expr->getOperator()) { | 198 switch (expr->getOperator()) { |
176 case OO_Arrow: | 199 case OO_Arrow: |
177 case OO_Subscript: | 200 case OO_Subscript: |
178 this->WalkUpFromCallExpr(expr); | 201 this->WalkUpFromCallExpr(expr); |
202 default: | |
203 return true; | |
179 } | 204 } |
180 return true; | |
181 } | 205 } |
182 | 206 |
183 // We consider all non-operator calls to be blacklisted contexts. | 207 // We consider all non-operator calls to be blacklisted contexts. |
184 bool WalkUpFromCallExpr(CallExpr* expr) { | 208 bool WalkUpFromCallExpr(CallExpr* expr) { |
185 bool prev_blacklist_context = blacklist_context_; | 209 bool prev_blacklist_context = blacklist_context_; |
186 blacklist_context_ = true; | 210 blacklist_context_ = true; |
187 for (size_t i = 0; i < expr->getNumArgs(); ++i) | 211 for (size_t i = 0; i < expr->getNumArgs(); ++i) |
188 this->TraverseStmt(expr->getArg(i)); | 212 this->TraverseStmt(expr->getArg(i)); |
189 blacklist_context_ = prev_blacklist_context; | 213 blacklist_context_ = prev_blacklist_context; |
190 return true; | 214 return true; |
(...skipping 22 matching lines...) Expand all Loading... | |
213 point->edge()->Accept(&visitor); | 237 point->edge()->Accept(&visitor); |
214 return visitor.might_be_collected(); | 238 return visitor.might_be_collected(); |
215 } | 239 } |
216 | 240 |
217 private: | 241 private: |
218 bool blacklist_context_; | 242 bool blacklist_context_; |
219 Errors finalized_fields_; | 243 Errors finalized_fields_; |
220 RecordCache* cache_; | 244 RecordCache* cache_; |
221 }; | 245 }; |
222 | 246 |
247 // This visitor checks that a method contains within its body, a call to a | |
248 // method on the provided receiver class. This is used to check manual | |
249 // dispatching for trace and finalize methods. | |
250 class CheckDispatchVisitor : public RecursiveASTVisitor<CheckDispatchVisitor> { | |
251 public: | |
252 CheckDispatchVisitor(RecordInfo* receiver) | |
253 : receiver_(receiver), dispatched_to_receiver_(false) { } | |
254 | |
255 bool dispatched_to_receiver() { return dispatched_to_receiver_; } | |
256 | |
257 bool VisitMemberExpr(MemberExpr* member) { | |
258 if (CXXMethodDecl* fn = dyn_cast<CXXMethodDecl>(member->getMemberDecl())) { | |
259 if (fn->getParent() == receiver_->record()) | |
260 dispatched_to_receiver_ = true; | |
261 } | |
262 return true; | |
263 } | |
264 | |
265 private: | |
266 RecordInfo* receiver_; | |
267 bool dispatched_to_receiver_; | |
268 }; | |
269 | |
223 // This visitor checks a tracing method by traversing its body. | 270 // This visitor checks a tracing method by traversing its body. |
224 // - A member field is considered traced if it is referenced in the body. | 271 // - A member field is considered traced if it is referenced in the body. |
225 // - A base is traced if a base-qualified call to a trace method is found. | 272 // - A base is traced if a base-qualified call to a trace method is found. |
226 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { | 273 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { |
227 public: | 274 public: |
228 CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info) | 275 CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info) |
229 : trace_(trace), info_(info) {} | 276 : trace_(trace), info_(info) {} |
230 | 277 |
231 // Allow recursive traversal by using VisitMemberExpr. | 278 // Allow recursive traversal by using VisitMemberExpr. |
232 bool VisitMemberExpr(MemberExpr* member) { | 279 bool VisitMemberExpr(MemberExpr* member) { |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
439 diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing); | 486 diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing); |
440 diag_class_contains_invalid_fields_ = | 487 diag_class_contains_invalid_fields_ = |
441 diagnostic_.getCustomDiagID(getErrorLevel(), | 488 diagnostic_.getCustomDiagID(getErrorLevel(), |
442 kClassContainsInvalidFields); | 489 kClassContainsInvalidFields); |
443 diag_class_contains_gc_root_ = | 490 diag_class_contains_gc_root_ = |
444 diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRoot); | 491 diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRoot); |
445 diag_class_requires_finalization_ = diagnostic_.getCustomDiagID( | 492 diag_class_requires_finalization_ = diagnostic_.getCustomDiagID( |
446 getErrorLevel(), kClassRequiresFinalization); | 493 getErrorLevel(), kClassRequiresFinalization); |
447 diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID( | 494 diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID( |
448 getErrorLevel(), kFinalizerAccessesFinalizedField); | 495 getErrorLevel(), kFinalizerAccessesFinalizedField); |
496 diag_overridden_non_virtual_trace_ = diagnostic_.getCustomDiagID( | |
497 getErrorLevel(), kOverriddenNonVirtualTrace); | |
498 diag_virtual_and_manual_dispatch_ = diagnostic_.getCustomDiagID( | |
499 getErrorLevel(), kVirtualAndManualDispatch); | |
500 diag_missing_trace_dispatch_ = diagnostic_.getCustomDiagID( | |
501 getErrorLevel(), kMissingTraceDispatch); | |
502 diag_missing_finalize_ = diagnostic_.getCustomDiagID( | |
503 getErrorLevel(), kMissingFinalize); | |
504 diag_missing_finalize_dispatch_ = diagnostic_.getCustomDiagID( | |
505 getErrorLevel(), kMissingFinalizeDispatch); | |
449 | 506 |
450 // Register note messages. | 507 // Register note messages. |
451 diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID( | 508 diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID( |
452 DiagnosticsEngine::Note, kFieldRequiresTracingNote); | 509 DiagnosticsEngine::Note, kFieldRequiresTracingNote); |
453 diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( | 510 diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( |
454 DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote); | 511 DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote); |
455 diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( | 512 diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( |
456 DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote); | 513 DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote); |
457 diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( | 514 diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( |
458 DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote); | 515 DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote); |
459 diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID( | 516 diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID( |
460 DiagnosticsEngine::Note, kPartObjectContainsGCRoot); | 517 DiagnosticsEngine::Note, kPartObjectContainsGCRoot); |
461 diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID( | 518 diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID( |
462 DiagnosticsEngine::Note, kFieldContainsGCRoot); | 519 DiagnosticsEngine::Note, kFieldContainsGCRoot); |
463 diag_finalized_field_note_ = diagnostic_.getCustomDiagID( | 520 diag_finalized_field_note_ = diagnostic_.getCustomDiagID( |
464 DiagnosticsEngine::Note, kFinalizedFieldNote); | 521 DiagnosticsEngine::Note, kFinalizedFieldNote); |
465 diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID( | 522 diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID( |
466 DiagnosticsEngine::Note, kUserDeclaredDestructorNote); | 523 DiagnosticsEngine::Note, kUserDeclaredDestructorNote); |
467 diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID( | 524 diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID( |
468 DiagnosticsEngine::Note, kBaseRequiresFinalizationNote); | 525 DiagnosticsEngine::Note, kBaseRequiresFinalizationNote); |
469 diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID( | 526 diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID( |
470 DiagnosticsEngine::Note, kFieldRequiresFinalizationNote); | 527 DiagnosticsEngine::Note, kFieldRequiresFinalizationNote); |
528 diag_overridden_non_virtual_trace_note_ = diagnostic_.getCustomDiagID( | |
529 DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote); | |
471 } | 530 } |
472 | 531 |
473 virtual void HandleTranslationUnit(ASTContext& context) { | 532 virtual void HandleTranslationUnit(ASTContext& context) { |
474 CollectVisitor visitor; | 533 CollectVisitor visitor; |
475 visitor.TraverseDecl(context.getTranslationUnitDecl()); | 534 visitor.TraverseDecl(context.getTranslationUnitDecl()); |
476 | 535 |
477 for (RecordVector::iterator it = visitor.record_decls().begin(); | 536 for (RecordVector::iterator it = visitor.record_decls().begin(); |
478 it != visitor.record_decls().end(); | 537 it != visitor.record_decls().end(); |
479 ++it) { | 538 ++it) { |
480 CheckRecord(cache_.Lookup(*it)); | 539 CheckRecord(cache_.Lookup(*it)); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
515 | 574 |
516 // Check a class-like object (eg, class, specialization, instantiation). | 575 // Check a class-like object (eg, class, specialization, instantiation). |
517 void CheckClass(RecordInfo* info) { | 576 void CheckClass(RecordInfo* info) { |
518 // Don't enforce tracing of stack allocated objects. | 577 // Don't enforce tracing of stack allocated objects. |
519 if (!info || info->IsStackAllocated()) | 578 if (!info || info->IsStackAllocated()) |
520 return; | 579 return; |
521 | 580 |
522 if (info->RequiresTraceMethod() && !info->GetTraceMethod()) | 581 if (info->RequiresTraceMethod() && !info->GetTraceMethod()) |
523 ReportClassRequiresTraceMethod(info); | 582 ReportClassRequiresTraceMethod(info); |
524 | 583 |
584 if (CXXMethodDecl* dispatch = info->GetTraceDispatchMethod()) | |
585 CheckDispatch(info, dispatch); | |
586 | |
525 { | 587 { |
526 CheckFieldsVisitor visitor(options_); | 588 CheckFieldsVisitor visitor(options_); |
527 if (visitor.ContainsInvalidFields(info)) | 589 if (visitor.ContainsInvalidFields(info)) |
528 ReportClassContainsInvalidFields(info, &visitor.invalid_fields()); | 590 ReportClassContainsInvalidFields(info, &visitor.invalid_fields()); |
529 } | 591 } |
530 | 592 |
531 if (info->IsGCDerived()) { | 593 if (info->IsGCDerived()) { |
532 CheckGCRootsVisitor visitor; | 594 CheckGCRootsVisitor visitor; |
533 if (visitor.ContainsGCRoots(info)) | 595 if (visitor.ContainsGCRoots(info)) |
534 ReportClassContainsGCRoots(info, &visitor.gc_roots()); | 596 ReportClassContainsGCRoots(info, &visitor.gc_roots()); |
535 | 597 |
536 if (info->NeedsFinalization()) | 598 if (info->NeedsFinalization()) |
537 CheckFinalization(info); | 599 CheckFinalization(info); |
538 } | 600 } |
539 } | 601 } |
540 | 602 |
603 void CheckDispatch(RecordInfo* info, CXXMethodDecl* dispatch) { | |
604 if (info->record()->isPolymorphic()) | |
605 ReportVirtualAndManualDispatch(info); | |
606 | |
607 CXXRecordDecl* base = dispatch->getParent(); | |
608 // If this class is finalized get its finalize dispatch method. | |
609 bool is_finalized = info->IsGCFinalized(); | |
610 CXXMethodDecl* finalize = 0; | |
611 if (is_finalized) { | |
612 for (CXXRecordDecl::method_iterator it = base->method_begin(); | |
613 it != base->method_end(); | |
614 ++it) { | |
615 if (it->getNameAsString() == kFinalizeName) { | |
616 finalize = *it; | |
617 break; | |
618 } | |
619 } | |
620 } | |
621 | |
622 // Check that the dispatching class implements finalize if needed. | |
623 if (is_finalized && !finalize && base == info->record()) | |
624 ReportMissingFinalize(info); | |
625 | |
626 // If this is a non-abstract class check that it is dispatched to. | |
627 // TODO: Create a global variant of this local check. We can only check if | |
628 // the dispatch body is known in this compilation unit. | |
629 if (info->IsConsideredAbstract()) | |
630 return; | |
631 | |
632 const FunctionDecl* defn; | |
633 | |
634 if (dispatch->isDefined(defn)) { | |
635 CheckDispatchVisitor visitor(info); | |
636 visitor.TraverseStmt(defn->getBody()); | |
637 if (!visitor.dispatched_to_receiver()) | |
638 ReportMissingTraceDispatch(defn, info); | |
639 } | |
640 | |
641 if (is_finalized && finalize && finalize->isDefined(defn)) { | |
642 CheckDispatchVisitor visitor(info); | |
643 visitor.TraverseStmt(defn->getBody()); | |
644 if (!visitor.dispatched_to_receiver()) | |
645 ReportMissingFinalizeDispatch(defn, info); | |
646 } | |
647 } | |
648 | |
541 void CheckFinalization(RecordInfo* info) { | 649 void CheckFinalization(RecordInfo* info) { |
542 // TODO: Should we collect destructors similar to trace methods? | 650 // TODO: Should we collect destructors similar to trace methods? |
543 // TODO: Check overridden finalize(). | 651 // TODO: Check overridden finalize(). |
544 CXXDestructorDecl* dtor = info->record()->getDestructor(); | 652 CXXDestructorDecl* dtor = info->record()->getDestructor(); |
545 | 653 |
546 // For finalized classes, check the finalization method if possible. | 654 // For finalized classes, check the finalization method if possible. |
547 if (info->IsGCFinalized()) { | 655 if (info->IsGCFinalized()) { |
548 if (dtor && dtor->hasBody()) { | 656 if (dtor && dtor->hasBody()) { |
549 CheckFinalizerVisitor visitor(&cache_); | 657 CheckFinalizerVisitor visitor(&cache_); |
550 visitor.TraverseCXXMethodDecl(dtor); | 658 visitor.TraverseCXXMethodDecl(dtor); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
602 return; | 710 return; |
603 } | 711 } |
604 | 712 |
605 CheckTraceOrDispatchMethod(parent, method); | 713 CheckTraceOrDispatchMethod(parent, method); |
606 } | 714 } |
607 | 715 |
608 // Determine what type of tracing method this is (dispatch or trace). | 716 // Determine what type of tracing method this is (dispatch or trace). |
609 void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) { | 717 void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) { |
610 bool isTraceAfterDispatch; | 718 bool isTraceAfterDispatch; |
611 if (Config::IsTraceMethod(method, &isTraceAfterDispatch)) { | 719 if (Config::IsTraceMethod(method, &isTraceAfterDispatch)) { |
612 if (!isTraceAfterDispatch && parent->GetTraceDispatchMethod()) | 720 if (isTraceAfterDispatch || !parent->GetTraceDispatchMethod()) { |
613 CheckTraceDispatchMethod(parent, method); | 721 CheckTraceMethod(parent, method, isTraceAfterDispatch); |
614 else | 722 } |
615 CheckTraceMethod(parent, method); | 723 // Dispatch methods are checked when we identify subclasses. |
616 } | 724 } |
617 } | 725 } |
618 | 726 |
619 // Check a tracing dispatch (ie, it dispatches to traceAfterDispatch) | 727 // Check an actual trace method. |
620 void CheckTraceDispatchMethod(RecordInfo* parent, CXXMethodDecl* trace) { | 728 void CheckTraceMethod(RecordInfo* parent, |
621 // TODO: check correct dispatch. | 729 CXXMethodDecl* trace, |
622 } | 730 bool isTraceAfterDispatch) { |
731 // A non-virtual trace method must not override another trace. | |
732 if (!isTraceAfterDispatch && !trace->isVirtual()) { | |
733 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); | |
734 it != parent->GetBases().end(); | |
735 ++it) { | |
736 RecordInfo* base = it->second.info(); | |
737 // We allow mixin bases to contain a non-virtual trace since it is will | |
738 // never be used for dispatching. | |
739 if (base->IsUnmixedGCMixin()) | |
Mads Ager (chromium)
2014/03/18 09:19:32
Can we find a better name for IsUnmixedGCMixin? I
zerny-chromium
2014/03/18 10:03:41
Changed to just IsGCMixin().
| |
740 continue; | |
741 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace()) | |
742 ReportOverriddenNonVirtualTrace(parent, trace, other); | |
743 } | |
744 } | |
623 | 745 |
624 // Check an actual trace method. | |
625 void CheckTraceMethod(RecordInfo* parent, CXXMethodDecl* trace) { | |
626 CheckTraceVisitor visitor(trace, parent); | 746 CheckTraceVisitor visitor(trace, parent); |
627 visitor.TraverseCXXMethodDecl(trace); | 747 visitor.TraverseCXXMethodDecl(trace); |
628 | 748 |
629 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); | 749 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); |
630 it != parent->GetBases().end(); | 750 it != parent->GetBases().end(); |
631 ++it) { | 751 ++it) { |
632 if (!it->second.IsProperlyTraced()) | 752 if (!it->second.IsProperlyTraced()) |
633 ReportBaseRequiresTracing(parent, trace, it->first); | 753 ReportBaseRequiresTracing(parent, trace, it->first); |
634 } | 754 } |
635 | 755 |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
800 } | 920 } |
801 | 921 |
802 void ReportClassRequiresFinalization(RecordInfo* info) { | 922 void ReportClassRequiresFinalization(RecordInfo* info) { |
803 SourceLocation loc = info->record()->getInnerLocStart(); | 923 SourceLocation loc = info->record()->getInnerLocStart(); |
804 SourceManager& manager = instance_.getSourceManager(); | 924 SourceManager& manager = instance_.getSourceManager(); |
805 FullSourceLoc full_loc(loc, manager); | 925 FullSourceLoc full_loc(loc, manager); |
806 diagnostic_.Report(full_loc, diag_class_requires_finalization_) | 926 diagnostic_.Report(full_loc, diag_class_requires_finalization_) |
807 << info->record(); | 927 << info->record(); |
808 } | 928 } |
809 | 929 |
930 void ReportOverriddenNonVirtualTrace(RecordInfo* info, | |
931 CXXMethodDecl* trace, | |
932 CXXMethodDecl* overridden) { | |
933 SourceLocation loc = trace->getLocStart(); | |
934 SourceManager& manager = instance_.getSourceManager(); | |
935 FullSourceLoc full_loc(loc, manager); | |
936 diagnostic_.Report(full_loc, diag_overridden_non_virtual_trace_) | |
937 << info->record() | |
938 << overridden->getParent(); | |
939 NoteOverriddenNonVirtualTrace(overridden); | |
940 } | |
941 | |
942 void ReportVirtualAndManualDispatch(RecordInfo* info) { | |
943 SourceLocation loc = info->record()->getInnerLocStart(); | |
944 SourceManager& manager = instance_.getSourceManager(); | |
945 FullSourceLoc full_loc(loc, manager); | |
946 diagnostic_.Report(full_loc, diag_virtual_and_manual_dispatch_) | |
947 << info->record(); | |
948 } | |
949 | |
950 void ReportMissingTraceDispatch(const FunctionDecl* dispatch, | |
951 RecordInfo* receiver) { | |
952 ReportMissingDispatch(dispatch, receiver, diag_missing_trace_dispatch_); | |
953 } | |
954 | |
955 void ReportMissingFinalize(RecordInfo* info) { | |
956 SourceLocation loc = info->record()->getInnerLocStart(); | |
957 SourceManager& manager = instance_.getSourceManager(); | |
958 FullSourceLoc full_loc(loc, manager); | |
959 diagnostic_.Report(full_loc, diag_missing_finalize_) << info->record(); | |
960 } | |
961 | |
962 void ReportMissingFinalizeDispatch(const FunctionDecl* dispatch, | |
963 RecordInfo* receiver) { | |
964 ReportMissingDispatch(dispatch, receiver, diag_missing_finalize_dispatch_); | |
965 } | |
966 | |
967 void ReportMissingDispatch(const FunctionDecl* dispatch, | |
968 RecordInfo* receiver, | |
969 unsigned error) { | |
970 SourceLocation loc = dispatch->getLocStart(); | |
971 SourceManager& manager = instance_.getSourceManager(); | |
972 FullSourceLoc full_loc(loc, manager); | |
973 diagnostic_.Report(full_loc, error) << receiver->record(); | |
974 } | |
975 | |
810 void NoteFieldRequiresTracing(RecordInfo* holder, FieldDecl* field) { | 976 void NoteFieldRequiresTracing(RecordInfo* holder, FieldDecl* field) { |
811 NoteField(field, diag_field_requires_tracing_note_); | 977 NoteField(field, diag_field_requires_tracing_note_); |
812 } | 978 } |
813 | 979 |
814 void NotePartObjectContainsGCRoot(FieldPoint* point) { | 980 void NotePartObjectContainsGCRoot(FieldPoint* point) { |
815 FieldDecl* field = point->field(); | 981 FieldDecl* field = point->field(); |
816 SourceLocation loc = field->getLocStart(); | 982 SourceLocation loc = field->getLocStart(); |
817 SourceManager& manager = instance_.getSourceManager(); | 983 SourceManager& manager = instance_.getSourceManager(); |
818 FullSourceLoc full_loc(loc, manager); | 984 FullSourceLoc full_loc(loc, manager); |
819 diagnostic_.Report(full_loc, diag_part_object_contains_gc_root_note_) | 985 diagnostic_.Report(full_loc, diag_part_object_contains_gc_root_note_) |
(...skipping 23 matching lines...) Expand all Loading... | |
843 NoteField(point->field(), note); | 1009 NoteField(point->field(), note); |
844 } | 1010 } |
845 | 1011 |
846 void NoteField(FieldDecl* field, unsigned note) { | 1012 void NoteField(FieldDecl* field, unsigned note) { |
847 SourceLocation loc = field->getLocStart(); | 1013 SourceLocation loc = field->getLocStart(); |
848 SourceManager& manager = instance_.getSourceManager(); | 1014 SourceManager& manager = instance_.getSourceManager(); |
849 FullSourceLoc full_loc(loc, manager); | 1015 FullSourceLoc full_loc(loc, manager); |
850 diagnostic_.Report(full_loc, note) << field; | 1016 diagnostic_.Report(full_loc, note) << field; |
851 } | 1017 } |
852 | 1018 |
1019 void NoteOverriddenNonVirtualTrace(CXXMethodDecl* overridden) { | |
1020 SourceLocation loc = overridden->getLocStart(); | |
1021 SourceManager& manager = instance_.getSourceManager(); | |
1022 FullSourceLoc full_loc(loc, manager); | |
1023 diagnostic_.Report(full_loc, diag_overridden_non_virtual_trace_note_) | |
1024 << overridden; | |
1025 } | |
1026 | |
853 unsigned diag_class_requires_trace_method_; | 1027 unsigned diag_class_requires_trace_method_; |
854 unsigned diag_base_requires_tracing_; | 1028 unsigned diag_base_requires_tracing_; |
855 unsigned diag_fields_require_tracing_; | 1029 unsigned diag_fields_require_tracing_; |
856 unsigned diag_class_contains_invalid_fields_; | 1030 unsigned diag_class_contains_invalid_fields_; |
857 unsigned diag_class_contains_gc_root_; | 1031 unsigned diag_class_contains_gc_root_; |
858 unsigned diag_class_requires_finalization_; | 1032 unsigned diag_class_requires_finalization_; |
859 unsigned diag_finalizer_accesses_finalized_field_; | 1033 unsigned diag_finalizer_accesses_finalized_field_; |
1034 unsigned diag_overridden_non_virtual_trace_; | |
1035 unsigned diag_virtual_and_manual_dispatch_; | |
1036 unsigned diag_missing_trace_dispatch_; | |
1037 unsigned diag_missing_finalize_; | |
1038 unsigned diag_missing_finalize_dispatch_; | |
860 | 1039 |
861 unsigned diag_field_requires_tracing_note_; | 1040 unsigned diag_field_requires_tracing_note_; |
862 unsigned diag_raw_ptr_to_gc_managed_class_note_; | 1041 unsigned diag_raw_ptr_to_gc_managed_class_note_; |
863 unsigned diag_ref_ptr_to_gc_managed_class_note_; | 1042 unsigned diag_ref_ptr_to_gc_managed_class_note_; |
864 unsigned diag_own_ptr_to_gc_managed_class_note_; | 1043 unsigned diag_own_ptr_to_gc_managed_class_note_; |
865 unsigned diag_part_object_contains_gc_root_note_; | 1044 unsigned diag_part_object_contains_gc_root_note_; |
866 unsigned diag_field_contains_gc_root_note_; | 1045 unsigned diag_field_contains_gc_root_note_; |
867 unsigned diag_finalized_field_note_; | 1046 unsigned diag_finalized_field_note_; |
868 unsigned diag_user_declared_destructor_note_; | 1047 unsigned diag_user_declared_destructor_note_; |
869 unsigned diag_base_requires_finalization_note_; | 1048 unsigned diag_base_requires_finalization_note_; |
870 unsigned diag_field_requires_finalization_note_; | 1049 unsigned diag_field_requires_finalization_note_; |
1050 unsigned diag_overridden_non_virtual_trace_note_; | |
871 | 1051 |
872 CompilerInstance& instance_; | 1052 CompilerInstance& instance_; |
873 DiagnosticsEngine& diagnostic_; | 1053 DiagnosticsEngine& diagnostic_; |
874 BlinkGCPluginOptions options_; | 1054 BlinkGCPluginOptions options_; |
875 RecordCache cache_; | 1055 RecordCache cache_; |
876 }; | 1056 }; |
877 | 1057 |
878 class BlinkGCPluginAction : public PluginASTAction { | 1058 class BlinkGCPluginAction : public PluginASTAction { |
879 public: | 1059 public: |
880 BlinkGCPluginAction() {} | 1060 BlinkGCPluginAction() {} |
(...skipping 23 matching lines...) Expand all Loading... | |
904 | 1084 |
905 private: | 1085 private: |
906 BlinkGCPluginOptions options_; | 1086 BlinkGCPluginOptions options_; |
907 }; | 1087 }; |
908 | 1088 |
909 } // namespace | 1089 } // namespace |
910 | 1090 |
911 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( | 1091 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( |
912 "blink-gc-plugin", | 1092 "blink-gc-plugin", |
913 "Check Blink GC invariants"); | 1093 "Check Blink GC invariants"); |
OLD | NEW |