/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
CommonTools/Utils/src/findMethod.cc
269 строк
9 KB
Christopher Jones
Move parser related headers to interface subdirectory
21 июл 2023, 16:43
21 июл 2023, 16:43
c1ad033
Код
Авторство
О чём код?
#include "CommonTools/Utils/src/findMethod.h" #include "CommonTools/Utils/src/ErrorCodes.h" #include "CommonTools/Utils/interface/parser/Exception.h" #include "FWCore/Reflection/interface/BaseWithDict.h" #include "FWCore/Reflection/interface/TypeWithDict.h" #include "FWCore/Utilities/interface/TypeID.h" #include <typeindex> #include <cassert> using AnyMethodArgument = reco::parser::AnyMethodArgument; /// Checks for errors which show we got the correct function /// but we cannot use it. static bool fatalErrorCondition(const int err) { return (err == reco::parser::kIsNotPublic) || (err == reco::parser::kIsStatic) || (err == reco::parser::kIsFunctionAddedByROOT) || (err == reco::parser::kIsConstructor) || (err == reco::parser::kIsDestructor) || (err == reco::parser::kIsOperator); } namespace reco { int checkMethod(const edm::FunctionWithDict& mem, const edm::TypeWithDict& type, const std::vector<AnyMethodArgument>& args, std::vector<AnyMethodArgument>& fixuppedArgs) { int casts = 0; if (mem.isConstructor()) { return -1 * parser::kIsConstructor; } if (mem.isDestructor()) { return -1 * parser::kIsDestructor; } // Some operators are allowed, e.g. operator[]. //if (mem.isOperator()) { // return -1 * parser::kIsOperator; //} if (!mem.isPublic()) { return -1 * parser::kIsNotPublic; } if (mem.isStatic()) { return -1 * parser::kIsStatic; } if (!mem.isConst()) { return -1 * parser::kIsNotConst; } if (mem.name().substr(0, 2) == "__") { return -1 * parser::kIsFunctionAddedByROOT; } // Functions from a base class are allowed. //if (mem.declaringType() != type) { //std::cerr << // "\nMETHOD OVERLOAD " << // mem.name() << // " by " << // type.qualifiedName() << // " from " << // mem.declaringType().qualifiedName() << // std::endl; //return -1 * parser::kOverloaded; //} size_t minArgs = mem.functionParameterSize(true); size_t maxArgs = mem.functionParameterSize(false); if ((args.size() < minArgs) || (args.size() > maxArgs)) { return -1 * parser::kWrongNumberOfArguments; } //std::cerr << // "\nMETHOD " << // mem.name() << // " of " << // mem.declaringType().name() << // ", min #args = " << // minArgs << // ", max #args = " << // maxArgs << // ", args = " << // args.size() << // std::endl; if (!args.empty()) { std::vector<AnyMethodArgument> tmpFixups; size_t i = 0; for (auto const& param : mem) { edm::TypeWithDict parameter(param); std::pair<AnyMethodArgument, int> fixup = std::visit(reco::parser::AnyMethodArgumentFixup(parameter), args[i]); //std::cerr << // "\t ARG " << // i << // " type is " << // parameter.name() << // " conversion = " << // fixup.second << // std::endl; if (fixup.second >= 0) { tmpFixups.push_back(fixup.first); casts += fixup.second; } else { return -1 * parser::kWrongArgumentType; } if (++i == args.size()) { break; } } fixuppedArgs.swap(tmpFixups); } //std::cerr << // "\nMETHOD " << // mem.name() << // " of " << // mem.declaringType().name() << // ", min #args = " << // minArgs << // ", max #args = " << // maxArgs << // ", args = " << // args.size() << // " fixupped args = " << // fixuppedArgs.size() << // "(" << casts << // " implicit casts)" << // std::endl; return casts; } typedef std::pair<int, edm::FunctionWithDict> OK; bool nCasts(const OK& a, const OK& b) { return a.first < b.first; } std::pair<edm::FunctionWithDict, bool> findMethod(const edm::TypeWithDict& t, /*class=in*/ const std::string& name, /*function member name=in*/ const std::vector<AnyMethodArgument>& args, /*args=in*/ std::vector<AnyMethodArgument>& fixuppedArgs, /*args=out*/ const char* iIterator, /*???=out*/ int& oError) /*err code=out*/ { oError = parser::kNameDoesNotExist; edm::TypeWithDict type = t; if (!bool(type)) { throw parser::Exception(iIterator) << "No dictionary for class \"" << type.name() << "\"."; } while (type.isPointer() || type.isReference()) { type = type.toType(); } while (type.isTypedef()) { edm::TypeWithDict theType = type.finalType(); if (theType == type) { break; } type = theType; } // strip const, volatile, c++ ref, .. type = type.stripConstRef(); // Create our return value. std::pair<edm::FunctionWithDict, bool> mem; //FIXME: We must initialize mem.first! mem.second = false; // suitable members and number of integer->real casts required to get them std::vector<std::pair<int, edm::FunctionWithDict> > oks; std::string theArgs; for (auto const& item : args) { if (!theArgs.empty()) { theArgs += ','; } theArgs += edm::TypeID(std::visit([](auto& variant) -> const std::type_info& { return typeid(variant); }, item)) .className(); } edm::FunctionWithDict f = type.functionMemberByName(name, theArgs, true); if (bool(f)) { int casts = checkMethod(f, type, args, fixuppedArgs); if (casts > -1) { oks.push_back(std::make_pair(casts, f)); } else { oError = -1 * casts; //is this a show stopper error? if (fatalErrorCondition(oError)) { return mem; } } } else { edm::TypeFunctionMembers functions(type); for (auto const& F : functions) { if (std::string(F->GetName()) != name) { continue; } edm::FunctionWithDict f(F); int casts = checkMethod(f, type, args, fixuppedArgs); if (casts > -1) { oks.push_back(std::make_pair(casts, f)); } else { oError = -1 * casts; //is this a show stopper error? if (fatalErrorCondition(oError)) { return mem; } } } } //std::cout << "At base scope (type " << (type.name()) << ") found " << // oks.size() << " methods." << std::endl; // found at least one method if (!oks.empty()) { if (oks.size() > 1) { // sort by number of conversions needed sort(oks.begin(), oks.end(), nCasts); if (oks[0].first == oks[1].first) { // two methods with same ambiguity throw parser::Exception(iIterator) << "Can't resolve method \"" << name << "\" for class \"" << type.name() << "\", the two candidates " << oks[0].second.name() << " and " << oks[1].second.name() << " require the same number of integer->real conversions (" << oks[0].first << ")."; } // We must fixup the args again, as both good methods // have pushed them on fixuppedArgs. fixuppedArgs.clear(); checkMethod(oks.front().second, type, args, fixuppedArgs); } mem.first = oks.front().second; } // if nothing was found, look in parent scopes without // checking for cross-scope overloading, as it is not // allowed int baseError = parser::kNameDoesNotExist; if (!bool(mem.first)) { edm::TypeBases bases(type); for (auto const& B : bases) { mem = findMethod(edm::BaseWithDict(B).typeOf(), name, args, fixuppedArgs, iIterator, baseError); if (bool(mem.first)) { break; } if (fatalErrorCondition(baseError)) { oError = baseError; return mem; } } } // otherwise see if this object is just a Ref or Ptr and we should pop it out if (!bool(mem.first)) { // check for edm::Ref or edm::RefToBase or edm::Ptr if (type.isTemplateInstance()) { std::string name = type.templateName(); if (!name.compare("edm::Ref") || !name.compare("edm::RefToBase") || !name.compare("edm::Ptr")) { // in this case i think 'get' should be taken with no arguments! std::vector<AnyMethodArgument> empty; std::vector<AnyMethodArgument> empty2; int error = 0; mem = findMethod(type, "get", empty, empty2, iIterator, error); if (!bool(mem.first)) { throw parser::Exception(iIterator) << "No member \"get\" in reference of type \"" << type.name() << "\"."; } mem.second = true; } } } //if (!bool(mem.first)) { // throw edm::Exception(edm::errors::Configuration) << "member \""" << // name << "\"" not found in class \"" << type.name() << "\""; //} if (bool(mem.first)) { oError = parser::kNoError; } else { // use error from base check if we never found function in primary class if (oError == parser::kNameDoesNotExist) { oError = baseError; } } return mem; } } // namespace reco