// TODO: Add classes with a finalize() method that specialize FinalizerTrait. bool RecordInfo::NeedsFinalization() { if (does_need_finalization_ == kNotComputed) { // Rely on hasNonTrivialDestructor(), but if the only // identifiable reason for it being true is the presence // of a safely ignorable class as a direct base, // or we're processing such an 'ignorable' class, then it does // not need finalization. does_need_finalization_ = record_->hasNonTrivialDestructor() ? kTrue : kFalse; if (!does_need_finalization_) return does_need_finalization_; CXXDestructorDecl* dtor = record_->getDestructor(); if (dtor && dtor->isUserProvided()) return does_need_finalization_; for (Fields::iterator it = GetFields().begin(); it != GetFields().end(); ++it) { if (it->second.edge()->NeedsFinalization()) return does_need_finalization_; } for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { if (it->second.info()->NeedsFinalization()) return does_need_finalization_; } // Destructor was non-trivial due to bases with destructors that // can be safely ignored. Hence, no need for finalization. does_need_finalization_ = kFalse; } return does_need_finalization_; }
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_); } }