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 "THashTable.h"
61 
62 #include <algorithm>
63 #include <sstream>
64 
65 namespace edm {
66 
67  bool
68  checkDictionary(std::vector<std::string>& missingDictionaries,
69  TypeID const& typeID) {
70 
71  TClass::GetClass(typeID.typeInfo());
72  if (!hasDictionary(typeID.typeInfo())) {
73  // a second attempt to load
75  }
76  if (!hasDictionary(typeID.typeInfo())) {
77  missingDictionaries.emplace_back(typeID.className());
78  return false;
79  }
80  return true;
81  }
82 
83  bool checkDictionaryOfWrappedType(std::vector<std::string>& missingDictionaries,
84  TypeID const& unwrappedTypeID) {
85  std::string wrappedName = wrappedClassName(unwrappedTypeID.className());
86  TypeWithDict wrappedTypeWithDict = TypeWithDict::byName(wrappedName);
87  return checkDictionary(missingDictionaries, wrappedName, wrappedTypeWithDict);
88  }
89 
90  bool checkDictionaryOfWrappedType(std::vector<std::string>& missingDictionaries,
91  std::string const& unwrappedName) {
92  std::string wrappedName = wrappedClassName(unwrappedName);
93  TypeWithDict wrappedTypeWithDict = TypeWithDict::byName(wrappedName);
94  return checkDictionary(missingDictionaries, wrappedName, wrappedTypeWithDict);
95  }
96 
97  bool
98  checkDictionary(std::vector<std::string>& missingDictionaries,
99  std::string const& name,
100  TypeWithDict const& typeWithDict) {
101  if (!bool(typeWithDict) || typeWithDict.invalidTypeInfo()) {
102  missingDictionaries.emplace_back(name);
103  return false;
104  }
105  return true;
106  }
107 
108  bool
109  checkClassDictionaries(std::vector<std::string>& missingDictionaries,
110  TypeID const& typeID) {
111 
112  // For a class type with a dictionary the TClass* will be
113  // non-null and hasDictionary will return true.
114  // For a type like "int", the TClass* pointer will be a
115  // nullptr and hasDictionary will return true.
116  // For a class type without a dictionary it is possible for
117  // TClass* to be non-null and hasDictionary to return false.
118 
119  TClass* tClass = TClass::GetClass(typeID.typeInfo());
120  if (!hasDictionary(typeID.typeInfo())) {
121  // a second attempt to load
123  tClass = TClass::GetClass(typeID.typeInfo());
124  }
125  if (!hasDictionary(typeID.typeInfo())) {
126  missingDictionaries.emplace_back(typeID.className());
127  return false;
128  }
129 
130  if (tClass == nullptr) {
131  return true;
132  }
133 
134  bool result = true;
135 
136  THashTable hashTable;
137  bool recursive = true;
138  tClass->GetMissingDictionaries(hashTable, recursive);
139 
140  for(auto const& item : hashTable) {
141  TClass const* cl = static_cast<TClass const*>(item);
142  missingDictionaries.emplace_back(cl->GetName());
143  result = false;
144  }
145  return result;
146  }
147 
148  bool
149  checkClassDictionaries(std::vector<std::string>& missingDictionaries,
150  std::string const& name,
151  TypeWithDict const& typeWithDict) {
152  if (!bool(typeWithDict) || typeWithDict.invalidTypeInfo()) {
153  missingDictionaries.emplace_back(name);
154  return false;
155  }
156 
157  TClass *tClass = typeWithDict.getClass();
158  if (tClass == nullptr) {
159  missingDictionaries.emplace_back(name);
160  return false;
161  }
162 
163  THashTable hashTable;
164  bool recursive = true;
165  tClass->GetMissingDictionaries(hashTable, recursive);
166 
167  bool result = true;
168 
169  for(auto const& item : hashTable) {
170  TClass const* cl = static_cast<TClass const*>(item);
171  missingDictionaries.emplace_back(cl->GetName());
172  result = false;
173  }
174  return result;
175  }
176 
178  std::vector<std::string>& missingDictionaries,
179  std::string const& context) {
180 
181  std::sort(missingDictionaries.begin(), missingDictionaries.end());
182  missingDictionaries.erase(std::unique(missingDictionaries.begin(), missingDictionaries.end()), missingDictionaries.end());
183 
184  std::ostringstream ostr;
185  for(auto const& item : missingDictionaries) {
186  ostr << " " << item << "\n";
187  }
188  exception << "No data dictionary found for the following classes:\n\n"
189  << ostr.str() << "\n"
190  << "Most likely each dictionary was never generated, but it may\n"
191  << "be that it was generated in the wrong package. Please add\n"
192  << "(or move) the specification \'<class name=\"whatever\"/>\' to\n"
193  << "the appropriate classes_def.xml file along with any other\n"
194  << "information needed there. For example, if this class has any\n"
195  << "transient members, you need to specify them in classes_def.xml.\n"
196  << "Also include the class header in classes.h\n";
197 
198  if (!context.empty()) {
199  exception.addContext(context);
200  }
201  }
202 
203  void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
204  std::string const& context) {
205  std::vector<std::string> empty;
206  throwMissingDictionariesException(missingDictionaries, context, empty);
207  }
208 
209  void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
210  std::string const& context,
211  std::vector<std::string>& producedTypes) {
212 
214  addToMissingDictionariesException(exception, missingDictionaries, context);
215 
216  if (!producedTypes.empty()) {
217  std::sort(producedTypes.begin(), producedTypes.end());
218  producedTypes.erase(std::unique(producedTypes.begin(), producedTypes.end()), producedTypes.end());
219 
220  std::ostringstream ostr;
221  for(auto const& item : producedTypes) {
222  ostr << " " << item << "\n";
223  }
224  exception << "\nA type listed above might or might not be the same as a\n"
225  << "type declared by a producer module with the function \'produces\'.\n"
226  << "Instead it might be the type of a data member, base class,\n"
227  << "wrapped type, or other object needed by a produced type. Below\n"
228  << "is some additional information which lists the types declared\n"
229  << "to be produced by a producer module that are associated with\n"
230  << "the types whose dictionaries were not found:\n\n"
231  << ostr.str() << "\n";
232  }
233  throw exception;
234  }
235 
236 
237  void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
238  std::string const& context,
239  std::vector<std::string>& producedTypes,
240  std::vector<std::string>& branchNames,
241  bool fromStreamerSource) {
242 
243 
245  addToMissingDictionariesException(exception, missingDictionaries, context);
246 
247  if (!producedTypes.empty()) {
248  std::sort(producedTypes.begin(), producedTypes.end());
249  producedTypes.erase(std::unique(producedTypes.begin(), producedTypes.end()), producedTypes.end());
250 
251  std::ostringstream ostr;
252  for(auto const& item : producedTypes) {
253  ostr << " " << item << "\n";
254  }
255  if (fromStreamerSource) {
256  exception << "\nA type listed above might or might not be the same as a\n"
257  << "type stored in the Event. Instead it might be the type of\n"
258  << "a data member, base class, wrapped type, or other object\n"
259  << "needed by a stored type. Below is some additional information\n"
260  << "which lists the stored types associated with the types whose\n"
261  << "dictionaries were not found:\n\n"
262  << ostr.str() << "\n";
263  } else {
264  exception << "\nA type listed above might or might not be the same as a\n"
265  << "type stored in the Event (or Lumi or Run). Instead it might\n"
266  << "be the type of a data member, base class, wrapped type, or\n"
267  << "other object needed by a stored type. Below is some additional\n"
268  << "information which lists the stored types associated with the\n"
269  << "types whose dictionaries were not found:\n\n"
270  << ostr.str() << "\n";
271  }
272  }
273 
274  if (!branchNames.empty()) {
275 
276  std::sort(branchNames.begin(), branchNames.end());
277  branchNames.erase(std::unique(branchNames.begin(), branchNames.end()), branchNames.end());
278 
279  std::ostringstream ostr;
280  for(auto const& item : branchNames) {
281  ostr << " " << item << "\n";
282  }
283  if (fromStreamerSource) {
284  exception << "Missing dictionaries are associated with these branch names:\n\n"
285  << ostr.str() << "\n";
286  } else {
287  exception << "Missing dictionaries are associated with these branch names:\n\n"
288  << ostr.str() << "\n"
289  << "If you do not need these branches and they are not produced\n"
290  << "in the current process, an alternate solution to adding\n"
291  << "dictionaries is to drop these branches on input using the\n"
292  << "inputCommands parameter of the PoolSource.";
293  }
294  }
295  throw exception;
296  }
297 
298  void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
299  std::string const& context,
300  std::set<std::string>& producedTypes,
301  bool consumedWithView) {
302 
304  addToMissingDictionariesException(exception, missingDictionaries, context);
305 
306  if (!producedTypes.empty()) {
307 
308  std::ostringstream ostr;
309  for(auto const& item : producedTypes) {
310  ostr << " " << item << "\n";
311  }
312  if (consumedWithView) {
313  exception << "\nThe list of types above was generated while checking for\n"
314  << "dictionaries related to products declared to be consumed\n"
315  << "using a View. They will be either the type or a base class\n"
316  << "of the type declared in a consumes declaration as the template\n"
317  << "parameter of a View. Below is some additional information\n"
318  << "which lists the type of the template parameter of the View.\n"
319  << "(It will be the same type unless the missing dictionary is\n"
320  << "for a base type):\n\n"
321  << ostr.str() << "\n";
322  } else {
323  exception << "\nThe list of types above was generated while checking for\n"
324  << "dictionaries related to products declared to be consumed.\n"
325  << "A type listed above might or might not be a type declared\n"
326  << "to be consumed. Instead it might be the type of a data member,\n"
327  << "base class, wrapped type or other object needed by a consumed\n"
328  << "type. Below is some additional information which lists\n"
329  << "the types declared to be consumed by a module and which\n"
330  << "are associated with the types whose dictionaries were not\n"
331  << "found:\n\n"
332  << ostr.str() << "\n";
333  }
334  }
335  throw exception;
336  }
337 
338 
339  bool
340  public_base_classes(std::vector<std::string>& missingDictionaries,
341  TypeID const& typeID,
342  std::vector<TypeWithDict>& baseTypes) {
343 
344  if (!checkDictionary(missingDictionaries, typeID)) {
345  return false;
346  }
347  TypeWithDict typeWithDict(typeID.typeInfo());
348 
349  if (!typeWithDict.isClass()) {
350  return true;
351  }
352 
353  TypeBases bases(typeWithDict);
354  bool returnValue = true;
355  for (auto const& basex : bases) {
356  BaseWithDict base(basex);
357  if (!base.isPublic()) {
358  continue;
359  }
360  TypeWithDict baseRflxType = base.typeOf();
361  if (!checkDictionary(missingDictionaries, baseRflxType.name(), baseRflxType)) {
362  returnValue = false;
363  continue;
364  }
365  TypeWithDict baseType(baseRflxType.typeInfo());
366  // Check to make sure this base appears only once in the
367  // inheritance hierarchy.
368  if (!search_all(baseTypes, baseType)) {
369  // Save the type and recursive look for its base types
370  baseTypes.push_back(baseType);
371  if (!public_base_classes(missingDictionaries, TypeID(baseType.typeInfo()), baseTypes)) {
372  returnValue = false;
373  continue;
374  }
375  }
376  // For now just ignore it if the class appears twice,
377  // After some more testing we may decide to uncomment the following
378  // exception.
379  //
380  //else {
381  // throw Exception(errors::UnimplementedFeature)
382  // << "DataFormats/Common/src/DictionaryTools.cc in function public_base_classes.\n"
383  // << "Encountered class that has a public base class that appears\n"
384  // << "multiple times in its inheritance heirarchy.\n"
385  // << "Please contact the EDM Framework group with details about\n"
386  // << "this exception. It was our hope that this complicated situation\n"
387  // << "would not occur. There are three possible solutions. 1. Change\n"
388  // << "the class design so the public base class does not appear multiple\n"
389  // << "times in the inheritance heirarchy. In many cases, this is a\n"
390  // << "sign of bad design. 2. Modify the code that supports Views to\n"
391  // << "ignore these base classes, but not supply support for creating a\n"
392  // << "View of this base class. 3. Improve the View infrastructure to\n"
393  // << "deal with this case. Class name of base class: " << baseType.Name() << "\n\n";
394  //}
395  }
396  return returnValue;
397  }
398 
399 } // 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< TypeWithDict > &baseTypes)
const std::type_info & typeInfo() const
Definition: TypeIDBase.h:58
static TypeWithDict byName(std::string const &name)
Definition: TypeWithDict.cc:82
bool invalidTypeInfo() const
TClass * getClass() const
std::string name() const
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::type_info const & typeInfo() const
TypeWithDict typeOf() const
Definition: BaseWithDict.cc:26
base
Make Sure CMSSW is Setup ##.
std::string wrappedClassName(std::string const &iFullName)
bool search_all(ForwardSequence const &s, Datum const &d)
Definition: Algorithms.h:46
void addContext(std::string const &context)
Definition: Exception.cc:227
void addToMissingDictionariesException(edm::Exception &exception, std::vector< std::string > &missingDictionaries, std::string const &context)
HLT enums.
std::string const & className() const
Definition: TypeID.cc:46
bool hasDictionary(std::type_info const &)
bool checkDictionaryOfWrappedType(std::vector< std::string > &missingDictionaries, TypeID const &unwrappedTypeID)
bool isPublic() const
Definition: BaseWithDict.cc:16