Method* MocClass::findMethod(const MethodCall& call) const { Method *method = _delegate->findMethod(call); if (method) return(method); SmokeObject *o = call.target(); /* only QObjects have meta methods */ if (o && o->ptr() && o->instanceOf("QObject") && o->klass() == this) { /* unwrap the call */ QObject * qobject = reinterpret_cast<QObject *>(o->castPtr("QObject")); const QMetaObject * meta = qobject->metaObject(); /* get the method id */ int id = findMethodId(o->smoke(), meta, call.method()->name(), call.args()); if (id >= 0) method = new MocMethod(o->smoke(), meta, id); } return method; }
/* C++ compilers select overloaded methods by ranking each argument in terms of its implicit conversions. There are three different types of implicit conversions: standard, user and ellipsis. We only consider the former, as the others probably are not relevant for Qt. Within standard conversions, there are three ranks: exact, promotion and conversion. We assign these scores 3, 2 and 1, respectively, while 0 indicates no conversion and -1 indicates an error (e.g. unsupported type). The method with better or same ranks for all of its parameters is selected. If there is a tie for the best method, there is an error (in our code). */ int scoreArg_basetype(SEXP arg, const SmokeType &type) { int score = 0; SEXP value = arg; int rtype = TYPEOF(value); unsigned short elem = type.elem(); switch(rtype) { // try the simple cases first case RAWSXP: switch(elem) { case Smoke::t_uchar: score = 3; break; case Smoke::t_short: case Smoke::t_ushort: score = 2; break; case Smoke::t_int: case Smoke::t_uint: case Smoke::t_long: case Smoke::t_ulong: case Smoke::t_float: case Smoke::t_double: score = 1; break; default: break; } break; case INTSXP: switch(elem) { case Smoke::t_enum: if (inherits(value, "QtEnum")) score = 2; else score = 1; break; case Smoke::t_int: score = 3; break; case Smoke::t_uint: if (inherits(value, "QtEnum")) { score = 3; // favor QFlags over enums break; } case Smoke::t_long: case Smoke::t_ulong: case Smoke::t_float: case Smoke::t_double: score = 2; break; case Smoke::t_short: case Smoke::t_ushort: case Smoke::t_uchar: score = 1; break; default: break; } break; case REALSXP: switch(elem) { case Smoke::t_double: score = 3; break; case Smoke::t_float: case Smoke::t_uint: // to distinguish int/uint score = 2; break; case Smoke::t_int: case Smoke::t_long: case Smoke::t_ulong: case Smoke::t_short: case Smoke::t_ushort: case Smoke::t_uchar: case Smoke::t_enum: score = 1; break; default: break; } break; case STRSXP: if (elem == Smoke::t_char && strlen(CHAR(asChar(value))) == 1) score = 2; break; case ENVSXP: if (elem == Smoke::t_class) { SmokeObject *o = SmokeObject::fromSexp(value); if (o) { const char *smokeClass = type.className(); if (o->className() == smokeClass) score = 3; else if (o->instanceOf(smokeClass)) score = 2; /* Not clear if we want to support this C++ feature else { Method *m = Class::fromSmokeType(type)->findImplicitConverter(o); if (m) { score = 1; delete m; } } */ } } break; case NILSXP: if (type.isPtr()) score = 1; break; default: break; } return score; }
QVariant qvariant_from_sexp(SEXP rvalue, int index) { QVariant variant; if (index == -1) { /* If a particular element is not selected, then non-lists of length one are considered scalars. Otherwise, collections. Except for raw vectors, which are naturally QByteArrays. */ if (TYPEOF(rvalue) == RAWSXP) return QVariant(from_sexp<QByteArray>(rvalue)); else if (TYPEOF(rvalue) == VECSXP || length(rvalue) > 1) { SEXP rlist = coerceVector(rvalue, VECSXP); if (getAttrib(rvalue, R_NamesSymbol) != R_NilValue) variant = asQVariantOfType(rlist, QMetaType::QVariantMap); else variant = asQVariantOfType(rlist, QMetaType::QVariantList); return variant; } index = 0; } switch(TYPEOF(rvalue)) { case RAWSXP: variant = qVariantFromValue(RAW(rvalue)[index]); break; case LGLSXP: // Rprintf("Logical\n"); // FIXME: by converting to 'bool' all NA become TRUE variant = QVariant((bool)LOGICAL(rvalue)[index]); break; case REALSXP: // Rprintf("Real\n"); variant = QVariant(REAL(rvalue)[index]); break; case INTSXP: // Rprintf("Integer\n"); { SEXP levels; if ((levels = getAttrib(rvalue, R_LevelsSymbol)) != R_NilValue) { int level = INTEGER(rvalue)[index]; SEXP level_str = NA_STRING; /*Rprintf("getting level: %d\n", level);*/ if (level != NA_INTEGER) level_str = STRING_ELT(levels, level - 1); variant = QVariant(sexp2qstring(level_str)); } else variant = QVariant(INTEGER(rvalue)[index]); break; } case STRSXP: // Rprintf("String\n"); variant = QVariant(sexp2qstring(STRING_ELT(rvalue, index))); break; case EXTPTRSXP: // Rprintf("External pointer\n"); variant = qVariantFromValue(unwrapPointer(rvalue, void)); break; case VECSXP: variant = from_sexp<QVariant>(VECTOR_ELT(rvalue, index)); break; case ENVSXP: { SmokeObject *so = SmokeObject::fromSexp(rvalue); if (so->instanceOf("QWidget")) variant = qVariantFromValue(reinterpret_cast<QWidget *>(so->castPtr("QWidget"))); else if (so->instanceOf("QObject")) variant = qVariantFromValue(reinterpret_cast<QObject *>(so->castPtr("QObject"))); else { QMetaType::Type type = (QMetaType::Type) QMetaType::type(so->className()); if (type) variant = asQVariantOfType(rvalue, type, false); else variant = qVariantFromValue(so->ptr()); } } break; case NILSXP: // invalid QVariant break; default: error("Converting to QVariant: unhandled R type"); } return variant; }