Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(539)

Side by Side Diff: tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp

Issue 964273002: BlinkGCPlugin: Handle omitted trace() in intermediary classes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Use range-for. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 307 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 private: 318 private:
319 RecordInfo* receiver_; 319 RecordInfo* receiver_;
320 bool dispatched_to_receiver_; 320 bool dispatched_to_receiver_;
321 }; 321 };
322 322
323 // This visitor checks a tracing method by traversing its body. 323 // This visitor checks a tracing method by traversing its body.
324 // - A member field is considered traced if it is referenced in the body. 324 // - A member field is considered traced if it is referenced in the body.
325 // - A base is traced if a base-qualified call to a trace method is found. 325 // - A base is traced if a base-qualified call to a trace method is found.
326 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { 326 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> {
327 public: 327 public:
328 CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info) 328 CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info, RecordCache* cache)
329 : trace_(trace), info_(info), delegates_to_traceimpl_(false) {} 329 : trace_(trace),
330 info_(info),
331 cache_(cache),
332 delegates_to_traceimpl_(false) {
333 }
330 334
331 bool delegates_to_traceimpl() const { return delegates_to_traceimpl_; } 335 bool delegates_to_traceimpl() const { return delegates_to_traceimpl_; }
332 336
333 bool VisitMemberExpr(MemberExpr* member) { 337 bool VisitMemberExpr(MemberExpr* member) {
334 // In weak callbacks, consider any occurrence as a correct usage. 338 // In weak callbacks, consider any occurrence as a correct usage.
335 // TODO: We really want to require that isAlive is checked on manually 339 // TODO: We really want to require that isAlive is checked on manually
336 // processed weak fields. 340 // processed weak fields.
337 if (IsWeakCallback()) { 341 if (IsWeakCallback()) {
338 if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) 342 if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl()))
339 FoundField(field); 343 FoundField(field);
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 callee_record = trace_decl->getParent(); 538 callee_record = trace_decl->getParent();
535 func_name = callee->getMemberName().getAsString(); 539 func_name = callee->getMemberName().getAsString();
536 } 540 }
537 541
538 if (!callee_record) 542 if (!callee_record)
539 return false; 543 return false;
540 544
541 if (!IsTraceCallName(func_name)) 545 if (!IsTraceCallName(func_name))
542 return false; 546 return false;
543 547
544 RecordInfo::Bases::iterator iter = info_->GetBases().find(callee_record); 548 for (auto& base : info_->GetBases()) {
545 if (iter == info_->GetBases().end()) 549 // We want to deal with omitted trace() function in an intermediary
546 return false; 550 // class in the class hierarchy, e.g.:
551 // class A : public GarbageCollected<A> { trace() { ... } };
552 // class B : public A { /* No trace(); have nothing to trace. */ };
553 // class C : public B { trace() { B::trace(visitor); } }
554 // where, B::trace() is actually A::trace(), and in some cases we get
555 // A as |callee_record| instead of B. We somehow need to mark B as
556 // traced if we find A::trace() call.
557 //
558 // To solve this, here we keep going up the class hierarchy as long as
559 // they are not required to have a trace method. The implementation is
560 // a simple DFS, where |base_records| represents the set of base classes
561 // we need to visit.
547 562
548 iter->second.MarkTraced(); 563 std::vector<CXXRecordDecl*> base_records;
549 return true; 564 base_records.push_back(base.first);
565
566 while (!base_records.empty()) {
567 CXXRecordDecl* base_record = base_records.back();
568 base_records.pop_back();
569
570 if (base_record == callee_record) {
571 // If we find a matching trace method, pretend the user has written
572 // a correct trace() method of the base; in the example above, we
573 // find A::trace() here and mark B as correctly traced.
574 base.second.MarkTraced();
575 return true;
576 }
577
578 if (RecordInfo* base_info = cache_->Lookup(base_record)) {
579 if (!base_info->RequiresTraceMethod()) {
580 // If this base class is not required to have a trace method, then
581 // the actual trace method may be defined in an ancestor.
582 for (auto& inner_base : base_info->GetBases())
583 base_records.push_back(inner_base.first);
584 }
585 }
586 }
587 }
588
589 return false;
550 } 590 }
551 591
552 bool CheckTraceFieldCall(CXXMemberCallExpr* call) { 592 bool CheckTraceFieldCall(CXXMemberCallExpr* call) {
553 return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(), 593 return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(),
554 call->getRecordDecl(), 594 call->getRecordDecl(),
555 call->getArg(0)); 595 call->getArg(0));
556 } 596 }
557 597
558 bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) { 598 bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) {
559 if (name != kTraceName || !Config::IsVisitor(callee->getName())) 599 if (name != kTraceName || !Config::IsVisitor(callee->getName()))
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
602 return false; 642 return false;
603 } 643 }
604 return true; 644 return true;
605 } 645 }
606 private: 646 private:
607 MemberExpr* member_; 647 MemberExpr* member_;
608 FieldDecl* field_; 648 FieldDecl* field_;
609 }; 649 };
610 650
611 // Nested checking for weak callbacks. 651 // Nested checking for weak callbacks.
612 CheckTraceVisitor(RecordInfo* info) : trace_(0), info_(info) {} 652 CheckTraceVisitor(RecordInfo* info)
653 : trace_(nullptr), info_(info), cache_(nullptr) {}
613 654
614 bool IsWeakCallback() { return !trace_; } 655 bool IsWeakCallback() { return !trace_; }
615 656
616 void MarkTraced(RecordInfo::Fields::iterator it) { 657 void MarkTraced(RecordInfo::Fields::iterator it) {
617 // In a weak callback we can't mark strong fields as traced. 658 // In a weak callback we can't mark strong fields as traced.
618 if (IsWeakCallback() && !it->second.edge()->IsWeakMember()) 659 if (IsWeakCallback() && !it->second.edge()->IsWeakMember())
619 return; 660 return;
620 it->second.MarkTraced(); 661 it->second.MarkTraced();
621 } 662 }
622 663
(...skipping 13 matching lines...) Expand all
636 } 677 }
637 } else { 678 } else {
638 RecordInfo::Fields::iterator it = info_->GetFields().find(field); 679 RecordInfo::Fields::iterator it = info_->GetFields().find(field);
639 if (it != info_->GetFields().end()) 680 if (it != info_->GetFields().end())
640 MarkTraced(it); 681 MarkTraced(it);
641 } 682 }
642 } 683 }
643 684
644 CXXMethodDecl* trace_; 685 CXXMethodDecl* trace_;
645 RecordInfo* info_; 686 RecordInfo* info_;
687 RecordCache* cache_;
646 bool delegates_to_traceimpl_; 688 bool delegates_to_traceimpl_;
647 }; 689 };
648 690
649 // This visitor checks that the fields of a class and the fields of 691 // This visitor checks that the fields of a class and the fields of
650 // its part objects don't define GC roots. 692 // its part objects don't define GC roots.
651 class CheckGCRootsVisitor : public RecursiveEdgeVisitor { 693 class CheckGCRootsVisitor : public RecursiveEdgeVisitor {
652 public: 694 public:
653 typedef std::vector<FieldPoint*> RootPath; 695 typedef std::vector<FieldPoint*> RootPath;
654 typedef std::set<RecordInfo*> VisitingSet; 696 typedef std::set<RecordInfo*> VisitingSet;
655 typedef std::vector<RootPath> Errors; 697 typedef std::vector<RootPath> Errors;
(...skipping 724 matching lines...) Expand 10 before | Expand all | Expand 10 after
1380 if (trace_type == Config::TRACE_METHOD) { 1422 if (trace_type == Config::TRACE_METHOD) {
1381 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); 1423 for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
1382 it != parent->GetBases().end(); 1424 it != parent->GetBases().end();
1383 ++it) { 1425 ++it) {
1384 RecordInfo* base = it->second.info(); 1426 RecordInfo* base = it->second.info();
1385 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace()) 1427 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace())
1386 ReportOverriddenNonVirtualTrace(parent, trace, other); 1428 ReportOverriddenNonVirtualTrace(parent, trace, other);
1387 } 1429 }
1388 } 1430 }
1389 1431
1390 CheckTraceVisitor visitor(trace, parent); 1432 CheckTraceVisitor visitor(trace, parent, &cache_);
1391 visitor.TraverseCXXMethodDecl(trace); 1433 visitor.TraverseCXXMethodDecl(trace);
1392 1434
1393 // Skip reporting if this trace method is a just delegate to 1435 // Skip reporting if this trace method is a just delegate to
1394 // traceImpl (or traceAfterDispatchImpl) method. We will report on 1436 // traceImpl (or traceAfterDispatchImpl) method. We will report on
1395 // CheckTraceMethod on traceImpl method. 1437 // CheckTraceMethod on traceImpl method.
1396 if (visitor.delegates_to_traceimpl()) 1438 if (visitor.delegates_to_traceimpl())
1397 return; 1439 return;
1398 1440
1399 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); 1441 for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
1400 it != parent->GetBases().end(); 1442 it != parent->GetBases().end();
(...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after
1990 2032
1991 private: 2033 private:
1992 BlinkGCPluginOptions options_; 2034 BlinkGCPluginOptions options_;
1993 }; 2035 };
1994 2036
1995 } // namespace 2037 } // namespace
1996 2038
1997 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( 2039 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X(
1998 "blink-gc-plugin", 2040 "blink-gc-plugin",
1999 "Check Blink GC invariants"); 2041 "Check Blink GC invariants");
OLDNEW
« no previous file with comments | « no previous file | tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698