Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-06-12 23:39:57

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 "TClassEdit.h"
0061 #include "THashTable.h"
0062 
0063 #include <algorithm>
0064 #include <sstream>
0065 
0066 namespace edm {
0067 
0068   bool checkDictionary(std::vector<std::string>& missingDictionaries, TypeID const& typeID) {
0069     TClass::GetClass(typeID.typeInfo());
0070     if (!hasDictionary(typeID.typeInfo())) {
0071       // a second attempt to load
0072       TypeWithDict::byName(typeID.className());
0073     }
0074     if (!hasDictionary(typeID.typeInfo())) {
0075       missingDictionaries.emplace_back(typeID.className());
0076       return false;
0077     }
0078     return true;
0079   }
0080 
0081   bool checkDictionaryOfWrappedType(std::vector<std::string>& missingDictionaries, TypeID const& unwrappedTypeID) {
0082     std::string wrappedName = wrappedClassName(unwrappedTypeID.className());
0083     TypeWithDict wrappedTypeWithDict = TypeWithDict::byName(wrappedName);
0084     return checkDictionary(missingDictionaries, wrappedName, wrappedTypeWithDict);
0085   }
0086 
0087   bool checkDictionaryOfWrappedType(std::vector<std::string>& missingDictionaries, std::string const& unwrappedName) {
0088     std::string wrappedName = wrappedClassName(unwrappedName);
0089     TypeWithDict wrappedTypeWithDict = TypeWithDict::byName(wrappedName);
0090     return checkDictionary(missingDictionaries, wrappedName, wrappedTypeWithDict);
0091   }
0092 
0093   bool checkDictionary(std::vector<std::string>& missingDictionaries,
0094                        std::string const& name,
0095                        TypeWithDict const& typeWithDict) {
0096     if (!bool(typeWithDict) || typeWithDict.invalidTypeInfo()) {
0097       missingDictionaries.emplace_back(name);
0098       return false;
0099     }
0100     return true;
0101   }
0102 
0103   bool checkClassDictionaries(std::vector<std::string>& missingDictionaries, TypeID const& typeID) {
0104     // For a class type with a dictionary the TClass* will be
0105     // non-null and hasDictionary will return true.
0106     // For a type like "int", the TClass* pointer will be a
0107     // nullptr and hasDictionary will return true.
0108     // For a class type without a dictionary it is possible for
0109     // TClass* to be non-null and hasDictionary to return false.
0110 
0111     TClass* tClass = TClass::GetClass(typeID.typeInfo());
0112     if (!hasDictionary(typeID.typeInfo())) {
0113       // a second attempt to load
0114       TypeWithDict::byName(typeID.className());
0115       tClass = TClass::GetClass(typeID.typeInfo());
0116     }
0117     if (!hasDictionary(typeID.typeInfo())) {
0118       missingDictionaries.emplace_back(typeID.className());
0119       return false;
0120     }
0121 
0122     if (tClass == nullptr) {
0123       return true;
0124     }
0125 
0126     bool result = true;
0127 
0128     THashTable hashTable;
0129     bool recursive = true;
0130     tClass->GetMissingDictionaries(hashTable, recursive);
0131 
0132     for (auto const& item : hashTable) {
0133       TClass const* cl = static_cast<TClass const*>(item);
0134       missingDictionaries.emplace_back(cl->GetName());
0135       result = false;
0136     }
0137     return result;
0138   }
0139 
0140   bool checkClassDictionaries(std::vector<std::string>& missingDictionaries,
0141                               std::string const& name,
0142                               TypeWithDict const& typeWithDict) {
0143     if (!bool(typeWithDict) || typeWithDict.invalidTypeInfo()) {
0144       missingDictionaries.emplace_back(name);
0145       return false;
0146     }
0147 
0148     TClass* tClass = typeWithDict.getClass();
0149     if (tClass == nullptr) {
0150       missingDictionaries.emplace_back(name);
0151       return false;
0152     }
0153 
0154     THashTable hashTable;
0155     bool recursive = true;
0156     tClass->GetMissingDictionaries(hashTable, recursive);
0157 
0158     bool result = true;
0159 
0160     for (auto const& item : hashTable) {
0161       TClass const* cl = static_cast<TClass const*>(item);
0162       missingDictionaries.emplace_back(cl->GetName());
0163       result = false;
0164     }
0165     return result;
0166   }
0167 
0168   void addToMissingDictionariesException(edm::Exception& exception,
0169                                          std::vector<std::string>& missingDictionaries,
0170                                          std::string const& context) {
0171     std::sort(missingDictionaries.begin(), missingDictionaries.end());
0172     missingDictionaries.erase(std::unique(missingDictionaries.begin(), missingDictionaries.end()),
0173                               missingDictionaries.end());
0174 
0175     std::ostringstream ostr;
0176     for (auto const& item : missingDictionaries) {
0177       ostr << "  " << item << "\n";
0178     }
0179     exception << "No data dictionary found for the following classes:\n\n"
0180               << ostr.str() << "\n"
0181               << "Most likely each dictionary was never generated, but it may\n"
0182               << "be that it was generated in the wrong package. Please add\n"
0183               << "(or move) the specification \'<class name=\"whatever\"/>\' to\n"
0184               << "the appropriate classes_def.xml file along with any other\n"
0185               << "information needed there. For example, if this class has any\n"
0186               << "transient members, you need to specify them in classes_def.xml.\n"
0187               << "Also include the class header in classes.h\n";
0188 
0189     if (!context.empty()) {
0190       exception.addContext(context);
0191     }
0192   }
0193 
0194   void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries, std::string const& context) {
0195     std::vector<std::string> empty;
0196     throwMissingDictionariesException(missingDictionaries, context, empty);
0197   }
0198 
0199   void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
0200                                          std::string const& context,
0201                                          std::vector<std::string>& producedTypes) {
0202     edm::Exception exception(errors::DictionaryNotFound);
0203     addToMissingDictionariesException(exception, missingDictionaries, context);
0204 
0205     if (!producedTypes.empty()) {
0206       std::sort(producedTypes.begin(), producedTypes.end());
0207       producedTypes.erase(std::unique(producedTypes.begin(), producedTypes.end()), producedTypes.end());
0208 
0209       std::ostringstream ostr;
0210       for (auto const& item : producedTypes) {
0211         ostr << "  " << item << "\n";
0212       }
0213       exception << "\nA type listed above might or might not be the same as a\n"
0214                 << "type declared by a producer module with the function \'produces\'.\n"
0215                 << "Instead it might be the type of a data member, base class,\n"
0216                 << "wrapped type, or other object needed by a produced type. Below\n"
0217                 << "is some additional information which lists the types declared\n"
0218                 << "to be produced by a producer module that are associated with\n"
0219                 << "the types whose dictionaries were not found:\n\n"
0220                 << ostr.str() << "\n";
0221     }
0222     throw exception;
0223   }
0224 
0225   void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
0226                                          std::string const& context,
0227                                          std::vector<std::string>& producedTypes,
0228                                          std::vector<std::string>& branchNames,
0229                                          bool fromStreamerSource) {
0230     edm::Exception exception(errors::DictionaryNotFound);
0231     addToMissingDictionariesException(exception, missingDictionaries, context);
0232 
0233     if (!producedTypes.empty()) {
0234       std::sort(producedTypes.begin(), producedTypes.end());
0235       producedTypes.erase(std::unique(producedTypes.begin(), producedTypes.end()), producedTypes.end());
0236 
0237       std::ostringstream ostr;
0238       for (auto const& item : producedTypes) {
0239         ostr << "  " << item << "\n";
0240       }
0241       if (fromStreamerSource) {
0242         exception << "\nA type listed above might or might not be the same as a\n"
0243                   << "type stored in the Event. Instead it might be the type of\n"
0244                   << "a data member, base class, wrapped type, or other object\n"
0245                   << "needed by a stored type. Below is some additional information\n"
0246                   << "which lists the stored types associated with the types whose\n"
0247                   << "dictionaries were not found:\n\n"
0248                   << ostr.str() << "\n";
0249       } else {
0250         exception << "\nA type listed above might or might not be the same as a\n"
0251                   << "type stored in the Event (or Lumi or Run). Instead it might\n"
0252                   << "be the type of a data member, base class, wrapped type, or\n"
0253                   << "other object needed by a stored type. Below is some additional\n"
0254                   << "information which lists the stored types associated with the\n"
0255                   << "types whose dictionaries were not found:\n\n"
0256                   << ostr.str() << "\n";
0257       }
0258     }
0259 
0260     if (!branchNames.empty()) {
0261       std::sort(branchNames.begin(), branchNames.end());
0262       branchNames.erase(std::unique(branchNames.begin(), branchNames.end()), branchNames.end());
0263 
0264       std::ostringstream ostr;
0265       for (auto const& item : branchNames) {
0266         ostr << "  " << item << "\n";
0267       }
0268       if (fromStreamerSource) {
0269         exception << "Missing dictionaries are associated with these branch names:\n\n" << ostr.str() << "\n";
0270       } else {
0271         exception << "Missing dictionaries are associated with these branch names:\n\n"
0272                   << ostr.str() << "\n"
0273                   << "If you do not need these branches and they are not produced\n"
0274                   << "in the current process, an alternate solution to adding\n"
0275                   << "dictionaries is to drop these branches on input using the\n"
0276                   << "inputCommands parameter of the PoolSource.";
0277       }
0278     }
0279     throw exception;
0280   }
0281 
0282   void throwMissingDictionariesException(std::vector<std::string>& missingDictionaries,
0283                                          std::string const& context,
0284                                          std::set<std::string>& producedTypes,
0285                                          bool consumedWithView) {
0286     edm::Exception exception(errors::DictionaryNotFound);
0287     addToMissingDictionariesException(exception, missingDictionaries, context);
0288 
0289     if (!producedTypes.empty()) {
0290       std::ostringstream ostr;
0291       for (auto const& item : producedTypes) {
0292         ostr << "  " << item << "\n";
0293       }
0294       if (consumedWithView) {
0295         exception << "\nThe list of types above was generated while checking for\n"
0296                   << "dictionaries related to products declared to be consumed\n"
0297                   << "using a View. They will be either the type or a base class\n"
0298                   << "of the type declared in a consumes declaration as the template\n"
0299                   << "parameter of a View. Below is some additional information\n"
0300                   << "which lists the type of the template parameter of the View.\n"
0301                   << "(It will be the same type unless the missing dictionary is\n"
0302                   << "for a base type):\n\n"
0303                   << ostr.str() << "\n";
0304       } else {
0305         exception << "\nThe list of types above was generated while checking for\n"
0306                   << "dictionaries related to products declared to be consumed.\n"
0307                   << "A type listed above might or might not be a type declared\n"
0308                   << "to be consumed. Instead it might be the type of a data member,\n"
0309                   << "base class, wrapped type or other object needed by a consumed\n"
0310                   << "type.  Below is some additional information which lists\n"
0311                   << "the types declared to be consumed by a module and which\n"
0312                   << "are associated with the types whose dictionaries were not\n"
0313                   << "found:\n\n"
0314                   << ostr.str() << "\n";
0315       }
0316     }
0317     throw exception;
0318   }
0319 
0320   bool public_base_classes(std::vector<std::string>& missingDictionaries,
0321                            TypeID const& typeID,
0322                            std::vector<TypeID>& baseTypes) {
0323     if (!checkDictionary(missingDictionaries, typeID)) {
0324       return false;
0325     }
0326     TypeWithDict typeWithDict(typeID.typeInfo());
0327 
0328     if (!typeWithDict.isClass()) {
0329       return true;
0330     }
0331 
0332     // No need to check into base classes of standard library
0333     // classes.
0334     if (TClassEdit::IsStdClass(typeWithDict.name().c_str())) {
0335       return true;
0336     }
0337 
0338     TypeBases bases(typeWithDict);
0339     bool returnValue = true;
0340     for (auto const& basex : bases) {
0341       BaseWithDict base(basex);
0342       if (!base.isPublic()) {
0343         continue;
0344       }
0345       TypeWithDict baseRflxType = base.typeOf();
0346       if (!checkDictionary(missingDictionaries, baseRflxType.name(), baseRflxType)) {
0347         returnValue = false;
0348         continue;
0349       }
0350       TypeID baseType{baseRflxType.typeInfo()};
0351       // Check to make sure this base appears only once in the
0352       // inheritance hierarchy.
0353       if (!search_all(baseTypes, baseType)) {
0354         // Save the type and recursive look for its base types
0355         baseTypes.push_back(baseType);
0356         if (!public_base_classes(missingDictionaries, baseType, baseTypes)) {
0357           returnValue = false;
0358           continue;
0359         }
0360       }
0361       // For now just ignore it if the class appears twice,
0362       // After some more testing we may decide to uncomment the following
0363       // exception.
0364       //
0365       //else {
0366       //  throw Exception(errors::UnimplementedFeature)
0367       //    << "DataFormats/Common/src/DictionaryTools.cc in function public_base_classes.\n"
0368       //    << "Encountered class that has a public base class that appears\n"
0369       //    << "multiple times in its inheritance heirarchy.\n"
0370       //    << "Please contact the EDM Framework group with details about\n"
0371       //    << "this exception. It was our hope that this complicated situation\n"
0372       //    << "would not occur. There are three possible solutions. 1. Change\n"
0373       //    << "the class design so the public base class does not appear multiple\n"
0374       //    << "times in the inheritance heirarchy. In many cases, this is a\n"
0375       //    << "sign of bad design. 2. Modify the code that supports Views to\n"
0376       //    << "ignore these base classes, but not supply support for creating a\n"
0377       //    << "View of this base class. 3. Improve the View infrastructure to\n"
0378       //    << "deal with this case. Class name of base class: " << baseType.Name() << "\n\n";
0379       //}
0380     }
0381     return returnValue;
0382   }
0383 
0384 }  // namespace edm