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
0015
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
0036
0037
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
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
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
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
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
0088
0089
0090
0091
0092
0093
0094
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
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
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,
0131 const std::string& name,
0132 const std::vector<AnyMethodArgument>& args,
0133 std::vector<AnyMethodArgument>& fixuppedArgs,
0134 const char* iIterator,
0135 int& oError)
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
0153 type = type.stripConstRef();
0154
0155 std::pair<edm::FunctionWithDict, bool> mem;
0156
0157 mem.second = false;
0158
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
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
0193 if (fatalErrorCondition(oError)) {
0194 return mem;
0195 }
0196 }
0197 }
0198 }
0199
0200
0201
0202 if (!oks.empty()) {
0203 if (oks.size() > 1) {
0204
0205 sort(oks.begin(), oks.end(), nCasts);
0206 if (oks[0].first == oks[1].first) {
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
0213
0214 fixuppedArgs.clear();
0215 checkMethod(oks.front().second, type, args, fixuppedArgs);
0216 }
0217 mem.first = oks.front().second;
0218 }
0219
0220
0221
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
0237 if (!bool(mem.first)) {
0238
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
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
0255
0256
0257
0258 if (bool(mem.first)) {
0259 oError = parser::kNoError;
0260 } else {
0261
0262 if (oError == parser::kNameDoesNotExist) {
0263 oError = baseError;
0264 }
0265 }
0266 return mem;
0267 }
0268
0269 }