bool BlinkGCPluginConsumer::HasNonEmptyFinalizer(RecordInfo* info) { CXXDestructorDecl* dtor = info->record()->getDestructor(); if (dtor && dtor->isUserProvided()) { if (!dtor->hasBody() || !EmptyStmtVisitor::isEmpty(dtor->getBody())) return true; } for (RecordInfo::Bases::iterator it = info->GetBases().begin(); it != info->GetBases().end(); ++it) { if (HasNonEmptyFinalizer(it->second.info())) return true; } for (RecordInfo::Fields::iterator it = info->GetFields().begin(); it != info->GetFields().end(); ++it) { if (it->second.edge()->NeedsFinalization()) return true; } return false; }
// TODO: Should we collect destructors similar to trace methods? void BlinkGCPluginConsumer::CheckFinalization(RecordInfo* info) { CXXDestructorDecl* dtor = info->record()->getDestructor(); // For finalized classes, check the finalization method if possible. if (info->IsGCFinalized()) { if (dtor && dtor->hasBody()) { CheckFinalizerVisitor visitor(&cache_, info->IsEagerlyFinalized()); 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->IsGCMixin()) 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_); } }