Logo ROOT   6.12/07
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}
50 TStatusBitsChecker::Check("TStreamerElement");
51 
52 Error in <TStatusBitsChecker>: In TStreamerElement class hierarchy, there are duplicates bits:
53 Error in <TStatusBitsChecker>: Bit 6 used in TStreamerElement as kHasRange
54 Error in <TStatusBitsChecker>: Bit 6 used in TObject as kCannotPick
55 Error in <TStatusBitsChecker>: Bit 13 used in TStreamerElement as kDoNotDelete
56 Error 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 
72 namespace ROOT {
73 namespace 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.
99 UChar_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.
135 void TStatusBitsChecker::Registry::RegisterBits(TClass &classRef /* = false */)
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.
181 bool 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.
224 bool 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.
233 bool 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.
247 bool 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
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
static UChar_t ConvertToBit(Long64_t constant, TClass &classRef, const char *constantName)
The TEnum class implements the enum type.
Definition: TEnum.h:31
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition: TClass.cxx:3507
long long Long64_t
Definition: RtypesCore.h:69
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
static bool Check(TClass &classRef, bool verbose=false)
R__EXTERN TClassTable * gClassTable
Definition: TClassTable.h:95
TList * GetListOfEnums(Bool_t load=kTRUE)
Return a list containing the TEnums of a class.
Definition: TClass.cxx:3561
int Int_t
Definition: RtypesCore.h:41
const TSeqCollection * GetConstants() const
Definition: TEnum.h:55
virtual TObject * FindObject(const char *name) const
Delete a TObjLink object.
Definition: TList.cxx:574
static void Init()
static bool CheckAllClasses(bool verbosity=false)
void Info(const char *location, const char *msgfmt,...)
A doubly linked list.
Definition: TList.h:44
bool Check(TClass &classRef, bool verbose=false)
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
#define Printf
Definition: TGeoToOCC.h:18
static char * Next()
Returns next class from sorted class table.
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:2887
Long64_t GetValue() const
Definition: TEnumConstant.h:40
std::map< UChar_t, std::list< Info > > fRegister
! Register of bits seen so far.
unsigned char UChar_t
Definition: RtypesCore.h:34
const Bool_t kTRUE
Definition: RtypesCore.h:87
const Int_t n
Definition: legend1.C:16
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.
const TEnumConstant * GetConstant(const char *name) const
Definition: TEnum.h:58