1 // Copyright 2015 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "CheckFinalizerVisitor.h" 6 7 using namespace clang; 8 9 namespace { 10 11 // Simple visitor to determine if the content of a field might be collected 12 // during finalization. 13 class MightBeCollectedVisitor : public EdgeVisitor { 14 public: 15 bool might_be_collected() const; 16 17 void VisitMember(Member* edge) override; 18 void VisitCollection(Collection* edge) override; 19 20 private: 21 bool might_be_collected_ = false; 22 }; 23 might_be_collected() const24bool MightBeCollectedVisitor::might_be_collected() const { 25 return might_be_collected_; 26 } 27 VisitMember(Member * edge)28void MightBeCollectedVisitor::VisitMember(Member* edge) { 29 might_be_collected_ = true; 30 } 31 VisitCollection(Collection * edge)32void MightBeCollectedVisitor::VisitCollection(Collection* edge) { 33 if (edge->on_heap()) { 34 might_be_collected_ = true; 35 } else { 36 edge->AcceptMembers(this); 37 } 38 } 39 40 } // namespace 41 CheckFinalizerVisitor(RecordCache * cache)42CheckFinalizerVisitor::CheckFinalizerVisitor(RecordCache* cache) 43 : blacklist_context_(false), 44 cache_(cache) { 45 } 46 finalized_fields()47CheckFinalizerVisitor::Errors& CheckFinalizerVisitor::finalized_fields() { 48 return finalized_fields_; 49 } 50 WalkUpFromCXXOperatorCallExpr(CXXOperatorCallExpr * expr)51bool CheckFinalizerVisitor::WalkUpFromCXXOperatorCallExpr( 52 CXXOperatorCallExpr* expr) { 53 // Only continue the walk-up if the operator is a blacklisted one. 54 switch (expr->getOperator()) { 55 case OO_Arrow: 56 case OO_Subscript: 57 this->WalkUpFromCallExpr(expr); 58 return true; 59 default: 60 return true; 61 } 62 } 63 WalkUpFromCallExpr(CallExpr * expr)64bool CheckFinalizerVisitor::WalkUpFromCallExpr(CallExpr* expr) { 65 // We consider all non-operator calls to be blacklisted contexts. 66 bool prev_blacklist_context = blacklist_context_; 67 blacklist_context_ = true; 68 for (size_t i = 0; i < expr->getNumArgs(); ++i) 69 this->TraverseStmt(expr->getArg(i)); 70 blacklist_context_ = prev_blacklist_context; 71 return true; 72 } 73 VisitMemberExpr(MemberExpr * member)74bool CheckFinalizerVisitor::VisitMemberExpr(MemberExpr* member) { 75 FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl()); 76 if (!field) 77 return true; 78 79 RecordInfo* info = cache_->Lookup(field->getParent()); 80 if (!info) 81 return true; 82 83 RecordInfo::Fields::iterator it = info->GetFields().find(field); 84 if (it == info->GetFields().end()) 85 return true; 86 87 if (seen_members_.find(member) != seen_members_.end()) 88 return true; 89 90 if (blacklist_context_ && 91 MightBeCollected(&it->second)) { 92 finalized_fields_.push_back( 93 Error(member, &it->second)); 94 seen_members_.insert(member); 95 } 96 return true; 97 } 98 MightBeCollected(FieldPoint * point)99bool CheckFinalizerVisitor::MightBeCollected(FieldPoint* point) { 100 MightBeCollectedVisitor visitor; 101 point->edge()->Accept(&visitor); 102 return visitor.might_be_collected(); 103 } 104