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 explicit MightBeCollectedVisitor(bool is_eagerly_finalized); 16 17 bool might_be_collected() const; 18 bool as_eagerly_finalized() const; 19 20 void VisitMember(Member* edge) override; 21 void VisitCollection(Collection* edge) override; 22 23 private: 24 bool might_be_collected_; 25 bool is_eagerly_finalized_; 26 bool as_eagerly_finalized_; 27 }; 28 29 MightBeCollectedVisitor::MightBeCollectedVisitor(bool is_eagerly_finalized) 30 : might_be_collected_(false), 31 is_eagerly_finalized_(is_eagerly_finalized), 32 as_eagerly_finalized_(false) { 33 } 34 35 bool MightBeCollectedVisitor::might_be_collected() const { 36 return might_be_collected_; 37 } 38 39 bool MightBeCollectedVisitor::as_eagerly_finalized() const { 40 return as_eagerly_finalized_; 41 } 42 43 void MightBeCollectedVisitor::VisitMember(Member* edge) { 44 if (is_eagerly_finalized_) { 45 if (edge->ptr()->IsValue()) { 46 Value* member = static_cast<Value*>(edge->ptr()); 47 if (member->value()->IsEagerlyFinalized()) { 48 might_be_collected_ = true; 49 as_eagerly_finalized_ = true; 50 } 51 } 52 return; 53 } 54 might_be_collected_ = true; 55 } 56 57 void MightBeCollectedVisitor::VisitCollection(Collection* edge) { 58 if (edge->on_heap() && !is_eagerly_finalized_) { 59 might_be_collected_ = !edge->is_root(); 60 } else { 61 edge->AcceptMembers(this); 62 } 63 } 64 65 } // namespace 66 67 CheckFinalizerVisitor::CheckFinalizerVisitor(RecordCache* cache, 68 bool is_eagerly_finalized) 69 : blacklist_context_(false), 70 cache_(cache), 71 is_eagerly_finalized_(is_eagerly_finalized) { 72 } 73 74 CheckFinalizerVisitor::Errors& CheckFinalizerVisitor::finalized_fields() { 75 return finalized_fields_; 76 } 77 78 bool CheckFinalizerVisitor::WalkUpFromCXXOperatorCallExpr( 79 CXXOperatorCallExpr* expr) { 80 // Only continue the walk-up if the operator is a blacklisted one. 81 switch (expr->getOperator()) { 82 case OO_Arrow: 83 case OO_Subscript: 84 this->WalkUpFromCallExpr(expr); 85 return true; 86 default: 87 return true; 88 } 89 } 90 91 bool CheckFinalizerVisitor::WalkUpFromCallExpr(CallExpr* expr) { 92 // We consider all non-operator calls to be blacklisted contexts. 93 bool prev_blacklist_context = blacklist_context_; 94 blacklist_context_ = true; 95 for (size_t i = 0; i < expr->getNumArgs(); ++i) 96 this->TraverseStmt(expr->getArg(i)); 97 blacklist_context_ = prev_blacklist_context; 98 return true; 99 } 100 101 bool CheckFinalizerVisitor::VisitMemberExpr(MemberExpr* member) { 102 FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl()); 103 if (!field) 104 return true; 105 106 RecordInfo* info = cache_->Lookup(field->getParent()); 107 if (!info) 108 return true; 109 110 RecordInfo::Fields::iterator it = info->GetFields().find(field); 111 if (it == info->GetFields().end()) 112 return true; 113 114 if (seen_members_.find(member) != seen_members_.end()) 115 return true; 116 117 bool as_eagerly_finalized = false; 118 if (blacklist_context_ && 119 MightBeCollected(&it->second, &as_eagerly_finalized)) { 120 finalized_fields_.push_back( 121 Error(member, as_eagerly_finalized, &it->second)); 122 seen_members_.insert(member); 123 } 124 return true; 125 } 126 127 bool CheckFinalizerVisitor::MightBeCollected(FieldPoint* point, 128 bool* as_eagerly_finalized) { 129 MightBeCollectedVisitor visitor(is_eagerly_finalized_); 130 point->edge()->Accept(&visitor); 131 *as_eagerly_finalized = visitor.as_eagerly_finalized(); 132 return visitor.might_be_collected(); 133 } 134