CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/CommonTools/Utils/src/findMethod.cc

Go to the documentation of this file.
00001 #include "CommonTools/Utils/src/findMethod.h"
00002 #include "CommonTools/Utils/src/ErrorCodes.h"
00003 #include "CommonTools/Utils/interface/Exception.h"
00004 #include "FWCore/Utilities/interface/BaseWithDict.h"
00005 #include "FWCore/Utilities/interface/TypeWithDict.h"
00006 #include <cassert>
00007 
00008 using namespace std;
00009 using reco::parser::AnyMethodArgument;
00010 
00011 //Checks for errors which show we got the correct function be we just can't use it
00012 static bool fatalErrorCondition(int iError)
00013 {
00014    return (reco::parser::kIsNotPublic==iError ||
00015       reco::parser::kIsStatic==iError ||
00016       reco::parser::kIsFunctionAddedByROOT==iError ||
00017       reco::parser::kIsConstructor==iError ||
00018       reco::parser::kIsDestructor==iError ||
00019       reco::parser::kIsOperator==iError);
00020    
00021 }
00022 namespace reco {
00023   int checkMethod(const edm::FunctionWithDict & mem, 
00024                   const edm::TypeWithDict   & type,
00025                   const std::vector<AnyMethodArgument> &args, std::vector<AnyMethodArgument> &fixuppedArgs) {
00026     int casts = 0;
00027     if (mem.isConstructor()) return -1*parser::kIsConstructor;
00028     if (mem.isDestructor()) return -1*parser::kIsDestructor;
00029     //if (mem.isOperator()) return -1*parser::kIsOperator;  // no, some operators are allowed, e.g. operator[]
00030     if (! mem.isPublic()) return -1*parser::kIsNotPublic;
00031     if (mem.isStatic()) return -1*parser::kIsStatic;
00032     if ( ! mem.isConst() ) return -1*parser::kIsNotConst;
00033     if (mem.name().substr(0, 2) == "__") return -1*parser::kIsFunctionAddedByROOT;
00034     if (mem.declaringType().id() != type.id()) {
00035         /*std::cerr << "\nMETHOD OVERLOAD " << mem.name() <<
00036                        " by "   << type.Name(QUALITIED|SCOPED) <<
00037                        " from " << mem.declaringTy[e().Name(QUALIFIED|SCOPED) << std::endl; */
00038         return -1*parser::kOverloaded;
00039     }
00040     size_t minArgs = mem.functionParameterSize(true), maxArgs = mem.functionParameterSize(false);
00041     if ((args.size() < minArgs) || (args.size() > maxArgs)) return -1*parser::kWrongNumberOfArguments;
00042     /*std::cerr << "\nMETHOD " << mem.name() << " of " << mem.declaringType().name() 
00043         << ", min #args = " << minArgs << ", max #args = " << maxArgs 
00044         << ", args = " << args.size() << std::endl;*/
00045     if (!args.empty()) {
00046         std::vector<AnyMethodArgument> tmpFixups;
00047         size_t i = 0;
00048         for (auto const& param : mem) { 
00049             edm::TypeWithDict parameter(param);
00050             std::pair<AnyMethodArgument,int> fixup = boost::apply_visitor( reco::parser::AnyMethodArgumentFixup(parameter), args[i] );
00051             //std::cerr << "\t ARG " << i << " type is " << parameter.name() << " conversion = " << fixup.second << std::endl; 
00052             if (fixup.second >= 0) { 
00053                 tmpFixups.push_back(fixup.first);
00054                 casts += fixup.second;
00055             } else { 
00056                 return -1*parser::kWrongArgumentType;
00057             }
00058             if(++i == args.size()) {
00059               break;
00060             }
00061         }
00062         fixuppedArgs.swap(tmpFixups);
00063     }
00064     /*std::cerr << "\nMETHOD " << mem.name() << " of " << mem.declaringType().name() 
00065         << ", min #args = " << minArgs << ", max #args = " << maxArgs 
00066         << ", args = " << args.size() << " fixupped args = " << fixuppedArgs.size() << "(" << casts << " implicit casts)" << std::endl; */
00067     return casts;
00068   }
00069 
00070   typedef pair<int,edm::FunctionWithDict> OK;
00071   bool nCasts(OK const& a, OK const& b) {
00072     return a.first < b.first;
00073   }
00074 
00075 
00076   pair<edm::FunctionWithDict, bool> findMethod(const edm::TypeWithDict & t, 
00077                                 const string & name, 
00078                                 const std::vector<AnyMethodArgument> &args, 
00079                                 std::vector<AnyMethodArgument> &fixuppedArgs,
00080                                 const char* iIterator, 
00081                                 int& oError) {
00082      oError = parser::kNameDoesNotExist;
00083     edm::TypeWithDict type = t; 
00084     if (! type)  
00085       throw parser::Exception(iIterator)
00086         << "No dictionary for class \"" << type.name() << "\".";
00087     while(type.isPointer() || type.isTypedef()) type = type.toType();
00088     type = edm::TypeWithDict(type, 0L); // strip const, volatile, c++ ref, ..
00089 
00090     pair<edm::FunctionWithDict, bool> mem; mem.second = false;
00091 
00092     // suitable members and number of integer->real casts required to get them
00093     vector<pair<int,edm::FunctionWithDict> > oks;
00094 
00095     // first look in base scope
00096     edm::TypeFunctionMembers functions(type);
00097     for(auto const& function : functions) {
00098       edm::FunctionWithDict m(function);
00099       if(m.name()==name) {
00100         int casts = checkMethod(m, type, args, fixuppedArgs);
00101         if (casts > -1) {
00102             oks.push_back( make_pair(casts,m) );
00103         } else {
00104            oError = -1*casts;
00105            //is this a show stopper error?
00106            if(fatalErrorCondition(oError)) {
00107               return mem;
00108            }
00109         }
00110       }
00111     }
00112     //std::cout << "At base scope (type " << (type.name()) << ") found " << oks.size() << " methods." << std::endl; 
00113     // found at least one method
00114     if (!oks.empty()) {
00115         if (oks.size() > 1) {
00116             // sort by number of conversions needed
00117             sort(oks.begin(), oks.end(), nCasts);
00118 
00119             if (oks[0].first == oks[1].first) { // two methods with same ambiguity
00120                 throw parser::Exception(iIterator)
00121                     << "Can't resolve method \"" << name << "\" for class \"" << type.name() << "\", the two candidates " 
00122                     << oks[0].second.name() << " and " << oks[1].second.name() 
00123                     << " require the same number of integer->real conversions (" << oks[0].first << ").";        
00124             }
00125 
00126             // I should fixup again the args, as both good methods have pushed them on fixuppedArgs
00127             fixuppedArgs.clear();
00128             checkMethod(oks.front().second, type, args, fixuppedArgs);
00129         } 
00130         mem.first = oks.front().second;
00131     }
00132 
00133     // if nothing was found, look in parent scopes (without checking for cross-scope overloading, as it's not allowed)
00134     int baseError=parser::kNameDoesNotExist;
00135     if(! mem.first) {
00136       edm::TypeBases bases(type);
00137       for(auto const& base : bases) {
00138               if((mem = findMethod(edm::BaseWithDict(base).typeOf(), name, args, fixuppedArgs,iIterator,baseError)).first) break;
00139               if(fatalErrorCondition(baseError)) {
00140             oError = baseError;
00141             return mem;
00142               }
00143       }
00144     }
00145 
00146     // otherwise see if this object is just a Ref or Ptr and we should pop it out
00147     if(!mem.first) {
00148       // check for edm::Ref or edm::RefToBase or edm::Ptr
00149       // std::cout << "Mem.first is null, so looking for templates from type " << type.name() << std::endl;
00150       if(type.isTemplateInstance()) {
00151          std::string name = type.templateName();
00152          if(name.compare("edm::Ref") == 0 ||
00153             name.compare("edm::RefToBase") == 0 ||
00154             name.compare("edm::Ptr") == 0) {
00155           // in this case  i think 'get' should be taken with no arguments!
00156           std::vector<AnyMethodArgument> empty, empty2; 
00157           int error;
00158           mem = findMethod(type, "get", empty, empty2,iIterator,error);
00159           if(!mem.first) {
00160              throw parser::Exception(iIterator)
00161                 << "No member \"get\" in reference of type \"" << type.name() << "\".";        
00162           }
00163           mem.second = true;
00164          }
00165       }
00166     }
00167     /*
00168     if(!mem.first) {
00169       throw edm::Exception(edm::errors::Configuration)
00170         << "member \""" << name << "\"" not found in class \""  << type.name() << "\"";        
00171     }
00172     */
00173     if(mem.first) {
00174        oError = parser::kNoError;
00175     } else {
00176        //use error from base check if we never found function in primary class
00177        if(oError == parser::kNameDoesNotExist) {
00178           oError = baseError;
00179        }
00180     }
00181     return mem;
00182   }
00183 }