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); |
551 if (!visitor.finalized_fields().empty()) { | 659 if (!visitor.finalized_fields().empty()) { |
552 ReportFinalizerAccessesFinalizedFields( | 660 ReportFinalizerAccessesFinalizedFields( |
553 dtor, &visitor.finalized_fields()); | 661 dtor, &visitor.finalized_fields()); |
554 } | 662 } |
555 } | 663 } |
556 return; | 664 return; |
557 } | 665 } |
558 | 666 |
559 // Don't require finalization of a mixin that has not yet been "mixed in". | 667 // Don't require finalization of a mixin that has not yet been "mixed in". |
560 if (info->IsUnmixedGCMixin()) | 668 if (info->IsGCMixin()) |
561 return; | 669 return; |
562 | 670 |
563 // Report the finalization error, and proceed to print possible causes for | 671 // Report the finalization error, and proceed to print possible causes for |
564 // the finalization requirement. | 672 // the finalization requirement. |
565 ReportClassRequiresFinalization(info); | 673 ReportClassRequiresFinalization(info); |
566 | 674 |
567 if (dtor && dtor->isUserProvided()) | 675 if (dtor && dtor->isUserProvided()) |
568 NoteUserDeclaredDestructor(dtor); | 676 NoteUserDeclaredDestructor(dtor); |
569 | 677 |
570 for (RecordInfo::Bases::iterator it = info->GetBases().begin(); | 678 for (RecordInfo::Bases::iterator it = info->GetBases().begin(); |
(...skipping 31 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 will |
| 738 // never be used for dispatching. |
| 739 if (base->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 |