12 #ifndef ROOT_TCheckHashRecursiveRemoveConsistency
13 #define ROOT_TCheckHashRecursiveRemoveConsistency
39 class TCheckHashRecursiveRemoveConsistency :
public TObject {
42 ULong_t fRecordedHash;
45 using Value_t = Value;
47 std::list<Value> fCont;
53 TCheckHashRecursiveRemoveConsistency()
56 gROOT->GetListOfCleanups()->Add(
this);
63 ~TCheckHashRecursiveRemoveConsistency()
67 if (!gROOT->MustClean())
68 gROOT->GetListOfCleanups()->Remove(
this);
71 void Add(TObject *obj)
73 obj->SetBit(kMustCleanup);
74 auto hashValue = obj->Hash();
76 std::unique_lock<std::mutex> lock(fMutex);
77 fCont.push_back(Value_t{hashValue, obj});
80 void RecursiveRemove(TObject *obj)
87 std::unique_lock<std::mutex> lock(fMutex);
90 for (
auto p = fCont.begin(); p != fCont.end(); ++p) {
91 if (p->fObjectPtr == obj) {
94 if (p->fRecordedHash == obj->Hash())
103 void SlowRemove(TObject *obj)
105 std::unique_lock<std::mutex> lock(fMutex);
107 for (
auto p = fCont.begin(); p != fCont.end(); ++p) {
108 if (p->fObjectPtr == obj) {
121 EResult CheckRecursiveRemove(TClass &classRef)
123 if (!classRef.HasDefaultConstructor() || classRef.Property() & kIsAbstract)
124 return kInconclusive;
126 auto size = fCont.size();
127 TObject *obj = (TObject *)classRef.DynamicCast(TObject::Class(), classRef.New(TClass::kDummyNew));
128 if (!obj || (!gROOT->MustClean() && obj->TestBit(kIsReferenced) && obj->GetUniqueID() != 0)) {
131 return kInconclusive;
133 ROOT::Internal::SetRequireCleanup(*obj);
137 if (fCont.size() != size) {
143 return kInconsistent;
149 TClass *FindMissingRecursiveRemove(TClass &classRef)
152 if (classRef.HasLocalHashMember() && CheckRecursiveRemove(classRef) != kConsistent) {
156 for (
auto base : ROOT::Detail::TRangeStaticCast<TBaseClass>(classRef.GetListOfBases())) {
157 TClass *baseCl = base->GetClassPointer();
158 TClass *res = FindMissingRecursiveRemove(*baseCl);
165 bool VerifyRecursiveRemove(
const char *classname)
167 TClass *classPtr = TClass::GetClass(classname);
169 return VerifyRecursiveRemove(*classPtr);
174 EResult HasConsistentHashMember(TClass &classRef)
177 if (classRef.fRuntimeProperties) {
179 return classRef.HasConsistentHashMember() ? kConsistent : kInconsistent;
182 if (classRef.HasLocalHashMember())
183 return CheckRecursiveRemove(classRef);
185 EResult baseResult = kConsistent;
186 for (
auto base : ROOT::Detail::TRangeStaticCast<TBaseClass>(classRef.GetListOfBases())) {
187 TClass *baseCl = base->GetClassPointer();
189 if (baseCl->HasLocalHashMember() &&
190 (!baseCl->HasDefaultConstructor() || baseCl->Property() & kIsAbstract))
194 return CheckRecursiveRemove(classRef);
196 auto baseConsistency = HasConsistentHashMember(*baseCl);
197 if (baseConsistency == kInconsistent) {
198 baseResult = kInconsistent;
199 }
else if (baseConsistency == kInconclusive) {
200 return CheckRecursiveRemove(classRef);
206 bool VerifyRecursiveRemove(TClass &classRef)
210 if (!classRef.IsTObject())
213 if (classRef.HasLocalHashMember() &&
214 (!classRef.HasDefaultConstructor() || classRef.Property() & kIsAbstract))
219 if (HasConsistentHashMember(classRef) != kConsistent) {
220 TClass *failing = FindMissingRecursiveRemove(classRef);
224 constexpr
const char *funcName =
"ROOT::Internal::TCheckHashRecursiveRemoveConsistency::CheckRecursiveRemove";
227 "The class %s overrides TObject::Hash but does not call TROOT::RecursiveRemove in its destructor (seen while checking %s).",
228 failing->GetName(),classRef.GetName());
230 ::Error(funcName,
"The class %s "
231 "or one of its base classes override TObject::Hash but does not call "
232 "TROOT::CallRecursiveRemoveIfNeeded in its destructor.\n",
240 static bool Check(TClass &classRef)
242 TCheckHashRecursiveRemoveConsistency checker;
243 return checker.VerifyRecursiveRemove(classRef);
246 ClassDefInline(TCheckHashRecursiveRemoveConsistency, 0);
252 #endif // ROOT__TCheckHashRecursiveRemoveConsistency