Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
#include "CommonTools/Utils/interface/parser/MethodSetter.h"

#include "CommonTools/Utils/interface/parser/Exception.h"
#include "CommonTools/Utils/src/ErrorCodes.h"
#include "CommonTools/Utils/interface/parser/MethodInvoker.h"
#include "CommonTools/Utils/src/findDataMember.h"
#include "CommonTools/Utils/src/findMethod.h"
#include "CommonTools/Utils/interface/returnType.h"

#include <string>

using namespace reco::parser;
using namespace std;

void MethodSetter::operator()(const char* begin, const char* end) const {
  string name(begin, end);
  string::size_type parenthesis = name.find_first_of('(');
  if ((*begin == '[') || (*begin == '(')) {
    name.insert(0, "operator..");     // operator..[arg];
    parenthesis = 10;                 //           ^--- idx = 10
    name[8] = *begin;                 // operator[.[arg];
    name[9] = name[name.size() - 1];  // operator[][arg];
    name[10] = '(';                   // operator[](arg];
    name[name.size() - 1] = ')';      // operator[](arg);
    // we don't actually need the last two, but just for extra care
    //std::cout << "Transformed {" << string(begin,end) << "} into
    //  {"<< name <<"}" << std::endl;
  }
  std::vector<AnyMethodArgument> args;
  if (parenthesis != string::npos) {
    name.erase(parenthesis, name.size());
    if (intStack_.empty()) {
      throw Exception(begin) << "expected method argument, but non given.";
    }
    for (vector<AnyMethodArgument>::const_iterator i = intStack_.begin(); i != intStack_.end(); ++i) {
      args.push_back(*i);
    }
    intStack_.clear();
  }
  string::size_type endOfExpr = name.find_last_of(' ');
  if (endOfExpr != string::npos) {
    name.erase(endOfExpr, name.size());
  }
  //std::cerr << "Pushing [" << name << "] with " << args.size()
  //  << " args " << (lazy_ ? "(lazy)" : "(immediate)") << std::endl;
  if (lazy_) {
    // for lazy parsing we just push method name and arguments
    lazyMethStack_.push_back(LazyInvoker(name, args));
  } else {
    // otherwise we really have to resolve the method
    push(name, args, begin);
  }
  //std::cerr << "Pushed [" << name << "] with " << args.size() <<
  //  " args " << (lazy_ ? "(lazy)" : "(immediate)") << std::endl;
}

bool MethodSetter::push(const string& name, const vector<AnyMethodArgument>& args, const char* begin, bool deep) const {
  edm::TypeWithDict type = typeStack_.back();
  vector<AnyMethodArgument> fixups;
  int error = 0;
  pair<edm::FunctionWithDict, bool> mem = reco::findMethod(type, name, args, fixups, begin, error);
  if (bool(mem.first)) {
    // We found the method.
    edm::TypeWithDict retType = reco::returnType(mem.first);
    if (!bool(retType)) {
      // Invalid return type, fatal error, throw.
      throw Exception(begin) << "member \"" << mem.first.name() << "\" return type is invalid:\n"
                             << "  return type: \"" << mem.first.typeName() << "\"\n";
    }
    typeStack_.push_back(retType);
    // check for edm::Ref, edm::RefToBase, edm::Ptr
    if (mem.second) {
      // Without fixups.
      //std::cout << "Mem.second, so book " << mem.first.name() <<
      //  " without fixups." << std::endl;
      methStack_.push_back(MethodInvoker(mem.first));
      if (!deep) {
        return false;
      }
      // note: we have not found the method, so we have not
      // fixupped the arguments
      push(name, args, begin);
    } else {
      // With fixups.
      //std::cout << "Not mem.second, so book " << mem.first.name()
      //  << " with #args = " << fixups.size() << std::endl;
      methStack_.push_back(MethodInvoker(mem.first, fixups));
    }
    return true;
  }
  if (error != reco::parser::kNameDoesNotExist) {
    // Fatal error, throw.
    switch (error) {
      case reco::parser::kIsNotPublic:
        throw Exception(begin) << "method named \"" << name << "\" for type \"" << type.name()
                               << "\" is not publically accessible.";
        break;
      case reco::parser::kIsStatic:
        throw Exception(begin) << "method named \"" << name << "\" for type \"" << type.name() << "\" is static.";
        break;
      case reco::parser::kIsNotConst:
        throw Exception(begin) << "method named \"" << name << "\" for type \"" << type.name() << "\" is not const.";
        break;
      case reco::parser::kWrongNumberOfArguments:
        throw Exception(begin) << "method named \"" << name << "\" for type \"" << type.name()
                               << "\" was passed the wrong number of arguments.";
        break;
      case reco::parser::kWrongArgumentType:
        throw Exception(begin) << "method named \"" << name << "\" for type \"" << type.name()
                               << "\" was passed the wrong types of arguments.";
        break;
      default:
        throw Exception(begin) << "method named \"" << name << "\" for type \"" << type.name()
                               << "\" is not usable in this context.";
    }
  }
  // Not a method, check for a data member.
  error = 0;
  edm::MemberWithDict member(reco::findDataMember(type, name, error));
  if (!bool(member)) {
    // Not a data member either, fatal error, throw.
    switch (error) {
      case reco::parser::kNameDoesNotExist: {
        Exception ex(begin);
        ex << "no method or data member named \"" << name << "\" found for type \"" << type.name() << "\"\n";
        // The following information is for temporary debugging only, intended to be removed later
        ex << "It has the following methods\n";
        edm::TypeFunctionMembers functions(type);
        for (auto const& f : functions) {
          ex << " " << f->GetName() << "\n";
        }
        ex << "and the following data members\n";
        edm::TypeDataMembers members(type);
        for (auto const& m : members) {
          ex << " " << m->GetName() << "\n";
        }
        throw ex;
      } break;
      case reco::parser::kIsNotPublic:
        throw Exception(begin) << "data member named \"" << name << "\" for type \"" << type.name()
                               << "\" is not publically accessible.";
        break;
      default:
        throw Exception(begin) << "data member named \"" << name << "\" for type \"" << type.name()
                               << "\" is not usable in this context.";
        break;
    }
  }
  // Ok, it was a data member.
  typeStack_.push_back(member.typeOf());
  methStack_.push_back(MethodInvoker(member));
  return true;
}