CMS 3D CMS Logo

CMSSW_4_4_3_patch1/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 "Reflex/Base.h"
00005 #include "Reflex/TypeTemplate.h"
00006 
00007 using namespace ROOT::Reflex;
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 ROOT::Reflex::Member & mem, 
00024                   const ROOT::Reflex::Type   & 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.TypeOf().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.DeclaringType().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         Type t = mem.TypeOf();
00047         std::vector<AnyMethodArgument> tmpFixups;
00048         for (size_t i = 0; i < args.size(); ++i) { 
00049             std::pair<AnyMethodArgument,int> fixup = boost::apply_visitor( reco::parser::AnyMethodArgumentFixup(t.FunctionParameterAt(i)), args[i] );
00050             //std::cerr << "\t ARG " << i << " type is " << t.FunctionParameterAt(i).Name() << " conversion = " << fixup.second << std::endl; 
00051             if (fixup.second >= 0) { 
00052                 tmpFixups.push_back(fixup.first);
00053                 casts += fixup.second;
00054             } else { 
00055                 return -1*parser::kWrongArgumentType;
00056             }
00057         }
00058         fixuppedArgs.swap(tmpFixups);
00059     }
00060     /*std::cerr << "\nMETHOD " << mem.Name() << " of " << mem.DeclaringType().Name() 
00061         << ", min #args = " << minArgs << ", max #args = " << maxArgs 
00062         << ", args = " << args.size() << " fixupped args = " << fixuppedArgs.size() << "(" << casts << " implicit casts)" << std::endl; */
00063     return casts;
00064   }
00065 
00066   pair<Member, bool> findMethod(const Type & t, 
00067                                 const string & name, 
00068                                 const std::vector<AnyMethodArgument> &args, 
00069                                 std::vector<AnyMethodArgument> &fixuppedArgs,
00070                                 const char* iIterator, 
00071                                 int& oError) {
00072      oError = parser::kNameDoesNotExist;
00073     Type type = t; 
00074     if (! type)  
00075       throw parser::Exception(iIterator)
00076         << "No dictionary for class \"" << type.Name() << "\".";
00077     while(type.IsPointer() || type.IsTypedef()) type = type.ToType();
00078     type = Type(type,0); // strip const, volatile, c++ ref, ..
00079 
00080     pair<Member, bool> mem; mem.second = false;
00081 
00082     // suitable members and number of integer->real casts required to get them
00083     vector<pair<int,Member> > oks;
00084 
00085     // first look in base scope
00086     for(Member_Iterator m = type.FunctionMember_Begin(); m != type.FunctionMember_End(); ++m ) {
00087       if(m->Name()==name) {
00088         int casts = checkMethod(*m, type, args, fixuppedArgs);
00089         if (casts > -1) {
00090             oks.push_back( make_pair(casts,*m) );
00091         } else {
00092            oError = -1*casts;
00093            //is this a show stopper error?
00094            if(fatalErrorCondition(oError)) {
00095               return mem;
00096            }
00097         }
00098       }
00099     }
00100     //std::cout << "At base scope (type " << (type.Name()) << ") found " << oks.size() << " methods." << std::endl; 
00101     // found at least one method
00102     if (!oks.empty()) {
00103         if (oks.size() > 1) {
00104             // sort by number of conversiosns needed
00105             sort(oks.begin(), oks.end());
00106 
00107             if (oks[0].first == oks[1].first) { // two methods with same ambiguity
00108                 throw parser::Exception(iIterator)
00109                     << "Can't resolve method \"" << name << "\" for class \"" << type.Name() << "\", the two candidates " 
00110                     << oks[0].second.Name() << " and " << oks[1].second.Name() 
00111                     << " require the same number of integer->real conversions (" << oks[0].first << ").";        
00112             }
00113 
00114             // I should fixup again the args, as both good methods have pushed them on fixuppedArgs
00115             fixuppedArgs.clear();
00116             checkMethod(oks.front().second, type, args, fixuppedArgs);
00117         } 
00118         mem.first = oks.front().second;
00119     }
00120 
00121     // if nothing was found, look in parent scopes (without checking for cross-scope overloading, as it's not allowed)
00122     int baseError=parser::kNameDoesNotExist;
00123     if(! mem.first) {
00124       for(Base_Iterator b = type.Base_Begin(); b != type.Base_End(); ++ b) {
00125               if((mem = findMethod(b->ToType(), name, args, fixuppedArgs,iIterator,baseError)).first) break;
00126               if(fatalErrorCondition(baseError)) {
00127             oError = baseError;
00128             return mem;
00129               }
00130       }
00131     }
00132 
00133     // otherwise see if this object is just a Ref or Ptr and we should pop it out
00134     if(!mem.first) {
00135       // check for edm::Ref or edm::RefToBase or edm::Ptr
00136       // std::cout << "Mem.first is null, so looking for templates from type " << type.Name() << std::endl;
00137       if(type.IsTemplateInstance()) {
00138          TypeTemplate templ = type.TemplateFamily();
00139          std::string name = templ.Name();
00140          if(name.compare("Ref") == 0 ||
00141             name.compare("RefToBase") == 0 ||
00142             name.compare("Ptr") == 0) {
00143           // in this case  i think 'get' should be taken with no arguments!
00144           std::vector<AnyMethodArgument> empty, empty2; 
00145           int error;
00146           mem = findMethod(type, "get", empty, empty2,iIterator,error);
00147           if(!mem.first) {
00148              throw parser::Exception(iIterator)
00149                 << "No member \"get\" in reference of type \"" << type.Name() << "\".";        
00150           }
00151           mem.second = true;
00152          }
00153       }
00154     }
00155     /*
00156     if(!mem.first) {
00157       throw edm::Exception(edm::errors::Configuration)
00158         << "member \""" << name << "\"" not found in class \""  << type.Name() << "\"";        
00159     }
00160     */
00161     if(mem.first) {
00162        oError = parser::kNoError;
00163     } else {
00164        //use error from base check if we never found function in primary class
00165        if(oError == parser::kNameDoesNotExist) {
00166           oError = baseError;
00167        }
00168     }
00169     return mem;
00170   }
00171 }