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