OLD | NEW |
(Empty) | |
| 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 } |
OLD | NEW |