CMS 3D CMS Logo

DictionaryTools.cc
Go to the documentation of this file.
1 
2 /*
3 
4 This file defines functions used to check if ROOT dictionaries
5 are missing for those types that require dictionaries.
6 Also there is a utility function named public_base_classes that
7 is used to find the base classes of classes used as elements in
8 container products. These base classes are needed to setup the
9 product lookup tables to support Views. That function also checks
10 for dictionaries of that contained class and its base classes as
11 it finds them.
12 
13 As of this writing, the dictionary checking functions are used
14 in the following circumstances:
15 
16 1. All produced products.
17 
18 2. All products in the main ProductRegistry and that are present
19 in the input.
20 
21 3. All consumed product types. Also for consumed element types (used by
22 View). But for consumed element types there is only a requirement that
23 the element type and its base classes have dictionaries (because there
24 is no way to know if the containing product type is transient or not).
25 
26 4. Products declared as kept by an output module.
27 
28 Transient classes are an exception to the above requirements. For
29 transients classes the only classes that are required to have dictionaries
30 are the top level type and its wrapped type. Also if it is a container
31 that can be accessed by Views, then its contained type and the base classes
32 of that contained type must also have dictionaries. But only that.
33 Other contituents types of a transient type are not required to have
34 dictionaries. This special treatment of transients is genuinely needed
35 because there are multiple transient types in CMSSW which do not have
36 dictionaries for many of their constituent types.
37 
38 For persistent types it checks the unwrapped type, the wrapped type, and
39 all the constituent types. It uses the TClass::GetMissingDictionaries
40 function from ROOT to check constituent types and depends on that.
41 (Currently, there is a JIRA ticket submitted related to bugs in that
42 ROOT function, JIRA-8208. We are trying to use the ROOT function for
43 that instead of creating our own CMS specific code that we need to
44 develop and maintain.). For transient types, TClass::GetMissingDictionaries
45 is not used because it requires too many of the constituent types
46 to have dictionaries.
47 
48 */
49 
51 
58 
59 #include "TClass.h"
60 #include "TClassEdit.h"
61 #include "THashTable.h"
62 
63 #include <algorithm>
64 #include <sstream>
65 
66 namespace edm {
67 
68  bool checkDictionary(std::vector<std::string>& missingDictionaries, TypeID const& typeID) {
69  TClass::GetClass(typeID.typeInfo());
70  if (!hasDictionary(typeID.typeInfo())) {
71  // a second attempt to load
73  }
74  if (!hasDictionary(typeID.typeInfo())) {
75  missingDictionaries.emplace_back(typeID.className());
76  return false;
77  }
78  return true;
79  }
80 
81  bool checkDictionaryOfWrappedType(std::vector<std::string>& missingDictionaries, TypeID const& unwrappedTypeID) {
82  std::string wrappedName = wrappedClassName(unwrappedTypeID.className());
83  TypeWithDict wrappedTypeWithDict = TypeWithDict::byName(wrappedName);
84  return checkDictionary(missingDictionaries, wrappedName, wrappedTypeWithDict);
85  }
86 
87  bool checkDictionaryOfWrappedType(std::vector<std::string>& missingDictionaries, std::string const& unwrappedName) {
88  std::string wrappedName = wrappedClassName(unwrappedName);
89  TypeWithDict wrappedTypeWithDict = TypeWithDict::byName(wrappedName);
90  return checkDictionary(missingDictionaries, wrappedName, wrappedTypeWithDict);
91  }
92 
93  bool checkDictionary(std::vector<std::string>& missingDictionaries,
94  std::string const& name,
95  TypeWithDict const& typeWithDict) {
96  if (!bool(typeWithDict) || typeWithDict.invalidTypeInfo()) {
97  missingDictionaries.emplace_back(name);
98  return false;
99  }
100  return true;
101  }
102 
103  bool checkClassDictionaries(std::vector<std::string>& missingDictionaries, TypeID const& typeID) {
104  // For a class type with a dictionary the TClass* will be
105  // non-null and hasDictionary will return true.
106  // For a type like "int", the TClass* pointer will be a
107  // nullptr and hasDictionary will return true.
108  // For a class type without a dictionary it is possible for
109  // TClass* to be non-null and hasDictionary to return false.
110 
111  TClass* tClass = TClass::GetClass(typeID.typeInfo());
112  if (!hasDictionary(typeID.typeInfo())) {
113  // a second attempt to load
115  tClass = TClass::GetClass(typeID.typeInfo());
116  }
117  if (!hasDictionary(typeID.typeInfo())) {
118  missingDictionaries.emplace_back(typeID.className());
119  return false;
120  }
121 
122  if (tClass == nullptr) {
123  return true;
124  }
125 
126  bool result = true;
127 
128  THashTable hashTable;
129  bool recursive = true;
130  tClass->GetMissingDictionaries(hashTable, recursive);
131 
132  for (auto const& item : hashTable) {
133  TClass const* cl = static_cast<TClass const*>(item);
134  missingDictionaries.emplace_back(cl->GetName());
135  result = false;
136  }
137  return result;
138  }
139 
140  bool checkClassDictionaries(std::vector<std::string>& missingDictionaries,
141  std::string const& name,
142  TypeWithDict const& typeWithDict) {
143  if (!bool(typeWithDict) || typeWithDict.invalidTypeInfo()) {
144  missingDictionaries.emplace_back(name);
145  return false;
146  }
147 
148  TClass* tClass = typeWithDict.getClass();
149  if (tClass == nullptr) {
150  missingDictionaries.emplace_back(name);
151  return false;
152  }
153 
154  THashTable hashTable;
155  bool recursive = true;
156  tClass->GetMissingDictionaries(hashTable, recursive);
157 
158  bool result = true;
159 
160  for (auto const& item : hashTable) {
161  TClass const* cl = static_cast<TClass const*>(item);
162  missingDictionaries.emplace_back(cl->GetName());
163  result = false;
164  }
165  return result;
166  }
167 
169  std::vector<std::string>& missingDictionaries,
170  std::string const& context) {
171  std::sort(missingDictionaries.begin(), missingDictionaries.end());
172  missingDictionaries.erase(std::unique(missingDictionaries.begin(), missingDictionaries.end()),
173  missingDictionaries.end());
174 
175  std::ostringstream ostr;
176  for (auto const& item : missingDictionaries) {
177  ostr << " " << item << "\n";
178  }
179  exception << "No data dictionary found for the following classes:\n\n"
180  << ostr.str() << "\n"
181  << "Most likely each dictionary was never generated, but it may\n"
182  << "be that it was generated in the wrong package. Please add\n"
183  << "(or move) the specification \'<class name=\"whatever\"/>\' to\n"
184  << "the appropriate classes_def.xml file along with any other\n"
185  << "information needed there. For example, if this class has any\n"
186  << "transient members, you need to specify them in classes_def.xml.\n"
187  << "Also include the class header in classes.h\n";
188 
189  if (!context.empty()) {
190  exception.addContext(context);
191  }
192  }
193 
194  void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries, std::string const& context) {
195  std::vector<std::string> empty;
196  throwMissingDictionariesException(missingDictionaries, context, empty);
197  }
198 
199  void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
200  std::string const& context,
201  std::vector<std::string>& producedTypes) {
203  addToMissingDictionariesException(exception, missingDictionaries, context);
204 
205  if (!producedTypes.empty()) {
206  std::sort(producedTypes.begin(), producedTypes.end());
207  producedTypes.erase(std::unique(producedTypes.begin(), producedTypes.end()), producedTypes.end());
208 
209  std::ostringstream ostr;
210  for (auto const& item : producedTypes) {
211  ostr << " " << item << "\n";
212  }
213  exception << "\nA type listed above might or might not be the same as a\n"
214  << "type declared by a producer module with the function \'produces\'.\n"
215  << "Instead it might be the type of a data member, base class,\n"
216  << "wrapped type, or other object needed by a produced type. Below\n"
217  << "is some additional information which lists the types declared\n"
218  << "to be produced by a producer module that are associated with\n"
219  << "the types whose dictionaries were not found:\n\n"
220  << ostr.str() << "\n";
221  }
222  throw exception;
223  }
224 
225  void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
226  std::string const& context,
227  std::vector<std::string>& producedTypes,
228  std::vector<std::string>& branchNames,
229  bool fromStreamerSource) {
231  addToMissingDictionariesException(exception, missingDictionaries, context);
232 
233  if (!producedTypes.empty()) {
234  std::sort(producedTypes.begin(), producedTypes.end());
235  producedTypes.erase(std::unique(producedTypes.begin(), producedTypes.end()), producedTypes.end());
236 
237  std::ostringstream ostr;
238  for (auto const& item : producedTypes) {
239  ostr << " " << item << "\n";
240  }
241  if (fromStreamerSource) {
242  exception << "\nA type listed above might or might not be the same as a\n"
243  << "type stored in the Event. Instead it might be the type of\n"
244  << "a data member, base class, wrapped type, or other object\n"
245  << "needed by a stored type. Below is some additional information\n"
246  << "which lists the stored types associated with the types whose\n"
247  << "dictionaries were not found:\n\n"
248  << ostr.str() << "\n";
249  } else {
250  exception << "\nA type listed above might or might not be the same as a\n"
251  << "type stored in the Event (or Lumi or Run). Instead it might\n"
252  << "be the type of a data member, base class, wrapped type, or\n"
253  << "other object needed by a stored type. Below is some additional\n"
254  << "information which lists the stored types associated with the\n"
255  << "types whose dictionaries were not found:\n\n"
256  << ostr.str() << "\n";
257  }
258  }
259 
260  if (!branchNames.empty()) {
261  std::sort(branchNames.begin(), branchNames.end());
262  branchNames.erase(std::unique(branchNames.begin(), branchNames.end()), branchNames.end());
263 
264  std::ostringstream ostr;
265  for (auto const& item : branchNames) {
266  ostr << " " << item << "\n";
267  }
268  if (fromStreamerSource) {
269  exception << "Missing dictionaries are associated with these branch names:\n\n" << ostr.str() << "\n";
270  } else {
271  exception << "Missing dictionaries are associated with these branch names:\n\n"
272  << ostr.str() << "\n"
273  << "If you do not need these branches and they are not produced\n"
274  << "in the current process, an alternate solution to adding\n"
275  << "dictionaries is to drop these branches on input using the\n"
276  << "inputCommands parameter of the PoolSource.";
277  }
278  }
279  throw exception;
280  }
281 
282  void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
283  std::string const& context,
284  std::set<std::string>& producedTypes,
285  bool consumedWithView) {
287  addToMissingDictionariesException(exception, missingDictionaries, context);
288 
289  if (!producedTypes.empty()) {
290  std::ostringstream ostr;
291  for (auto const& item : producedTypes) {
292  ostr << " " << item << "\n";
293  }
294  if (consumedWithView) {
295  exception << "\nThe list of types above was generated while checking for\n"
296  << "dictionaries related to products declared to be consumed\n"
297  << "using a View. They will be either the type or a base class\n"
298  << "of the type declared in a consumes declaration as the template\n"
299  << "parameter of a View. Below is some additional information\n"
300  << "which lists the type of the template parameter of the View.\n"
301  << "(It will be the same type unless the missing dictionary is\n"
302  << "for a base type):\n\n"
303  << ostr.str() << "\n";
304  } else {
305  exception << "\nThe list of types above was generated while checking for\n"
306  << "dictionaries related to products declared to be consumed.\n"
307  << "A type listed above might or might not be a type declared\n"
308  << "to be consumed. Instead it might be the type of a data member,\n"
309  << "base class, wrapped type or other object needed by a consumed\n"
310  << "type. Below is some additional information which lists\n"
311  << "the types declared to be consumed by a module and which\n"
312  << "are associated with the types whose dictionaries were not\n"
313  << "found:\n\n"
314  << ostr.str() << "\n";
315  }
316  }
317  throw exception;
318  }
319 
320  bool public_base_classes(std::vector<std::string>& missingDictionaries,
321  TypeID const& typeID,
322  std::vector<TypeID>& baseTypes) {
323  if (!checkDictionary(missingDictionaries, typeID)) {
324  return false;
325  }
326  TypeWithDict typeWithDict(typeID.typeInfo());
327 
328  if (!typeWithDict.isClass()) {
329  return true;
330  }
331 
332  // No need to check into base classes of standard library
333  // classes.
334  if (TClassEdit::IsStdClass(typeWithDict.name().c_str())) {
335  return true;
336  }
337 
338  TypeBases bases(typeWithDict);
339  bool returnValue = true;
340  for (auto const& basex : bases) {
341  BaseWithDict base(basex);
342  if (!base.isPublic()) {
343  continue;
344  }
345  TypeWithDict baseRflxType = base.typeOf();
346  if (!checkDictionary(missingDictionaries, baseRflxType.name(), baseRflxType)) {
347  returnValue = false;
348  continue;
349  }
350  TypeID baseType{baseRflxType.typeInfo()};
351  // Check to make sure this base appears only once in the
352  // inheritance hierarchy.
353  if (!search_all(baseTypes, baseType)) {
354  // Save the type and recursive look for its base types
355  baseTypes.push_back(baseType);
356  if (!public_base_classes(missingDictionaries, baseType, baseTypes)) {
357  returnValue = false;
358  continue;
359  }
360  }
361  // For now just ignore it if the class appears twice,
362  // After some more testing we may decide to uncomment the following
363  // exception.
364  //
365  //else {
366  // throw Exception(errors::UnimplementedFeature)
367  // << "DataFormats/Common/src/DictionaryTools.cc in function public_base_classes.\n"
368  // << "Encountered class that has a public base class that appears\n"
369  // << "multiple times in its inheritance heirarchy.\n"
370  // << "Please contact the EDM Framework group with details about\n"
371  // << "this exception. It was our hope that this complicated situation\n"
372  // << "would not occur. There are three possible solutions. 1. Change\n"
373  // << "the class design so the public base class does not appear multiple\n"
374  // << "times in the inheritance heirarchy. In many cases, this is a\n"
375  // << "sign of bad design. 2. Modify the code that supports Views to\n"
376  // << "ignore these base classes, but not supply support for creating a\n"
377  // << "View of this base class. 3. Improve the View infrastructure to\n"
378  // << "deal with this case. Class name of base class: " << baseType.Name() << "\n\n";
379  //}
380  }
381  return returnValue;
382  }
383 
384 } // namespace edm
void throwMissingDictionariesException(std::vector< std::string > &missingDictionaries, std::string const &context)
bool public_base_classes(std::vector< std::string > &missingDictionaries, TypeID const &typeID, std::vector< TypeID > &baseTypes)
bool invalidTypeInfo() const
static TypeWithDict byName(std::string const &name)
Definition: TypeWithDict.cc:74
bool checkDictionary(std::vector< std::string > &missingDictionaries, TypeID const &typeID)
def unique(seq, keepstr=True)
Definition: tier0.py:24
bool checkClassDictionaries(std::vector< std::string > &missingDictionaries, TypeID const &typeID)
std::string const & className() const
Definition: TypeID.cc:40
std::type_info const & typeInfo() const
std::string wrappedClassName(std::string const &iFullName)
std::string name() const
bool search_all(ForwardSequence const &s, Datum const &d)
Definition: Algorithms.h:36
void addToMissingDictionariesException(edm::Exception &exception, std::vector< std::string > &missingDictionaries, std::string const &context)
TClass * getClass() const
HLT enums.
bool hasDictionary(std::type_info const &)
bool checkDictionaryOfWrappedType(std::vector< std::string > &missingDictionaries, TypeID const &unwrappedTypeID)
constexpr const std::type_info & typeInfo() const
Definition: TypeIDBase.h:50
branchNames
Definition: haddnano.py:54