Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-07-20 02:18:37

0001 
0002 /*
0003 
0004 This file defines functions used to check if ROOT dictionaries
0005 are missing for those types that require dictionaries.
0006 Also there is a utility function named public_base_classes that
0007 is used to find the base classes of classes used as elements in
0008 container products. These base classes are needed to setup the
0009 product lookup tables to support Views. That function also checks
0010 for dictionaries of that contained class and its base classes as
0011 it finds them.
0012 
0013 As of this writing, the dictionary checking functions are used
0014 in the following circumstances:
0015 
0016 1. All produced products.
0017 
0018 2. All products in the main ProductRegistry and that are present
0019 in the input.
0020 
0021 3. All consumed product types. Also for consumed element types (used by
0022 View). But for consumed element types there is only a requirement that
0023 the element type and its base classes have dictionaries (because there
0024 is no way to know if the containing product type is transient or not).
0025 
0026 4. Products declared as kept by an output module.
0027 
0028 Transient classes are an exception to the above requirements. For
0029 transients classes the only classes that are required to have dictionaries
0030 are the top level type and its wrapped type. Also if it is a container
0031 that can be accessed by Views, then its contained type and the base classes
0032 of that contained type must also have dictionaries.  But only that.
0033 Other contituents types of a transient type are not required to have
0034 dictionaries. This special treatment of transients is genuinely needed
0035 because there are multiple transient types in CMSSW which do not have
0036 dictionaries for many of their constituent types.
0037 
0038 For persistent types it checks the unwrapped type, the wrapped type, and
0039 all the constituent types. It uses the TClass::GetMissingDictionaries
0040 function from ROOT to check constituent types and depends on that.
0041 (Currently, there is a JIRA ticket submitted related to bugs in that
0042 ROOT function, JIRA-8208. We are trying to use the ROOT function for
0043 that instead of creating our own CMS specific code that we need to
0044 develop and maintain.). For transient types, TClass::GetMissingDictionaries
0045 is not used because it requires too many of the constituent types
0046 to have dictionaries.
0047 
0048 */
0049 
0050 #include "FWCore/Reflection/interface/DictionaryTools.h"
0051 
0052 #include "FWCore/Utilities/interface/Algorithms.h"
0053 #include "FWCore/Reflection/interface/BaseWithDict.h"
0054 #include "FWCore/Utilities/interface/EDMException.h"
0055 #include "FWCore/Utilities/interface/TypeID.h"
0056 #include "FWCore/Reflection/interface/TypeWithDict.h"
0057 #include "FWCore/Utilities/interface/WrappedClassName.h"
0058 
0059 #include "TClass.h"
0060 #include "THashTable.h"
0061 
0062 #include <algorithm>
0063 #include <sstream>
0064 
0065 namespace edm {
0066 
0067   bool checkDictionary(std::vector<std::string>& missingDictionaries, TypeID const& typeID) {
0068     TClass::GetClass(typeID.typeInfo());
0069     if (!hasDictionary(typeID.typeInfo())) {
0070       // a second attempt to load
0071       TypeWithDict::byName(typeID.className());
0072     }
0073     if (!hasDictionary(typeID.typeInfo())) {
0074       missingDictionaries.emplace_back(typeID.className());
0075       return false;
0076     }
0077     return true;
0078   }
0079 
0080   bool checkDictionaryOfWrappedType(std::vector<std::string>& missingDictionaries, TypeID const& unwrappedTypeID) {
0081     std::string wrappedName = wrappedClassName(unwrappedTypeID.className());
0082     TypeWithDict wrappedTypeWithDict = TypeWithDict::byName(wrappedName);
0083     return checkDictionary(missingDictionaries, wrappedName, wrappedTypeWithDict);
0084   }
0085 
0086   bool checkDictionaryOfWrappedType(std::vector<std::string>& missingDictionaries, std::string const& unwrappedName) {
0087     std::string wrappedName = wrappedClassName(unwrappedName);
0088     TypeWithDict wrappedTypeWithDict = TypeWithDict::byName(wrappedName);
0089     return checkDictionary(missingDictionaries, wrappedName, wrappedTypeWithDict);
0090   }
0091 
0092   bool checkDictionary(std::vector<std::string>& missingDictionaries,
0093                        std::string const& name,
0094                        TypeWithDict const& typeWithDict) {
0095     if (!bool(typeWithDict) || typeWithDict.invalidTypeInfo()) {
0096       missingDictionaries.emplace_back(name);
0097       return false;
0098     }
0099     return true;
0100   }
0101 
0102   bool checkClassDictionaries(std::vector<std::string>& missingDictionaries, TypeID const& typeID) {
0103     // For a class type with a dictionary the TClass* will be
0104     // non-null and hasDictionary will return true.
0105     // For a type like "int", the TClass* pointer will be a
0106     // nullptr and hasDictionary will return true.
0107     // For a class type without a dictionary it is possible for
0108     // TClass* to be non-null and hasDictionary to return false.
0109 
0110     TClass* tClass = TClass::GetClass(typeID.typeInfo());
0111     if (!hasDictionary(typeID.typeInfo())) {
0112       // a second attempt to load
0113       TypeWithDict::byName(typeID.className());
0114       tClass = TClass::GetClass(typeID.typeInfo());
0115     }
0116     if (!hasDictionary(typeID.typeInfo())) {
0117       missingDictionaries.emplace_back(typeID.className());
0118       return false;
0119     }
0120 
0121     if (tClass == nullptr) {
0122       return true;
0123     }
0124 
0125     bool result = true;
0126 
0127     THashTable hashTable;
0128     bool recursive = true;
0129     tClass->GetMissingDictionaries(hashTable, recursive);
0130 
0131     for (auto const& item : hashTable) {
0132       TClass const* cl = static_cast<TClass const*>(item);
0133       missingDictionaries.emplace_back(cl->GetName());
0134       result = false;
0135     }
0136     return result;
0137   }
0138 
0139   bool checkClassDictionaries(std::vector<std::string>& missingDictionaries,
0140                               std::string const& name,
0141                               TypeWithDict const& typeWithDict) {
0142     if (!bool(typeWithDict) || typeWithDict.invalidTypeInfo()) {
0143       missingDictionaries.emplace_back(name);
0144       return false;
0145     }
0146 
0147     TClass* tClass = typeWithDict.getClass();
0148     if (tClass == nullptr) {
0149       missingDictionaries.emplace_back(name);
0150       return false;
0151     }
0152 
0153     THashTable hashTable;
0154     bool recursive = true;
0155     tClass->GetMissingDictionaries(hashTable, recursive);
0156 
0157     bool result = true;
0158 
0159     for (auto const& item : hashTable) {
0160       TClass const* cl = static_cast<TClass const*>(item);
0161       missingDictionaries.emplace_back(cl->GetName());
0162       result = false;
0163     }
0164     return result;
0165   }
0166 
0167   void addToMissingDictionariesException(edm::Exception& exception,
0168                                          std::vector<std::string>& missingDictionaries,
0169                                          std::string const& context) {
0170     std::sort(missingDictionaries.begin(), missingDictionaries.end());
0171     missingDictionaries.erase(std::unique(missingDictionaries.begin(), missingDictionaries.end()),
0172                               missingDictionaries.end());
0173 
0174     std::ostringstream ostr;
0175     for (auto const& item : missingDictionaries) {
0176       ostr << "  " << item << "\n";
0177     }
0178     exception << "No data dictionary found for the following classes:\n\n"
0179               << ostr.str() << "\n"
0180               << "Most likely each dictionary was never generated, but it may\n"
0181               << "be that it was generated in the wrong package. Please add\n"
0182               << "(or move) the specification \'<class name=\"whatever\"/>\' to\n"
0183               << "the appropriate classes_def.xml file along with any other\n"
0184               << "information needed there. For example, if this class has any\n"
0185               << "transient members, you need to specify them in classes_def.xml.\n"
0186               << "Also include the class header in classes.h\n";
0187 
0188     if (!context.empty()) {
0189       exception.addContext(context);
0190     }
0191   }
0192 
0193   void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries, std::string const& context) {
0194     std::vector<std::string> empty;
0195     throwMissingDictionariesException(missingDictionaries, context, empty);
0196   }
0197 
0198   void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
0199                                          std::string const& context,
0200                                          std::vector<std::string>& producedTypes) {
0201     edm::Exception exception(errors::DictionaryNotFound);
0202     addToMissingDictionariesException(exception, missingDictionaries, context);
0203 
0204     if (!producedTypes.empty()) {
0205       std::sort(producedTypes.begin(), producedTypes.end());
0206       producedTypes.erase(std::unique(producedTypes.begin(), producedTypes.end()), producedTypes.end());
0207 
0208       std::ostringstream ostr;
0209       for (auto const& item : producedTypes) {
0210         ostr << "  " << item << "\n";
0211       }
0212       exception << "\nA type listed above might or might not be the same as a\n"
0213                 << "type declared by a producer module with the function \'produces\'.\n"
0214                 << "Instead it might be the type of a data member, base class,\n"
0215                 << "wrapped type, or other object needed by a produced type. Below\n"
0216                 << "is some additional information which lists the types declared\n"
0217                 << "to be produced by a producer module that are associated with\n"
0218                 << "the types whose dictionaries were not found:\n\n"
0219                 << ostr.str() << "\n";
0220     }
0221     throw exception;
0222   }
0223 
0224   void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
0225                                          std::string const& context,
0226                                          std::vector<std::string>& producedTypes,
0227                                          std::vector<std::string>& branchNames,
0228                                          bool fromStreamerSource) {
0229     edm::Exception exception(errors::DictionaryNotFound);
0230     addToMissingDictionariesException(exception, missingDictionaries, context);
0231 
0232     if (!producedTypes.empty()) {
0233       std::sort(producedTypes.begin(), producedTypes.end());
0234       producedTypes.erase(std::unique(producedTypes.begin(), producedTypes.end()), producedTypes.end());
0235 
0236       std::ostringstream ostr;
0237       for (auto const& item : producedTypes) {
0238         ostr << "  " << item << "\n";
0239       }
0240       if (fromStreamerSource) {
0241         exception << "\nA type listed above might or might not be the same as a\n"
0242                   << "type stored in the Event. Instead it might be the type of\n"
0243                   << "a data member, base class, wrapped type, or other object\n"
0244                   << "needed by a stored type. Below is some additional information\n"
0245                   << "which lists the stored types associated with the types whose\n"
0246                   << "dictionaries were not found:\n\n"
0247                   << ostr.str() << "\n";
0248       } else {
0249         exception << "\nA type listed above might or might not be the same as a\n"
0250                   << "type stored in the Event (or Lumi or Run). Instead it might\n"
0251                   << "be the type of a data member, base class, wrapped type, or\n"
0252                   << "other object needed by a stored type. Below is some additional\n"
0253                   << "information which lists the stored types associated with the\n"
0254                   << "types whose dictionaries were not found:\n\n"
0255                   << ostr.str() << "\n";
0256       }
0257     }
0258 
0259     if (!branchNames.empty()) {
0260       std::sort(branchNames.begin(), branchNames.end());
0261       branchNames.erase(std::unique(branchNames.begin(), branchNames.end()), branchNames.end());
0262 
0263       std::ostringstream ostr;
0264       for (auto const& item : branchNames) {
0265         ostr << "  " << item << "\n";
0266       }
0267       if (fromStreamerSource) {
0268         exception << "Missing dictionaries are associated with these branch names:\n\n" << ostr.str() << "\n";
0269       } else {
0270         exception << "Missing dictionaries are associated with these branch names:\n\n"
0271                   << ostr.str() << "\n"
0272                   << "If you do not need these branches and they are not produced\n"
0273                   << "in the current process, an alternate solution to adding\n"
0274                   << "dictionaries is to drop these branches on input using the\n"
0275                   << "inputCommands parameter of the PoolSource.";
0276       }
0277     }
0278     throw exception;
0279   }
0280 
0281   void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
0282                                          std::string const& context,
0283                                          std::set<std::string>& producedTypes,
0284                                          bool consumedWithView) {
0285     edm::Exception exception(errors::DictionaryNotFound);
0286     addToMissingDictionariesException(exception, missingDictionaries, context);
0287 
0288     if (!producedTypes.empty()) {
0289       std::ostringstream ostr;
0290       for (auto const& item : producedTypes) {
0291         ostr << "  " << item << "\n";
0292       }
0293       if (consumedWithView) {
0294         exception << "\nThe list of types above was generated while checking for\n"
0295                   << "dictionaries related to products declared to be consumed\n"
0296                   << "using a View. They will be either the type or a base class\n"
0297                   << "of the type declared in a consumes declaration as the template\n"
0298                   << "parameter of a View. Below is some additional information\n"
0299                   << "which lists the type of the template parameter of the View.\n"
0300                   << "(It will be the same type unless the missing dictionary is\n"
0301                   << "for a base type):\n\n"
0302                   << ostr.str() << "\n";
0303       } else {
0304         exception << "\nThe list of types above was generated while checking for\n"
0305                   << "dictionaries related to products declared to be consumed.\n"
0306                   << "A type listed above might or might not be a type declared\n"
0307                   << "to be consumed. Instead it might be the type of a data member,\n"
0308                   << "base class, wrapped type or other object needed by a consumed\n"
0309                   << "type.  Below is some additional information which lists\n"
0310                   << "the types declared to be consumed by a module and which\n"
0311                   << "are associated with the types whose dictionaries were not\n"
0312                   << "found:\n\n"
0313                   << ostr.str() << "\n";
0314       }
0315     }
0316     throw exception;
0317   }
0318 
0319   bool public_base_classes(std::vector<std::string>& missingDictionaries,
0320                            TypeID const& typeID,
0321                            std::vector<TypeID>& baseTypes) {
0322     if (!checkDictionary(missingDictionaries, typeID)) {
0323       return false;
0324     }
0325     TypeWithDict typeWithDict(typeID.typeInfo());
0326 
0327     if (!typeWithDict.isClass()) {
0328       return true;
0329     }
0330 
0331     TypeBases bases(typeWithDict);
0332     bool returnValue = true;
0333     for (auto const& basex : bases) {
0334       BaseWithDict base(basex);
0335       if (!base.isPublic()) {
0336         continue;
0337       }
0338       TypeWithDict baseRflxType = base.typeOf();
0339       if (!checkDictionary(missingDictionaries, baseRflxType.name(), baseRflxType)) {
0340         returnValue = false;
0341         continue;
0342       }
0343       TypeID baseType{baseRflxType.typeInfo()};
0344       // Check to make sure this base appears only once in the
0345       // inheritance hierarchy.
0346       if (!search_all(baseTypes, baseType)) {
0347         // Save the type and recursive look for its base types
0348         baseTypes.push_back(baseType);
0349         if (!public_base_classes(missingDictionaries, baseType, baseTypes)) {
0350           returnValue = false;
0351           continue;
0352         }
0353       }
0354       // For now just ignore it if the class appears twice,
0355       // After some more testing we may decide to uncomment the following
0356       // exception.
0357       //
0358       //else {
0359       //  throw Exception(errors::UnimplementedFeature)
0360       //    << "DataFormats/Common/src/DictionaryTools.cc in function public_base_classes.\n"
0361       //    << "Encountered class that has a public base class that appears\n"
0362       //    << "multiple times in its inheritance heirarchy.\n"
0363       //    << "Please contact the EDM Framework group with details about\n"
0364       //    << "this exception. It was our hope that this complicated situation\n"
0365       //    << "would not occur. There are three possible solutions. 1. Change\n"
0366       //    << "the class design so the public base class does not appear multiple\n"
0367       //    << "times in the inheritance heirarchy. In many cases, this is a\n"
0368       //    << "sign of bad design. 2. Modify the code that supports Views to\n"
0369       //    << "ignore these base classes, but not supply support for creating a\n"
0370       //    << "View of this base class. 3. Improve the View infrastructure to\n"
0371       //    << "deal with this case. Class name of base class: " << baseType.Name() << "\n\n";
0372       //}
0373     }
0374     return returnValue;
0375   }
0376 
0377 }  // namespace edm