Logo ROOT   6.16/01
Reference Guide
TStatusBitsChecker.cxx
Go to the documentation of this file.
1// Author: Philippe Canal, 2017
2
3/*************************************************************************
4 * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11/** \class TStatusBitsChecker
12
13 TStatusBitsChecker::Check and TStatusBitsChecker::CheckAllClasses will
14 determine if the set of "status bit" declared in the class and its
15 base classes presents any overlap. The status bit are declared in
16 a given class by declaring an enum type named EStatusBits.
17 If some of the duplication is intentional, those duplication can
18 be registered in an enum type named EStatusBitsDupExceptions.
19
20 ~~~ {.cpp}
21 // TStreamerElement status bits
22 enum EStatusBits {
23 kHasRange = BIT(6),
24 kCache = BIT(9),
25 kRepeat = BIT(10),
26 kRead = BIT(11),
27 kWrite = BIT(12),
28 kDoNotDelete = BIT(13),
29 kWholeObject = BIT(14)
30 };
31
32 enum class EStatusBitsDupExceptions {
33 // This bit duplicates TObject::kInvalidObject. As the semantic of kDoNotDelete is a persistent,
34 // we can not change its value without breaking forward compatibility.
35 // Furthermore, TObject::kInvalidObject and its semantic is not (and should not be)
36 // used in TStreamerElement
37 kDoNotDelete = TStreamerElement::kDoNotDelete,
38
39 // This bit duplicates TObject::kCannotPick. As the semantic of kHasRange is a persistent,
40 // we can not change its value without breaking forward compatibility.
41 // Furthermore, TObject::kCannotPick and its semantic is not (and should not be)
42 // used in TStreamerElement
43 kHasRange = TStreamerElement::kHasRange
44 };
45 ~~~ {.cpp}
46
47 Without the EStatusBitsDupExceptions enum you would see
48
49 ~~~ {.cpp}
50TStatusBitsChecker::Check("TStreamerElement");
51
52Error in <TStatusBitsChecker>: In TStreamerElement class hierarchy, there are duplicates bits:
53Error in <TStatusBitsChecker>: Bit 6 used in TStreamerElement as kHasRange
54Error in <TStatusBitsChecker>: Bit 6 used in TObject as kCannotPick
55Error in <TStatusBitsChecker>: Bit 13 used in TStreamerElement as kDoNotDelete
56Error in <TStatusBitsChecker>: Bit 13 used in TObject as kInvalidObject
57 ~~~ {.cpp}
58
59*/
60
61#include "TStatusBitsChecker.h"
62
63#include "TBaseClass.h"
64#include "TClass.h"
65#include "TClassTable.h"
66#include "TEnum.h"
67#include "TEnumConstant.h"
68#include "TError.h"
69
70#include <cmath>
71
72namespace ROOT {
73namespace Detail {
74
76 Info() = default;
77 Info(const Info &) = default;
78 Info(Info &&) = default;
79
80 Info(TClass &o, std::string &&n, bool intentionalDup) : fOwner(&o), fConstantName(n), fIntentionalDup(intentionalDup)
81 {
82 }
83
84 ~Info() = default;
85
86 TClass *fOwner;
87 std::string fConstantName;
88 bool fIntentionalDup = false;
89};
90
91/// Default constructor. Implemented in source file to allow hiding of the Info struct.
93
94/// Default destructor. Implemented in source file to allow hiding of the Info struct.
96
97/// Figure out which bit the constant has been set from/to.
98/// Return 255 if the constant is not an integer or out of range.
99UChar_t TStatusBitsChecker::ConvertToBit(Long64_t constant, TClass &classRef, const char *constantName)
100{
101
102 if (constant <= 0) {
103 Error("TStatusBitsChecker::ConvertBit", "In %s the value of %s is %lld which was not produced by BIT macro.",
104 classRef.GetName(), constantName, constant);
105 return 255;
106 }
107
108 int backshift;
109 double fraction = std::frexp(constant, &backshift);
110 // frexp doc is:
111 // if no errors occur,
112 // returns the value x in the range (-1;-0.5], [0.5; 1)
113 // and stores an integer value in *exp such that x×2^(*exp) = arg
114 --backshift; // frexp is such that BIT(0) == 1 == 0.5*2^(*exp) with *exp == 1
115
116 if (backshift < 0 || std::abs(0.5 - fraction) > 0.00001f) {
117 Error("TStatusBitsChecker::ConvertBit", "In %s the value of %s is %lld which was not produced by BIT macro.",
118 classRef.GetName(), constantName, constant);
119 return 255;
120 }
121
122 if (backshift > 24) {
123 Error("TStatusBitsChecker::ConvertBit", "In %s the value of %s is %lld (>23) which is ignored by SetBit.",
124 classRef.GetName(), constantName, constant);
125
126 if (backshift > 255) // really we could snip it sooner.
127 backshift = 255;
128 }
129
130 return backshift;
131}
132
133/// @brief Add to fRegister the Info about the bits in this class and its base
134/// classes.
136{
137 TEnum *eStatusBits = (TEnum *)classRef.GetListOfEnums()->FindObject("EStatusBits");
138 TEnum *exceptionBits = (TEnum *)classRef.GetListOfEnums()->FindObject("EStatusBitsDupExceptions");
139
140 if (eStatusBits) {
141
142 for (auto constant : TRangeStaticCast<TEnumConstant>(*eStatusBits->GetConstants())) {
143
144 // Ignore the known/intentional duplication.
145 bool intentionalDup = exceptionBits && exceptionBits->GetConstant(constant->GetName());
146
147 auto value = constant->GetValue();
148 auto bit = ConvertToBit(value, classRef, constant->GetName());
149
150 if (bit < 24) {
151 bool need = true;
152 for (auto reg : fRegister[bit]) {
153 if (reg.fOwner == &classRef) {
154 // We have a duplicate declared in the same class
155 // let's accept this as an alias.
156 need = false;
157 }
158 }
159
160 if (need)
161 fRegister[bit].emplace_back(classRef, std::string(constant->GetName()), intentionalDup);
162 }
163 }
164 }
165
166 TList *lb = classRef.GetListOfBases();
167 if (lb) {
168 for (auto base : TRangeStaticCast<TBaseClass>(*lb)) {
169 TClass *bcl = base->GetClassPointer();
170 if (bcl)
171 RegisterBits(*bcl);
172 }
173 }
174}
175
176/// @brief Return false and print error messages if there is any unexpected
177/// duplicates BIT constant in the class hierarchy or any of the bits
178/// already registered.
179/// If verbose is true, also print all the bit declare in this class
180/// and all its bases.
181bool TStatusBitsChecker::Registry::Check(TClass &classRef, bool verbose /* = false */)
182{
183 RegisterBits(classRef);
184
185 if (verbose) {
186 for (auto cursor : fRegister) {
187 for (auto constant : cursor.second) {
188 Printf("Bit %3d declared in %s as %s", cursor.first, constant.fOwner->GetName(),
189 constant.fConstantName.c_str());
190 }
191 }
192 }
193
194 bool issuedHeader = false;
195 bool result = true;
196 for (auto cursor : fRegister) {
197 unsigned int nDuplicate = 0;
198 for (auto constant : cursor.second) {
199 if (!constant.fIntentionalDup)
200 ++nDuplicate;
201 }
202 if (nDuplicate > 1) {
203 if (!issuedHeader) {
204 Error("TStatusBitsChecker", "In %s class hierarchy, there are duplicates bits:", classRef.GetName());
205 issuedHeader = true;
206 }
207 for (auto constant : cursor.second) {
208 if (!constant.fIntentionalDup) {
209 Error("TStatusBitsChecker", " Bit %3d used in %s as %s", cursor.first, constant.fOwner->GetName(),
210 constant.fConstantName.c_str());
211 result = false;
212 }
213 }
214 }
215 }
216
217 return result;
218}
219
220/// Return false and print error messages if there is any unexpected
221/// duplicates BIT constant in the class hierarchy.
222/// If verbose is true, also print all the bit declare in this class
223/// and all its bases.
224bool TStatusBitsChecker::Check(TClass &classRef, bool verbose /* = false */)
225{
226 return Registry().Check(classRef, verbose);
227}
228
229/// Return false and print error messages if there is any unexpected
230/// duplicates BIT constant in the class hierarchy.
231/// If verbose is true, also print all the bit declare in this class
232/// and all its bases.
233bool TStatusBitsChecker::Check(const char *classname, bool verbose)
234{
235 TClass *cl = TClass::GetClass(classname);
236 if (cl)
237 return Check(*cl, verbose);
238 else
239 return true;
240}
241
242/// Return false and print error messages if there is any unexpected
243/// duplicates BIT constant in any of the class hierarchy knows
244/// to TClassTable.
245/// If verbose is true, also print all the bit declare in eacho of the classes
246/// and all their bases.
247bool TStatusBitsChecker::CheckAllClasses(bool verbosity /* = false */)
248{
249 bool result = true;
250
251 // Start from beginning
252 gClassTable->Init();
253
254 std::set<std::string> rootLibs;
255 TList classesDeclFileNotFound;
256 TList classesImplFileNotFound;
257
258 Int_t totalNumberOfClasses = gClassTable->Classes();
259 for (Int_t i = 0; i < totalNumberOfClasses; i++) {
260
261 // get class name
262 const char *cname = gClassTable->Next();
263 if (!cname)
264 continue;
265
266 // get class & filename - use TROOT::GetClass, as we also
267 // want those classes without decl file name!
268 TClass *classPtr = TClass::GetClass((const char *)cname, kTRUE);
269 if (!classPtr)
270 continue;
271
272 result = Check(*classPtr, verbosity) && result;
273 }
274
275 return result;
276}
277
278} // namespace Detail
279} // namespace ROOT
int Int_t
Definition: RtypesCore.h:41
unsigned char UChar_t
Definition: RtypesCore.h:34
long long Long64_t
Definition: RtypesCore.h:69
const Bool_t kTRUE
Definition: RtypesCore.h:87
R__EXTERN TClassTable * gClassTable
Definition: TClassTable.h:95
void Info(const char *location, const char *msgfmt,...)
void Error(const char *location, const char *msgfmt,...)
#define Printf
Definition: TGeoToOCC.h:18
TRangeStaticCast is an adaptater class that allows the typed iteration through a TCollection.
Definition: TCollection.h:382
std::map< UChar_t, std::list< Info > > fRegister
! Register of bits seen so far.
Registry()
Default constructor. Implemented in source file to allow hiding of the Info struct.
bool Check(TClass &classRef, bool verbose=false)
Return false and print error messages if there is any unexpected duplicates BIT constant in the class...
void RegisterBits(TClass &classRef)
Add to fRegister the Info about the bits in this class and its base classes.
~Registry()
Default destructor. Implemented in source file to allow hiding of the Info struct.
static bool Check(TClass &classRef, bool verbose=false)
Return false and print error messages if there is any unexpected duplicates BIT constant in the class...
static UChar_t ConvertToBit(Long64_t constant, TClass &classRef, const char *constantName)
Figure out which bit the constant has been set from/to.
static bool CheckAllClasses(bool verbosity=false)
Return false and print error messages if there is any unexpected duplicates BIT constant in any of th...
static char * Next()
Returns next class from sorted class table.
static void Init()
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
TList * GetListOfEnums(Bool_t load=kTRUE)
Return a list containing the TEnums of a class.
Definition: TClass.cxx:3559
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition: TClass.cxx:3505
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2885
Long64_t GetValue() const
Definition: TEnumConstant.h:40
The TEnum class implements the enum type.
Definition: TEnum.h:33
const TSeqCollection * GetConstants() const
Definition: TEnum.h:61
const TEnumConstant * GetConstant(const char *name) const
Definition: TEnum.h:64
A doubly linked list.
Definition: TList.h:44
virtual TObject * FindObject(const char *name) const
Delete a TObjLink object.
Definition: TList.cxx:574
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
const Int_t n
Definition: legend1.C:16
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21