Chromium Code Reviews| 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 15ce1aececc493172495d642a7fffe87651f4857..2ff89cebe96f77cc18d09caf8269b605e5d659b3 100644 |
| --- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
| +++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
| @@ -41,8 +41,8 @@ const char kClassContainsInvalidFields[] = |
| const char kClassContainsGCRoot[] = |
| "[blink-gc] Class %0 contains GC root in field %1."; |
| -const char kFinalizerInNonFinalizedClass[] = |
| - "[blink-gc] Non-finalized class %0 has a user-declared finalizer %1."; |
| +const char kClassRequiresFinalization[] = |
| + "[blink-gc] Non-finalized class %0 requires finalization."; |
|
Vyacheslav Egorov (Chromium)
2014/03/12 18:24:24
I would remove "Non-finalized" it is confusing.
zerny-chromium
2014/03/13 09:32:22
Removed the "non-finalized" part. I've not added t
|
| const char kFinalizerAccessesFinalizedField[] = |
| "[blink-gc] Finalizer %0 accesses potentially finalized field %1."; |
| @@ -65,6 +65,15 @@ const char kFieldContainsGCRoot[] = |
| const char kFinalizedFieldNote[] = |
| "[blink-gc] Potentially finalized field %0 declared here:"; |
| +const char kUserDeclaredDestructorNote[] = |
| + "[blink-gc] User-declared destructor declared here:"; |
| + |
| +const char kBaseRequiresFinalizationNote[] = |
| + "[blink-gc] Base class %0 requiring finalization declared here:"; |
| + |
| +const char kFieldRequiresFinalizationNote[] = |
| + "[blink-gc] Field %0 requiring finalization declared here:"; |
| + |
| struct BlinkGCPluginOptions { |
| BlinkGCPluginOptions() : enable_oilpan(false) {} |
| bool enable_oilpan; |
| @@ -409,8 +418,8 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
| kClassContainsInvalidFields); |
| diag_class_contains_gc_root_ = |
| diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRoot); |
| - diag_finalizer_in_nonfinalized_class_ = diagnostic_.getCustomDiagID( |
| - getErrorLevel(), kFinalizerInNonFinalizedClass); |
| + diag_class_requires_finalization_ = diagnostic_.getCustomDiagID( |
| + getErrorLevel(), kClassRequiresFinalization); |
| diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID( |
| getErrorLevel(), kFinalizerAccessesFinalizedField); |
| @@ -429,6 +438,12 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
| DiagnosticsEngine::Note, kFieldContainsGCRoot); |
| diag_finalized_field_note_ = diagnostic_.getCustomDiagID( |
| DiagnosticsEngine::Note, kFinalizedFieldNote); |
| + diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID( |
| + DiagnosticsEngine::Note, kUserDeclaredDestructorNote); |
| + diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID( |
| + DiagnosticsEngine::Note, kBaseRequiresFinalizationNote); |
| + diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID( |
| + DiagnosticsEngine::Note, kFieldRequiresFinalizationNote); |
| } |
| virtual void HandleTranslationUnit(ASTContext& context) { |
| @@ -490,37 +505,56 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
| } |
| if (info->IsGCDerived()) { |
| - { |
| - CheckGCRootsVisitor visitor; |
| - if (visitor.ContainsGCRoots(info)) |
| - ReportClassContainsGCRoots(info, &visitor.gc_roots()); |
| - } |
| + CheckGCRootsVisitor visitor; |
| + if (visitor.ContainsGCRoots(info)) |
| + ReportClassContainsGCRoots(info, &visitor.gc_roots()); |
| - // TODO: check for non-user defined and non-trivial destructors too. |
| - // TODO: support overridden finalize(). |
| - if (CXXDestructorDecl* dtor = info->record()->getDestructor()) { |
| - if (dtor->isUserProvided() && !info->IsGCFinalized()) { |
| - // Don't report if using transition types and the body is empty. |
| - if (!options_.enable_oilpan) { |
| - ReportFinalizerInNonFinalizedClass(info, dtor); |
| - } else { |
| - if (dtor->hasBody()) { |
| - CompoundStmt* stmt = cast<CompoundStmt>(dtor->getBody()); |
| - if (stmt && !stmt->body_empty()) |
| - ReportFinalizerInNonFinalizedClass(info, dtor); |
| - } |
| - } |
| - } |
| + if (info->NeedsFinalization()) |
| + CheckFinalization(info); |
| + } |
| + } |
| - if (dtor->hasBody()) { |
| - CheckFinalizerVisitor visitor(&cache_); |
| - visitor.TraverseCXXMethodDecl(dtor); |
| - if (!visitor.finalized_fields().empty()) { |
| - ReportFinalizerAccessesFinalizedFields(dtor, |
| - &visitor.finalized_fields()); |
| - } |
| + void CheckFinalization(RecordInfo* info) { |
| + // TODO: Should we collect destructors similar to trace methods? |
| + // TODO: Check overridden finalize(). |
| + CXXDestructorDecl* dtor = info->record()->getDestructor(); |
| + |
| + // For finalized classes, check the finalization method if possible. |
| + if (info->IsGCFinalized()) { |
| + if (dtor && dtor->hasBody()) { |
| + CheckFinalizerVisitor visitor(&cache_); |
| + visitor.TraverseCXXMethodDecl(dtor); |
| + if (!visitor.finalized_fields().empty()) { |
| + ReportFinalizerAccessesFinalizedFields( |
| + dtor, &visitor.finalized_fields()); |
| } |
| } |
| + return; |
| + } |
| + |
| + // Don't require finalization of a mixin that has not yet been "mixed in". |
| + if (info->IsUnmixedGCMixin()) |
| + return; |
| + |
| + // Report the finalization error, and proceed to print possible causes for |
| + // the finalization requirement. |
| + ReportClassRequiresFinalization(info); |
| + |
| + if (dtor && dtor->isUserProvided()) |
| + NoteUserDeclaredDestructor(dtor); |
| + |
| + for (RecordInfo::Bases::iterator it = info->GetBases().begin(); |
| + it != info->GetBases().end(); |
| + ++it) { |
| + if (it->second.info()->NeedsFinalization()) |
| + NoteBaseRequiresFinalization(&it->second); |
| + } |
| + |
| + for (RecordInfo::Fields::iterator it = info->GetFields().begin(); |
| + it != info->GetFields().end(); |
| + ++it) { |
| + if (it->second.edge()->NeedsFinalization()) |
| + NoteField(&it->second, diag_field_requires_finalization_note_); |
| } |
| } |
| @@ -725,15 +759,6 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
| } |
| } |
| - void ReportFinalizerInNonFinalizedClass(RecordInfo* info, |
| - CXXMethodDecl* dtor) { |
| - SourceLocation loc = dtor->getLocStart(); |
| - SourceManager& manager = instance_.getSourceManager(); |
| - FullSourceLoc full_loc(loc, manager); |
| - diagnostic_.Report(full_loc, diag_finalizer_in_nonfinalized_class_) |
| - << info->record() << dtor; |
| - } |
| - |
| void ReportFinalizerAccessesFinalizedFields( |
| CXXMethodDecl* dtor, |
| CheckFinalizerVisitor::Errors* fields) { |
| @@ -749,6 +774,14 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
| } |
| } |
| + void ReportClassRequiresFinalization(RecordInfo* info) { |
| + SourceLocation loc = info->record()->getInnerLocStart(); |
| + SourceManager& manager = instance_.getSourceManager(); |
| + FullSourceLoc full_loc(loc, manager); |
| + diagnostic_.Report(full_loc, diag_class_requires_finalization_) |
| + << info->record(); |
| + } |
| + |
| void NoteFieldRequiresTracing(RecordInfo* holder, FieldDecl* field) { |
| NoteField(field, diag_field_requires_tracing_note_); |
| } |
| @@ -766,6 +799,21 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
| NoteField(point, diag_field_contains_gc_root_note_); |
| } |
| + void NoteUserDeclaredDestructor(CXXMethodDecl* dtor) { |
| + SourceLocation loc = dtor->getLocStart(); |
| + SourceManager& manager = instance_.getSourceManager(); |
| + FullSourceLoc full_loc(loc, manager); |
| + diagnostic_.Report(full_loc, diag_user_declared_destructor_note_); |
| + } |
| + |
| + void NoteBaseRequiresFinalization(BasePoint* base) { |
| + SourceLocation loc = base->spec().getLocStart(); |
| + SourceManager& manager = instance_.getSourceManager(); |
| + FullSourceLoc full_loc(loc, manager); |
| + diagnostic_.Report(full_loc, diag_base_requires_finalization_note_) |
| + << base->info()->record(); |
| + } |
| + |
| void NoteField(FieldPoint* point, unsigned note) { |
| NoteField(point->field(), note); |
| } |
| @@ -782,7 +830,7 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
| unsigned diag_fields_require_tracing_; |
| unsigned diag_class_contains_invalid_fields_; |
| unsigned diag_class_contains_gc_root_; |
| - unsigned diag_finalizer_in_nonfinalized_class_; |
| + unsigned diag_class_requires_finalization_; |
| unsigned diag_finalizer_accesses_finalized_field_; |
| unsigned diag_field_requires_tracing_note_; |
| @@ -792,6 +840,9 @@ 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_user_declared_destructor_note_; |
| + unsigned diag_base_requires_finalization_note_; |
| + unsigned diag_field_requires_finalization_note_; |
| CompilerInstance& instance_; |
| DiagnosticsEngine& diagnostic_; |