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