Logo ROOT  
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 #include <set>
72 
73 namespace ROOT {
74 namespace Detail {
75 
77  Info() = default;
78  Info(const Info &) = default;
79  Info(Info &&) = default;
80 
81  Info(TClass &o, std::string &&n, bool intentionalDup) : fOwner(&o), fConstantName(n), fIntentionalDup(intentionalDup)
82  {
83  }
84 
85  ~Info() = default;
86 
87  TClass *fOwner;
88  std::string fConstantName;
89  bool fIntentionalDup = false;
90 };
91 
92 /// Default constructor. Implemented in source file to allow hiding of the Info struct.
94 
95 /// Default destructor. Implemented in source file to allow hiding of the Info struct.
97 
98 /// Figure out which bit the constant has been set from/to.
99 /// Return 255 if the constant is not an integer or out of range.
100 UChar_t TStatusBitsChecker::ConvertToBit(Long64_t constant, TClass &classRef, const char *constantName)
101 {
102 
103  if (constant <= 0) {
104  Error("TStatusBitsChecker::ConvertBit", "In %s the value of %s is %lld which was not produced by BIT macro.",
105  classRef.GetName(), constantName, constant);
106  return 255;
107  }
108 
109  int backshift;
110  double fraction = std::frexp(constant, &backshift);
111  // frexp doc is:
112  // if no errors occur,
113  // returns the value x in the range (-1;-0.5], [0.5; 1)
114  // and stores an integer value in *exp such that x×2^(*exp) = arg
115  --backshift; // frexp is such that BIT(0) == 1 == 0.5*2^(*exp) with *exp == 1
116 
117  if (backshift < 0 || std::abs(0.5 - fraction) > 0.00001f) {
118  Error("TStatusBitsChecker::ConvertBit", "In %s the value of %s is %lld which was not produced by BIT macro.",
119  classRef.GetName(), constantName, constant);
120  return 255;
121  }
122 
123  if (backshift > 24) {
124  Error("TStatusBitsChecker::ConvertBit", "In %s the value of %s is %lld (>23) which is ignored by SetBit.",
125  classRef.GetName(), constantName, constant);
126 
127  if (backshift > 255) // really we could snip it sooner.
128  backshift = 255;
129  }
130 
131  return backshift;
132 }
133 
134 /// @brief Add to fRegister the Info about the bits in this class and its base
135 /// classes.
137 {
138  TEnum *eStatusBits = (TEnum *)classRef.GetListOfEnums()->FindObject("EStatusBits");
139  TEnum *exceptionBits = (TEnum *)classRef.GetListOfEnums()->FindObject("EStatusBitsDupExceptions");
140 
141  if (eStatusBits) {
142 
143  for (auto constant : TRangeStaticCast<TEnumConstant>(*eStatusBits->GetConstants())) {
144 
145  // Ignore the known/intentional duplication.
146  bool intentionalDup = exceptionBits && exceptionBits->GetConstant(constant->GetName());
147 
148  auto value = constant->GetValue();
149  auto bit = ConvertToBit(value, classRef, constant->GetName());
150 
151  if (bit < 24) {
152  bool need = true;
153  for (auto reg : fRegister[bit]) {
154  if (reg.fOwner == &classRef) {
155  // We have a duplicate declared in the same class
156  // let's accept this as an alias.
157  need = false;
158  }
159  }
160 
161  if (need)
162  fRegister[bit].emplace_back(classRef, std::string(constant->GetName()), intentionalDup);
163  }
164  }
165  }
166 
167  TList *lb = classRef.GetListOfBases();
168  if (lb) {
169  for (auto base : TRangeStaticCast<TBaseClass>(*lb)) {
170  TClass *bcl = base->GetClassPointer();
171  if (bcl)
172  RegisterBits(*bcl);
173  }
174  }
175 }
176 
177 /// @brief Return false and print error messages if there is any unexpected
178 /// duplicates BIT constant in the class hierarchy or any of the bits
179 /// already registered.
180 /// If verbose is true, also print all the bit declare in this class
181 /// and all its bases.
182 bool TStatusBitsChecker::Registry::Check(TClass &classRef, bool verbose /* = false */)
183 {
184  RegisterBits(classRef);
185 
186  if (verbose) {
187  for (auto cursor : fRegister) {
188  for (auto constant : cursor.second) {
189  Printf("Bit %3d declared in %s as %s", cursor.first, constant.fOwner->GetName(),
190  constant.fConstantName.c_str());
191  }
192  }
193  }
194 
195  bool issuedHeader = false;
196  bool result = true;
197  for (auto cursor : fRegister) {
198  unsigned int nDuplicate = 0;
199  for (auto constant : cursor.second) {
200  if (!constant.fIntentionalDup)
201  ++nDuplicate;
202  }
203  if (nDuplicate > 1) {
204  if (!issuedHeader) {
205  Error("TStatusBitsChecker", "In %s class hierarchy, there are duplicates bits:", classRef.GetName());
206  issuedHeader = true;
207  }
208  for (auto constant : cursor.second) {
209  if (!constant.fIntentionalDup) {
210  Error("TStatusBitsChecker", " Bit %3d used in %s as %s", cursor.first, constant.fOwner->GetName(),
211  constant.fConstantName.c_str());
212  result = false;
213  }
214  }
215  }
216  }
217 
218  return result;
219 }
220 
221 /// Return false and print error messages if there is any unexpected
222 /// duplicates BIT constant in the class hierarchy.
223 /// If verbose is true, also print all the bit declare in this class
224 /// and all its bases.
225 bool TStatusBitsChecker::Check(TClass &classRef, bool verbose /* = false */)
226 {
227  return Registry().Check(classRef, verbose);
228 }
229 
230 /// Return false and print error messages if there is any unexpected
231 /// duplicates BIT constant in the class hierarchy.
232 /// If verbose is true, also print all the bit declare in this class
233 /// and all its bases.
234 bool TStatusBitsChecker::Check(const char *classname, bool verbose)
235 {
236  TClass *cl = TClass::GetClass(classname);
237  if (cl)
238  return Check(*cl, verbose);
239  else
240  return true;
241 }
242 
243 /// Return false and print error messages if there is any unexpected
244 /// duplicates BIT constant in any of the class hierarchy knows
245 /// to TClassTable.
246 /// If verbose is true, also print all the bit declare in eacho of the classes
247 /// and all their bases.
248 bool TStatusBitsChecker::CheckAllClasses(bool verbosity /* = false */)
249 {
250  bool result = true;
251 
252  // Start from beginning
253  gClassTable->Init();
254 
255  std::set<std::string> rootLibs;
256  TList classesDeclFileNotFound;
257  TList classesImplFileNotFound;
258 
259  Int_t totalNumberOfClasses = gClassTable->Classes();
260  for (Int_t i = 0; i < totalNumberOfClasses; i++) {
261 
262  // get class name
263  const char *cname = gClassTable->Next();
264  if (!cname)
265  continue;
266 
267  // get class & filename - use TROOT::GetClass, as we also
268  // want those classes without decl file name!
269  TClass *classPtr = TClass::GetClass((const char *)cname, kTRUE);
270  if (!classPtr)
271  continue;
272 
273  result = Check(*classPtr, verbosity) && result;
274  }
275 
276  return result;
277 }
278 
279 } // namespace Detail
280 } // namespace ROOT
gClassTable
R__EXTERN TClassTable * gClassTable
Definition: TClassTable.h:95
n
const Int_t n
Definition: legend1.C:16
TEnum::GetConstant
const TEnumConstant * GetConstant(const char *name) const
Definition: TEnum.h:60
kTRUE
const Bool_t kTRUE
Definition: RtypesCore.h:91
TStatusBitsChecker.h
f
#define f(i)
Definition: RSha256.hxx:122
TEnumConstant.h
ROOT::Detail::TStatusBitsChecker::ConvertToBit
static UChar_t ConvertToBit(Long64_t constant, TClass &classRef, const char *constantName)
Figure out which bit the constant has been set from/to.
Definition: TStatusBitsChecker.cxx:100
TEnumConstant::GetValue
Long64_t GetValue() const
Definition: TEnumConstant.h:40
ROOT::Detail::TStatusBitsChecker::Check
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...
Definition: TStatusBitsChecker.cxx:225
TList::FindObject
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:577
TClassTable::Init
static void Init()
Definition: TClassTable.cxx:334
Long64_t
long long Long64_t
Definition: RtypesCore.h:73
TBaseClass.h
TClass.h
TClass::GetListOfEnums
TList * GetListOfEnums(Bool_t load=kTRUE)
Return a list containing the TEnums of a class.
Definition: TClass.cxx:3609
TEnum::GetConstants
const TSeqCollection * GetConstants() const
Definition: TEnum.h:59
TClassTable.h
TEnum.h
TClass::GetListOfBases
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition: TClass.cxx:3555
TEnum
Definition: TEnum.h:33
ROOT::Detail::TRangeStaticCast
TRangeStaticCast is an adaptater class that allows the typed iteration through a TCollection.
Definition: TCollection.h:382
ROOT::Detail::TStatusBitsChecker::Registry::~Registry
~Registry()
Default destructor. Implemented in source file to allow hiding of the Info struct.
ROOT::Detail::TStatusBitsChecker::Registry::Registry
Registry()
Default constructor. Implemented in source file to allow hiding of the Info struct.
TClass::GetClass
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:2925
ROOT::Detail::TStatusBitsChecker::Registry
Definition: TStatusBitsChecker.h:30
TClassTable::Next
static char * Next()
Returns next class from sorted class table.
Definition: TClassTable.cxx:678
ROOT::Detail::TStatusBitsChecker::Registry::Check
bool Check(TClass &classRef, bool verbose=false)
Return false and print error messages if there is any unexpected duplicates BIT constant in the class...
Definition: TStatusBitsChecker.cxx:182
ROOT::Detail::TStatusBitsChecker::Registry::RegisterBits
void RegisterBits(TClass &classRef)
Add to fRegister the Info about the bits in this class and its base classes.
Definition: TStatusBitsChecker.cxx:136
Printf
void Printf(const char *fmt,...)
ROOT::Detail::TStatusBitsChecker::Registry::fRegister
std::map< UChar_t, std::list< Info > > fRegister
! Register of bits seen so far.
Definition: TStatusBitsChecker.h:32
Info
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition: TError.cxx:220
TClass
Definition: TClass.h:80
UChar_t
unsigned char UChar_t
Definition: RtypesCore.h:38
TClassTable::Classes
int Classes()
Definition: TClassTable.cxx:332
genreflex::verbose
bool verbose
Definition: rootcling_impl.cxx:133
TNamed::GetName
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:53
ROOT
VSD Structures.
Definition: StringConv.hxx:21
ROOT::Detail::TStatusBitsChecker::CheckAllClasses
static bool CheckAllClasses(bool verbosity=false)
Return false and print error messages if there is any unexpected duplicates BIT constant in any of th...
Definition: TStatusBitsChecker.cxx:248
TList
Definition: TList.h:44
int
Error
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition: TError.cxx:187
TError.h