Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:01:19

0001 #include "CommonTools/Utils/src/findMethod.h"
0002 
0003 #include "CommonTools/Utils/src/ErrorCodes.h"
0004 #include "CommonTools/Utils/interface/parser/Exception.h"
0005 #include "FWCore/Reflection/interface/BaseWithDict.h"
0006 #include "FWCore/Reflection/interface/TypeWithDict.h"
0007 #include "FWCore/Utilities/interface/TypeID.h"
0008 
0009 #include <typeindex>
0010 #include <cassert>
0011 
0012 using AnyMethodArgument = reco::parser::AnyMethodArgument;
0013 
0014 /// Checks for errors which show we got the correct function
0015 /// but we cannot use it.
0016 static bool fatalErrorCondition(const int err) {
0017   return (err == reco::parser::kIsNotPublic) || (err == reco::parser::kIsStatic) ||
0018          (err == reco::parser::kIsFunctionAddedByROOT) || (err == reco::parser::kIsConstructor) ||
0019          (err == reco::parser::kIsDestructor) || (err == reco::parser::kIsOperator);
0020 }
0021 
0022 namespace reco {
0023 
0024   int checkMethod(const edm::FunctionWithDict& mem,
0025                   const edm::TypeWithDict& type,
0026                   const std::vector<AnyMethodArgument>& args,
0027                   std::vector<AnyMethodArgument>& fixuppedArgs) {
0028     int casts = 0;
0029     if (mem.isConstructor()) {
0030       return -1 * parser::kIsConstructor;
0031     }
0032     if (mem.isDestructor()) {
0033       return -1 * parser::kIsDestructor;
0034     }
0035     // Some operators are allowed, e.g. operator[].
0036     //if (mem.isOperator()) {
0037     //  return -1 * parser::kIsOperator;
0038     //}
0039     if (!mem.isPublic()) {
0040       return -1 * parser::kIsNotPublic;
0041     }
0042     if (mem.isStatic()) {
0043       return -1 * parser::kIsStatic;
0044     }
0045     if (!mem.isConst()) {
0046       return -1 * parser::kIsNotConst;
0047     }
0048     if (mem.name().substr(0, 2) == "__") {
0049       return -1 * parser::kIsFunctionAddedByROOT;
0050     }
0051     // Functions from a base class are allowed.
0052     //if (mem.declaringType() != type) {
0053     //std::cerr <<
0054     //  "\nMETHOD OVERLOAD " <<
0055     //  mem.name() <<
0056     //  " by " <<
0057     //  type.qualifiedName() <<
0058     //  " from " <<
0059     //  mem.declaringType().qualifiedName() <<
0060     //  std::endl;
0061     //return -1 * parser::kOverloaded;
0062     //}
0063 
0064     size_t minArgs = mem.functionParameterSize(true);
0065     size_t maxArgs = mem.functionParameterSize(false);
0066     if ((args.size() < minArgs) || (args.size() > maxArgs)) {
0067       return -1 * parser::kWrongNumberOfArguments;
0068     }
0069     //std::cerr <<
0070     //  "\nMETHOD " <<
0071     //  mem.name() <<
0072     //  " of " <<
0073     //  mem.declaringType().name() <<
0074     //  ", min #args = " <<
0075     //  minArgs <<
0076     //  ", max #args = " <<
0077     //  maxArgs <<
0078     //  ", args = " <<
0079     //  args.size() <<
0080     //  std::endl;
0081     if (!args.empty()) {
0082       std::vector<AnyMethodArgument> tmpFixups;
0083       size_t i = 0;
0084       for (auto const& param : mem) {
0085         edm::TypeWithDict parameter(param);
0086         std::pair<AnyMethodArgument, int> fixup = std::visit(reco::parser::AnyMethodArgumentFixup(parameter), args[i]);
0087         //std::cerr <<
0088         //  "\t ARG " <<
0089         //  i <<
0090         //  " type is " <<
0091         //  parameter.name() <<
0092         //  " conversion = " <<
0093         //  fixup.second <<
0094         //  std::endl;
0095         if (fixup.second >= 0) {
0096           tmpFixups.push_back(fixup.first);
0097           casts += fixup.second;
0098         } else {
0099           return -1 * parser::kWrongArgumentType;
0100         }
0101         if (++i == args.size()) {
0102           break;
0103         }
0104       }
0105       fixuppedArgs.swap(tmpFixups);
0106     }
0107     //std::cerr <<
0108     //  "\nMETHOD " <<
0109     //  mem.name() <<
0110     //  " of " <<
0111     //  mem.declaringType().name() <<
0112     //  ", min #args = " <<
0113     //  minArgs <<
0114     //  ", max #args = " <<
0115     //  maxArgs <<
0116     //  ", args = " <<
0117     //  args.size() <<
0118     //  " fixupped args = " <<
0119     //  fixuppedArgs.size() <<
0120     //  "(" << casts <<
0121     //  " implicit casts)" <<
0122     //  std::endl;
0123     return casts;
0124   }
0125 
0126   typedef std::pair<int, edm::FunctionWithDict> OK;
0127 
0128   bool nCasts(const OK& a, const OK& b) { return a.first < b.first; }
0129 
0130   std::pair<edm::FunctionWithDict, bool> findMethod(const edm::TypeWithDict& t, /*class=in*/
0131                                                     const std::string& name,    /*function member name=in*/
0132                                                     const std::vector<AnyMethodArgument>& args,   /*args=in*/
0133                                                     std::vector<AnyMethodArgument>& fixuppedArgs, /*args=out*/
0134                                                     const char* iIterator,                        /*???=out*/
0135                                                     int& oError)                                  /*err code=out*/
0136   {
0137     oError = parser::kNameDoesNotExist;
0138     edm::TypeWithDict type = t;
0139     if (!bool(type)) {
0140       throw parser::Exception(iIterator) << "No dictionary for class \"" << type.name() << "\".";
0141     }
0142     while (type.isPointer() || type.isReference()) {
0143       type = type.toType();
0144     }
0145     while (type.isTypedef()) {
0146       edm::TypeWithDict theType = type.finalType();
0147       if (theType == type) {
0148         break;
0149       }
0150       type = theType;
0151     }
0152     // strip const, volatile, c++ ref, ..
0153     type = type.stripConstRef();
0154     // Create our return value.
0155     std::pair<edm::FunctionWithDict, bool> mem;
0156     //FIXME: We must initialize mem.first!
0157     mem.second = false;
0158     // suitable members and number of integer->real casts required to get them
0159     std::vector<std::pair<int, edm::FunctionWithDict> > oks;
0160     std::string theArgs;
0161     for (auto const& item : args) {
0162       if (!theArgs.empty()) {
0163         theArgs += ',';
0164       }
0165       theArgs += edm::TypeID(std::visit([](auto& variant) -> const std::type_info& { return typeid(variant); }, item))
0166                      .className();
0167     }
0168     edm::FunctionWithDict f = type.functionMemberByName(name, theArgs, true);
0169     if (bool(f)) {
0170       int casts = checkMethod(f, type, args, fixuppedArgs);
0171       if (casts > -1) {
0172         oks.push_back(std::make_pair(casts, f));
0173       } else {
0174         oError = -1 * casts;
0175         //is this a show stopper error?
0176         if (fatalErrorCondition(oError)) {
0177           return mem;
0178         }
0179       }
0180     } else {
0181       edm::TypeFunctionMembers functions(type);
0182       for (auto const& F : functions) {
0183         if (std::string(F->GetName()) != name) {
0184           continue;
0185         }
0186         edm::FunctionWithDict f(F);
0187         int casts = checkMethod(f, type, args, fixuppedArgs);
0188         if (casts > -1) {
0189           oks.push_back(std::make_pair(casts, f));
0190         } else {
0191           oError = -1 * casts;
0192           //is this a show stopper error?
0193           if (fatalErrorCondition(oError)) {
0194             return mem;
0195           }
0196         }
0197       }
0198     }
0199     //std::cout << "At base scope (type " << (type.name()) << ") found " <<
0200     //  oks.size() << " methods." << std::endl;
0201     // found at least one method
0202     if (!oks.empty()) {
0203       if (oks.size() > 1) {
0204         // sort by number of conversions needed
0205         sort(oks.begin(), oks.end(), nCasts);
0206         if (oks[0].first == oks[1].first) {  // two methods with same ambiguity
0207           throw parser::Exception(iIterator)
0208               << "Can't resolve method \"" << name << "\" for class \"" << type.name() << "\", the two candidates "
0209               << oks[0].second.name() << " and " << oks[1].second.name()
0210               << " require the same number of integer->real conversions (" << oks[0].first << ").";
0211         }
0212         // We must fixup the args again, as both good methods
0213         // have pushed them on fixuppedArgs.
0214         fixuppedArgs.clear();
0215         checkMethod(oks.front().second, type, args, fixuppedArgs);
0216       }
0217       mem.first = oks.front().second;
0218     }
0219     // if nothing was found, look in parent scopes without
0220     // checking for cross-scope overloading, as it is not
0221     // allowed
0222     int baseError = parser::kNameDoesNotExist;
0223     if (!bool(mem.first)) {
0224       edm::TypeBases bases(type);
0225       for (auto const& B : bases) {
0226         mem = findMethod(edm::BaseWithDict(B).typeOf(), name, args, fixuppedArgs, iIterator, baseError);
0227         if (bool(mem.first)) {
0228           break;
0229         }
0230         if (fatalErrorCondition(baseError)) {
0231           oError = baseError;
0232           return mem;
0233         }
0234       }
0235     }
0236     // otherwise see if this object is just a Ref or Ptr and we should pop it out
0237     if (!bool(mem.first)) {
0238       // check for edm::Ref or edm::RefToBase or edm::Ptr
0239       if (type.isTemplateInstance()) {
0240         std::string name = type.templateName();
0241         if (!name.compare("edm::Ref") || !name.compare("edm::RefToBase") || !name.compare("edm::Ptr")) {
0242           // in this case  i think 'get' should be taken with no arguments!
0243           std::vector<AnyMethodArgument> empty;
0244           std::vector<AnyMethodArgument> empty2;
0245           int error = 0;
0246           mem = findMethod(type, "get", empty, empty2, iIterator, error);
0247           if (!bool(mem.first)) {
0248             throw parser::Exception(iIterator) << "No member \"get\" in reference of type \"" << type.name() << "\".";
0249           }
0250           mem.second = true;
0251         }
0252       }
0253     }
0254     //if (!bool(mem.first)) {
0255     //  throw edm::Exception(edm::errors::Configuration) << "member \""" <<
0256     //        name << "\"" not found in class \""  << type.name() << "\"";
0257     //}
0258     if (bool(mem.first)) {
0259       oError = parser::kNoError;
0260     } else {
0261       // use error from base check if we never found function in primary class
0262       if (oError == parser::kNameDoesNotExist) {
0263         oError = baseError;
0264       }
0265     }
0266     return mem;
0267   }
0268 
0269 }  // namespace reco