Chromium Code Reviews| 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 |