Index: tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
index a6f32c73ce70b63548dc379ede77c72218e41830..f8a7a84d801d248cf0f377b1a1fe297c77b3b401 100644 |
--- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
+++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
@@ -59,6 +59,9 @@ const char kClassDoesNotRequireFinalization[] = |
const char kFinalizerAccessesFinalizedField[] = |
"[blink-gc] Finalizer %0 accesses potentially finalized field %1."; |
+const char kFinalizerAccessesEagerlyFinalizedField[] = |
+ "[blink-gc] Finalizer %0 accesses eagerly finalized field %1."; |
+ |
const char kRawPtrToGCManagedClassNote[] = |
"[blink-gc] Raw pointer field %0 to a GC managed class declared here:"; |
@@ -108,6 +111,9 @@ const char kMissingFinalizeDispatch[] = |
const char kFinalizedFieldNote[] = |
"[blink-gc] Potentially finalized field %0 declared here:"; |
+const char kEagerlyFinalizedFieldNote[] = |
+ "[blink-gc] Field %0 having eagerly finalized value, declared here:"; |
+ |
const char kUserDeclaredDestructorNote[] = |
"[blink-gc] User-declared destructor declared here:"; |
@@ -243,11 +249,27 @@ class CheckFinalizerVisitor |
// during finalization. |
class MightBeCollectedVisitor : public EdgeVisitor { |
public: |
- MightBeCollectedVisitor() : might_be_collected_(false) {} |
+ MightBeCollectedVisitor(bool is_eagerly_finalized) |
+ : might_be_collected_(false) |
+ , is_eagerly_finalized_(is_eagerly_finalized) |
+ , as_eagerly_finalized_(false) {} |
bool might_be_collected() { return might_be_collected_; } |
- void VisitMember(Member* edge) override { might_be_collected_ = true; } |
+ bool as_eagerly_finalized() { return as_eagerly_finalized_; } |
+ void VisitMember(Member* edge) override { |
+ 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 VisitCollection(Collection* edge) override { |
- if (edge->on_heap()) { |
+ if (edge->on_heap() && !is_eagerly_finalized_) { |
might_be_collected_ = !edge->is_root(); |
} else { |
edge->AcceptMembers(this); |
@@ -256,13 +278,31 @@ class CheckFinalizerVisitor |
private: |
bool might_be_collected_; |
+ bool is_eagerly_finalized_; |
+ bool as_eagerly_finalized_; |
}; |
public: |
- typedef std::vector<std::pair<MemberExpr*, FieldPoint*> > Errors; |
+ class Error { |
+ public: |
+ Error(MemberExpr *member, |
+ bool as_eagerly_finalized, |
+ FieldPoint* field) |
+ : member_(member) |
+ , as_eagerly_finalized_(as_eagerly_finalized) |
+ , field_(field) {} |
- CheckFinalizerVisitor(RecordCache* cache) |
- : blacklist_context_(false), cache_(cache) {} |
+ MemberExpr* member_; |
+ bool as_eagerly_finalized_; |
+ FieldPoint* field_; |
+ }; |
+ |
+ typedef std::vector<Error> Errors; |
+ |
+ CheckFinalizerVisitor(RecordCache* cache, bool is_eagerly_finalized) |
+ : blacklist_context_(false) |
+ , cache_(cache) |
+ , is_eagerly_finalized_(is_eagerly_finalized) {} |
Errors& finalized_fields() { return finalized_fields_; } |
@@ -300,21 +340,32 @@ class CheckFinalizerVisitor |
if (it == info->GetFields().end()) |
return true; |
- if (blacklist_context_ && MightBeCollected(&it->second)) |
- finalized_fields_.push_back(std::make_pair(member, &it->second)); |
+ 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 MightBeCollected(FieldPoint* point) { |
- MightBeCollectedVisitor visitor; |
+ bool 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(); |
} |
private: |
bool blacklist_context_; |
Errors finalized_fields_; |
+ std::set<MemberExpr*> seen_members_; |
RecordCache* cache_; |
+ bool is_eagerly_finalized_; |
}; |
// This visitor checks that a method contains within its body, a call to a |
@@ -969,6 +1020,8 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
DiagnosticsEngine::Warning, kClassDoesNotRequireFinalization); |
diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID( |
getErrorLevel(), kFinalizerAccessesFinalizedField); |
+ diag_finalizer_eagerly_finalized_field_ = diagnostic_.getCustomDiagID( |
+ getErrorLevel(), kFinalizerAccessesEagerlyFinalizedField); |
diag_overridden_non_virtual_trace_ = diagnostic_.getCustomDiagID( |
getErrorLevel(), kOverriddenNonVirtualTrace); |
diag_missing_trace_dispatch_method_ = diagnostic_.getCustomDiagID( |
@@ -1018,6 +1071,8 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
DiagnosticsEngine::Note, kFieldContainsGCRootNote); |
diag_finalized_field_note_ = diagnostic_.getCustomDiagID( |
DiagnosticsEngine::Note, kFinalizedFieldNote); |
+ diag_eagerly_finalized_field_note_ = diagnostic_.getCustomDiagID( |
+ DiagnosticsEngine::Note, kEagerlyFinalizedFieldNote); |
diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID( |
DiagnosticsEngine::Note, kUserDeclaredDestructorNote); |
diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID( |
@@ -1387,7 +1442,7 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
// For finalized classes, check the finalization method if possible. |
if (info->IsGCFinalized()) { |
if (dtor && dtor->hasBody()) { |
- CheckFinalizerVisitor visitor(&cache_); |
+ CheckFinalizerVisitor visitor(&cache_, info->IsEagerlyFinalized()); |
visitor.TraverseCXXMethodDecl(dtor); |
if (!visitor.finalized_fields().empty()) { |
ReportFinalizerAccessesFinalizedFields( |
@@ -1816,12 +1871,19 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
for (CheckFinalizerVisitor::Errors::iterator it = fields->begin(); |
it != fields->end(); |
++it) { |
- SourceLocation loc = it->first->getLocStart(); |
+ SourceLocation loc = it->member_->getLocStart(); |
SourceManager& manager = instance_.getSourceManager(); |
+ bool as_eagerly_finalized = it->as_eagerly_finalized_; |
+ unsigned diag_error = as_eagerly_finalized ? |
+ diag_finalizer_eagerly_finalized_field_ : |
+ diag_finalizer_accesses_finalized_field_; |
+ unsigned diag_note = as_eagerly_finalized ? |
+ diag_eagerly_finalized_field_note_ : |
+ diag_finalized_field_note_; |
FullSourceLoc full_loc(loc, manager); |
- diagnostic_.Report(full_loc, diag_finalizer_accesses_finalized_field_) |
- << dtor << it->second->field(); |
- NoteField(it->second, diag_finalized_field_note_); |
+ diagnostic_.Report(full_loc, diag_error) |
+ << dtor << it->field_->field(); |
+ NoteField(it->field_, diag_note); |
} |
} |
@@ -2030,6 +2092,7 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
unsigned diag_class_requires_finalization_; |
unsigned diag_class_does_not_require_finalization_; |
unsigned diag_finalizer_accesses_finalized_field_; |
+ unsigned diag_finalizer_eagerly_finalized_field_; |
unsigned diag_overridden_non_virtual_trace_; |
unsigned diag_missing_trace_dispatch_method_; |
unsigned diag_missing_finalize_dispatch_method_; |
@@ -2045,6 +2108,7 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
unsigned diag_base_requires_tracing_note_; |
unsigned diag_field_requires_tracing_note_; |
+ unsigned diag_field_illegally_traced_note_; |
unsigned diag_raw_ptr_to_gc_managed_class_note_; |
unsigned diag_ref_ptr_to_gc_managed_class_note_; |
unsigned diag_own_ptr_to_gc_managed_class_note_; |
@@ -2054,6 +2118,7 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
unsigned diag_part_object_contains_gc_root_note_; |
unsigned diag_field_contains_gc_root_note_; |
unsigned diag_finalized_field_note_; |
+ unsigned diag_eagerly_finalized_field_note_; |
unsigned diag_user_declared_destructor_note_; |
unsigned diag_user_declared_finalizer_note_; |
unsigned diag_base_requires_finalization_note_; |