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

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: 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 (RecordInfo::Bases::iterator iter = info_->GetBases().begin();
545 if (iter == info_->GetBases().end()) 549 iter != info_->GetBases().end(); ++iter) {
kouhei (in TOK) 2015/03/02 04:24:13 Nit: use foreach?
Yuta Kitamura 2015/03/02 07:36:49 Done.
546 return false; 550 // We want to deal with omitted trace() function in an intermediary
551 // class in the class hierarchy, e.g.:
552 // class A : public GarbageCollected<A> { trace() { ... } };
553 // class B : public A { /* No trace(); have nothing to trace. */ };
554 // class C : public B { trace() { B::trace(visitor); } }
555 // where, B::trace() is actually A::trace(), and in some cases we get
556 // A as |callee_record| instead of B. We somehow need to mark B as
557 // traced if we find A::trace() call.
558 //
559 // To solve this, here we keep going up the class hierarchy as long as
560 // they are not required to have a trace method. The implementation is
561 // a simple DFS, where |base_records| represents the set of base classes
562 // we need to visit.
547 563
548 iter->second.MarkTraced(); 564 std::vector<CXXRecordDecl*> base_records;
549 return true; 565 base_records.push_back(iter->first);
566
567 while (!base_records.empty()) {
568 CXXRecordDecl* base_record = base_records.back();
569 base_records.pop_back();
570
571 if (base_record == callee_record) {
572 // If we find a matching trace method, pretend the user has written
573 // a correct trace() method of the base; in the example above, we
574 // find A::trace() here and mark B as correctly traced.
575 iter->second.MarkTraced();
576 return true;
577 }
578
579 if (RecordInfo* base_info = cache_->Lookup(base_record)) {
580 if (!base_info->RequiresTraceMethod()) {
581 // If this base class is not required to have a trace method, then
582 // the actual trace method may be defined in an ancestor.
583 for (RecordInfo::Bases::iterator inner_iter =
584 base_info->GetBases().begin();
585 inner_iter != base_info->GetBases().end(); ++inner_iter) {
586 base_records.push_back(inner_iter->first);
587 }
588 }
589 }
590 }
591 }
592
593 return false;
550 } 594 }
551 595
552 bool CheckTraceFieldCall(CXXMemberCallExpr* call) { 596 bool CheckTraceFieldCall(CXXMemberCallExpr* call) {
553 return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(), 597 return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(),
554 call->getRecordDecl(), 598 call->getRecordDecl(),
555 call->getArg(0)); 599 call->getArg(0));
556 } 600 }
557 601
558 bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) { 602 bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) {
559 if (name != kTraceName || !Config::IsVisitor(callee->getName())) 603 if (name != kTraceName || !Config::IsVisitor(callee->getName()))
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
602 return false; 646 return false;
603 } 647 }
604 return true; 648 return true;
605 } 649 }
606 private: 650 private:
607 MemberExpr* member_; 651 MemberExpr* member_;
608 FieldDecl* field_; 652 FieldDecl* field_;
609 }; 653 };
610 654
611 // Nested checking for weak callbacks. 655 // Nested checking for weak callbacks.
612 CheckTraceVisitor(RecordInfo* info) : trace_(0), info_(info) {} 656 CheckTraceVisitor(RecordInfo* info)
657 : trace_(nullptr), info_(info), cache_(nullptr) {}
613 658
614 bool IsWeakCallback() { return !trace_; } 659 bool IsWeakCallback() { return !trace_; }
615 660
616 void MarkTraced(RecordInfo::Fields::iterator it) { 661 void MarkTraced(RecordInfo::Fields::iterator it) {
617 // In a weak callback we can't mark strong fields as traced. 662 // In a weak callback we can't mark strong fields as traced.
618 if (IsWeakCallback() && !it->second.edge()->IsWeakMember()) 663 if (IsWeakCallback() && !it->second.edge()->IsWeakMember())
619 return; 664 return;
620 it->second.MarkTraced(); 665 it->second.MarkTraced();
621 } 666 }
622 667
(...skipping 13 matching lines...) Expand all
636 } 681 }
637 } else { 682 } else {
638 RecordInfo::Fields::iterator it = info_->GetFields().find(field); 683 RecordInfo::Fields::iterator it = info_->GetFields().find(field);
639 if (it != info_->GetFields().end()) 684 if (it != info_->GetFields().end())
640 MarkTraced(it); 685 MarkTraced(it);
641 } 686 }
642 } 687 }
643 688
644 CXXMethodDecl* trace_; 689 CXXMethodDecl* trace_;
645 RecordInfo* info_; 690 RecordInfo* info_;
691 RecordCache* cache_;
646 bool delegates_to_traceimpl_; 692 bool delegates_to_traceimpl_;
647 }; 693 };
648 694
649 // This visitor checks that the fields of a class and the fields of 695 // This visitor checks that the fields of a class and the fields of
650 // its part objects don't define GC roots. 696 // its part objects don't define GC roots.
651 class CheckGCRootsVisitor : public RecursiveEdgeVisitor { 697 class CheckGCRootsVisitor : public RecursiveEdgeVisitor {
652 public: 698 public:
653 typedef std::vector<FieldPoint*> RootPath; 699 typedef std::vector<FieldPoint*> RootPath;
654 typedef std::set<RecordInfo*> VisitingSet; 700 typedef std::set<RecordInfo*> VisitingSet;
655 typedef std::vector<RootPath> Errors; 701 typedef std::vector<RootPath> Errors;
(...skipping 724 matching lines...) Expand 10 before | Expand all | Expand 10 after
1380 if (trace_type == Config::TRACE_METHOD) { 1426 if (trace_type == Config::TRACE_METHOD) {
1381 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); 1427 for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
1382 it != parent->GetBases().end(); 1428 it != parent->GetBases().end();
1383 ++it) { 1429 ++it) {
1384 RecordInfo* base = it->second.info(); 1430 RecordInfo* base = it->second.info();
1385 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace()) 1431 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace())
1386 ReportOverriddenNonVirtualTrace(parent, trace, other); 1432 ReportOverriddenNonVirtualTrace(parent, trace, other);
1387 } 1433 }
1388 } 1434 }
1389 1435
1390 CheckTraceVisitor visitor(trace, parent); 1436 CheckTraceVisitor visitor(trace, parent, &cache_);
1391 visitor.TraverseCXXMethodDecl(trace); 1437 visitor.TraverseCXXMethodDecl(trace);
1392 1438
1393 // Skip reporting if this trace method is a just delegate to 1439 // Skip reporting if this trace method is a just delegate to
1394 // traceImpl (or traceAfterDispatchImpl) method. We will report on 1440 // traceImpl (or traceAfterDispatchImpl) method. We will report on
1395 // CheckTraceMethod on traceImpl method. 1441 // CheckTraceMethod on traceImpl method.
1396 if (visitor.delegates_to_traceimpl()) 1442 if (visitor.delegates_to_traceimpl())
1397 return; 1443 return;
1398 1444
1399 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); 1445 for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
1400 it != parent->GetBases().end(); 1446 it != parent->GetBases().end();
(...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after
1990 2036
1991 private: 2037 private:
1992 BlinkGCPluginOptions options_; 2038 BlinkGCPluginOptions options_;
1993 }; 2039 };
1994 2040
1995 } // namespace 2041 } // namespace
1996 2042
1997 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( 2043 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X(
1998 "blink-gc-plugin", 2044 "blink-gc-plugin",
1999 "Check Blink GC invariants"); 2045 "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