Showing the changes to libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp (1 of 11 files). Show all
Unified · Split
| @@ -53,6 +53,18 @@ private: // storage · 52 unmodified lines | |||
| 53 | QScriptValue ScriptObjectQtProxy::newQObject(ScriptEngineQtScript* engine, QObject* object, | 53 | QScriptValue ScriptObjectQtProxy::newQObject(ScriptEngineQtScript* engine, QObject* object, |
| 54 | ScriptEngine::ValueOwnership ownership, | 54 | ScriptEngine::ValueOwnership ownership, |
| 55 | const ScriptEngine::QObjectWrapOptions& options) { | 55 | const ScriptEngine::QObjectWrapOptions& options) { |
| 56 | QScriptEngine* qengine = static_cast<QScriptEngine*>(engine); | ||
| 57 | |||
| 58 | // do we already have a valid wrapper for this QObject? | ||
| 59 | { | ||
| 60 | QMutexLocker guard(&engine->_qobjectWrapperMapProtect); | ||
| 61 | ScriptEngineQtScript::ObjectWrapperMap::const_iterator lookup = engine->_qobjectWrapperMap.find(object); | ||
| 62 | if (lookup != engine->_qobjectWrapperMap.end()) { | ||
| 63 | QSharedPointer<ScriptObjectQtProxy> proxy = lookup.value().lock(); | ||
| 64 | if (proxy) return static_cast<QScriptEngine*>(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 56 | bool ownsObject; | 68 | bool ownsObject; |
| 57 | switch (ownership) { | 69 | switch (ownership) { |
| 58 | case ScriptEngine::QtOwnership: | 70 | case ScriptEngine::QtOwnership: |
| @@ -65,8 +77,33 @@ QScriptValue ScriptObjectQtProxy::newQObject(ScriptEngineQtScript* engine, QObje · 6 unmodified lines | |||
| 65 | ownsObject = !object->parent(); | 77 | ownsObject = !object->parent(); |
| 66 | break; | 78 | break; |
| 67 | } | 79 | } |
| 68 | QScriptEngine* qengine = static_cast<QScriptEngine*>(engine); | 80 | |
| 81 | // create the wrapper | ||
| 69 | auto proxy = QSharedPointer<ScriptObjectQtProxy>::create(engine, object, ownsObject, options); | 82 | auto proxy = QSharedPointer<ScriptObjectQtProxy>::create(engine, object, ownsObject, options); |
| 83 | |||
| 84 | { | ||
| 85 | QMutexLocker guard(&engine->_qobjectWrapperMapProtect); | ||
| 86 | |||
| 87 | // check again to see if someone else created the wrapper while we were busy | ||
| 88 | ScriptEngineQtScript::ObjectWrapperMap::const_iterator lookup = engine->_qobjectWrapperMap.find(object); | ||
| 89 | if (lookup != engine->_qobjectWrapperMap.end()) { | ||
| 90 | QSharedPointer<ScriptObjectQtProxy> proxy = lookup.value().lock(); | ||
| 91 | if (proxy) return static_cast<QScriptEngine*>(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));; | ||
| 92 | } | ||
| 93 | |||
| 94 | // register the wrapper with the engine and make sure it cleans itself up | ||
| 95 | engine->_qobjectWrapperMap.insert(object, proxy); | ||
| 96 | QPointer<ScriptEngineQtScript> enginePtr = engine; | ||
| 97 | object->connect(object, &QObject::destroyed, engine, [enginePtr, object]() { | ||
| 98 | if (!enginePtr) return; | ||
| 99 | QMutexLocker guard(&enginePtr->_qobjectWrapperMapProtect); | ||
| 100 | ScriptEngineQtScript::ObjectWrapperMap::iterator lookup = enginePtr->_qobjectWrapperMap.find(object); | ||
| 101 | if (lookup != enginePtr->_qobjectWrapperMap.end()) { | ||
| 102 | enginePtr->_qobjectWrapperMap.erase(lookup); | ||
| 103 | } | ||
| 104 | }); | ||
| 105 | } | ||
| 106 | |||
| 70 | return static_cast<QScriptEngine*>(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy))); | 107 | return static_cast<QScriptEngine*>(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy))); |
| 71 | } | 108 | } |
| 72 | 109 | ||
| @@ -96,7 +133,6 @@ void ScriptObjectQtProxy::investigate() { · 23 unmodified lines | |||
| 96 | if (!qobject) return; | 133 | if (!qobject) return; |
| 97 | 134 | ||
| 98 | const QMetaObject* metaObject = qobject->metaObject(); | 135 | const QMetaObject* metaObject = qobject->metaObject(); |
| 99 | _name = QString::fromLatin1(metaObject->className()); | ||
| 100 | 136 | ||
| 101 | // discover properties | 137 | // discover properties |
| 102 | int startIdx = _wrapOptions & ScriptEngine::ExcludeSuperClassProperties ? metaObject->propertyOffset() : 0; | 138 | int startIdx = _wrapOptions & ScriptEngine::ExcludeSuperClassProperties ? metaObject->propertyOffset() : 0; |
| @@ -185,6 +221,15 @@ void ScriptObjectQtProxy::investigate() { · 82 unmodified lines | |||
| 185 | } | 221 | } |
| 186 | } | 222 | } |
| 187 | 223 | ||
| 224 | QString ScriptObjectQtProxy::name() const { | ||
| 225 | Q_ASSERT(_object); | ||
| 226 | if (!_object) return ""; | ||
| 227 | return _object ? _object->objectName() : ""; | ||
| 228 | QString objectName = _object->objectName(); | ||
| 229 | if (!objectName.isEmpty()) return objectName; | ||
| 230 | return _object->metaObject()->className(); | ||
| 231 | } | ||
| 232 | |||
| 188 | QScriptClass::QueryFlags ScriptObjectQtProxy::queryProperty(const QScriptValue& object, const QScriptString& name, QueryFlags flags, uint* id) { | 233 | QScriptClass::QueryFlags ScriptObjectQtProxy::queryProperty(const QScriptValue& object, const QScriptString& name, QueryFlags flags, uint* id) { |
| 189 | // check for properties | 234 | // check for properties |
| 190 | for (PropertyDefMap::const_iterator trans = _props.cbegin(); trans != _props.cend(); ++trans) { | 235 | for (PropertyDefMap::const_iterator trans = _props.cbegin(); trans != _props.cend(); ++trans) { |
| @@ -268,7 +313,7 @@ QScriptValue ScriptObjectQtProxy::property(const QScriptValue& object, const QSc · 77 unmodified lines | |||
| 268 | MethodDefMap::const_iterator lookup = _methods.find(methodId); | 313 | MethodDefMap::const_iterator lookup = _methods.find(methodId); |
| 269 | if (lookup == _methods.cend()) return QScriptValue(); | 314 | if (lookup == _methods.cend()) return QScriptValue(); |
| 270 | return static_cast<QScriptEngine*>(_engine)->newObject( | 315 | return static_cast<QScriptEngine*>(_engine)->newObject( |
| 271 | new ScriptMethodQtProxy(_engine, qobject, object, name, lookup.value().methods)); | 316 | new ScriptMethodQtProxy(_engine, qobject, object, lookup.value().methods)); |
| 272 | } | 317 | } |
| 273 | case SIGNAL_TYPE: { | 318 | case SIGNAL_TYPE: { |
| 274 | int signalId = id & ~TYPE_MASK; | 319 | int signalId = id & ~TYPE_MASK; |
| @@ -278,7 +323,7 @@ QScriptValue ScriptObjectQtProxy::property(const QScriptValue& object, const QSc · 3 unmodified lines | |||
| 278 | InstanceMap::const_iterator instLookup = _signalInstances.find(signalId); | 323 | InstanceMap::const_iterator instLookup = _signalInstances.find(signalId); |
| 279 | if (instLookup == _signalInstances.cend() || instLookup.value().isNull()) { | 324 | if (instLookup == _signalInstances.cend() || instLookup.value().isNull()) { |
| 280 | instLookup = _signalInstances.insert(signalId, | 325 | instLookup = _signalInstances.insert(signalId, |
| 281 | new ScriptSignalQtProxy(_engine, qobject, object, name, defLookup.value().signal)); | 326 | new ScriptSignalQtProxy(_engine, qobject, object, defLookup.value().signal)); |
| 282 | Q_ASSERT(instLookup != _signalInstances.cend()); | 327 | Q_ASSERT(instLookup != _signalInstances.cend()); |
| 283 | } | 328 | } |
| 284 | ScriptSignalQtProxy* proxy = instLookup.value(); | 329 | ScriptSignalQtProxy* proxy = instLookup.value(); |
| @@ -315,10 +360,11 @@ void ScriptObjectQtProxy::setProperty(QScriptValue& object, const QScriptString& · 30 unmodified lines | |||
| 315 | ScriptContextGuard guard(&ourContext); | 360 | ScriptContextGuard guard(&ourContext); |
| 316 | 361 | ||
| 317 | int propTypeId = prop.userType(); | 362 | int propTypeId = prop.userType(); |
| 363 | Q_ASSERT(propTypeId != QMetaType::UnknownType); | ||
| 318 | QVariant varValue; | 364 | QVariant varValue; |
| 319 | if(!_engine->castValueToVariant(value, varValue, propTypeId)) { | 365 | if(!_engine->castValueToVariant(value, varValue, propTypeId)) { |
| 320 | QByteArray propTypeName = QMetaType(propTypeId).name(); | 366 | QByteArray propTypeName = QMetaType(propTypeId).name(); |
| 321 | QByteArray valTypeName = value.toVariant().typeName(); | 367 | QByteArray valTypeName = _engine->valueType(value).toLatin1(); |
| 322 | QScriptContext* currentContext = static_cast<QScriptEngine*>(_engine)->currentContext(); | 368 | QScriptContext* currentContext = static_cast<QScriptEngine*>(_engine)->currentContext(); |
| 323 | currentContext->throwError(QScriptContext::TypeError, QString("Cannot convert %1 to %2").arg(valTypeName, propTypeName)); | 369 | currentContext->throwError(QScriptContext::TypeError, QString("Cannot convert %1 to %2").arg(valTypeName, propTypeName)); |
| 324 | return; | 370 | return; |
| @@ -352,6 +398,18 @@ QVariant ScriptVariantQtProxy::unwrap(const QScriptValue& val) { · 27 unmodified lines | |||
| 352 | return proxy ? proxy->toQtValue() : QVariant(); | 398 | return proxy ? proxy->toQtValue() : QVariant(); |
| 353 | } | 399 | } |
| 354 | 400 | ||
| 401 | QString ScriptMethodQtProxy::fullName() const { | ||
| 402 | Q_ASSERT(_object); | ||
| 403 | if (!_object) return ""; | ||
| 404 | Q_ASSERT(!_metas.isEmpty()); | ||
| 405 | const QMetaMethod& firstMethod = _metas.front(); | ||
| 406 | QString objectName = _object->objectName(); | ||
| 407 | if (!objectName.isEmpty()) { | ||
| 408 | return QString("%1.%2").arg(objectName, firstMethod.name()); | ||
| 409 | } | ||
| 410 | return QString("%1::%2").arg(_object->metaObject()->className(), firstMethod.name()); | ||
| 411 | } | ||
| 412 | |||
| 355 | bool ScriptMethodQtProxy::supportsExtension(Extension extension) const { | 413 | bool ScriptMethodQtProxy::supportsExtension(Extension extension) const { |
| 356 | switch (extension) { | 414 | switch (extension) { |
| 357 | case Callable: | 415 | case Callable: |
| @@ -377,6 +435,9 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg · 19 unmodified lines | |||
| 377 | 435 | ||
| 378 | const int scriptValueTypeId = qMetaTypeId<ScriptValue>(); | 436 | const int scriptValueTypeId = qMetaTypeId<ScriptValue>(); |
| 379 | 437 | ||
| 438 | int parameterConversionFailureId = 0; | ||
| 439 | int parameterConversionFailureCount = 0; | ||
| 440 | |||
| 380 | for (auto iter = _metas.cbegin(); iter != _metas.end(); ++iter) { | 441 | for (auto iter = _metas.cbegin(); iter != _metas.end(); ++iter) { |
| 381 | const QMetaMethod& meta = *iter; | 442 | const QMetaMethod& meta = *iter; |
| 382 | int methodNumArgs = meta.parameterCount(); | 443 | int methodNumArgs = meta.parameterCount(); |
| @@ -387,10 +448,10 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg · 4 unmodified lines | |||
| 387 | QList<ScriptValue> qScriptArgList; | 448 | QList<ScriptValue> qScriptArgList; |
| 388 | QList<QVariant> qVarArgList; | 449 | QList<QVariant> qVarArgList; |
| 389 | QGenericArgument qGenArgs[10]; | 450 | QGenericArgument qGenArgs[10]; |
| 390 | int arg; | 451 | int conversionFailures = 0; |
| 391 | bool conversionFailed = false; | 452 | for (int arg = 0; arg < numArgs; ++arg) { |
| 392 | for (arg = 0; arg < numArgs && !conversionFailed; ++arg) { | ||
| 393 | int methodArgTypeId = meta.parameterType(arg); | 453 | int methodArgTypeId = meta.parameterType(arg); |
| 454 | Q_ASSERT(methodArgTypeId != QMetaType::UnknownType); | ||
| 394 | QScriptValue argVal = context->argument(arg); | 455 | QScriptValue argVal = context->argument(arg); |
| 395 | if (methodArgTypeId == scriptValueTypeId) { | 456 | if (methodArgTypeId == scriptValueTypeId) { |
| 396 | qScriptArgList.append(ScriptValue(new ScriptValueQtWrapper(_engine, argVal))); | 457 | qScriptArgList.append(ScriptValue(new ScriptValueQtWrapper(_engine, argVal))); |
| @@ -401,24 +462,23 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg · 4 unmodified lines | |||
| 401 | } else { | 462 | } else { |
| 402 | QVariant varArgVal; | 463 | QVariant varArgVal; |
| 403 | if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) { | 464 | if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) { |
| 404 | conversionFailed = true; | 465 | conversionFailures++; |
| 405 | break; | 466 | } else { |
| 406 | /*QByteArray methodTypeName = QMetaType(methodArgTypeId).name(); | 467 | qVarArgList.append(varArgVal); |
| 407 | QByteArray argTypeName = argVal.toVariant().typeName(); | 468 | const QVariant& converted = qVarArgList.back(); |
| 408 | context->throwError(QScriptContext::TypeError, | 469 | |
| 409 | QString("Cannot convert %1 to %2").arg(argTypeName, methodTypeName)); | 470 | // a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant |
| 410 | return QVariant();*/ | 471 | // A const_cast is needed because calling data() would detach the QVariant. |
| 472 | qGenArgs[arg] = | ||
| 473 | QGenericArgument(QMetaType::typeName(converted.userType()), const_cast<void*>(converted.constData())); | ||
| 411 | } | 474 | } |
| 412 | qVarArgList.append(varArgVal); | ||
| 413 | const QVariant& converted = qVarArgList.back(); | ||
| 414 | |||
| 415 | // a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant | ||
| 416 | // A const_cast is needed because calling data() would detach the QVariant. | ||
| 417 | qGenArgs[arg] = | ||
| 418 | QGenericArgument(QMetaType::typeName(converted.userType()), const_cast<void*>(converted.constData())); | ||
| 419 | } | 475 | } |
| 420 | } | 476 | } |
| 421 | if (conversionFailed) { | 477 | if (conversionFailures) { |
| 478 | if (conversionFailures < parameterConversionFailureCount || !parameterConversionFailureCount) { | ||
| 479 | parameterConversionFailureCount = conversionFailures; | ||
| 480 | parameterConversionFailureId = meta.methodIndex(); | ||
| 481 | } | ||
| 422 | continue; | 482 | continue; |
| 423 | } | 483 | } |
| 424 | 484 | ||
| @@ -426,11 +486,18 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg · 1 unmodified line | |||
| 426 | ScriptContextGuard guard(&ourContext); | 486 | ScriptContextGuard guard(&ourContext); |
| 427 | 487 | ||
| 428 | int returnTypeId = meta.returnType(); | 488 | int returnTypeId = meta.returnType(); |
| 429 | if (returnTypeId == QMetaType::Void) { | 489 | |
| 490 | // The Qt MOC engine will automatically call qRegisterMetaType on invokable parameters and properties, but there's | ||
| 491 | // nothing in there for return values so these need to be explicitly runtime-registered! | ||
| 492 | Q_ASSERT(returnTypeId != QMetaType::UnknownType); | ||
| 493 | if (returnTypeId == QMetaType::UnknownType) { | ||
| 494 | context->throwError(QString("Cannot call native function %1, its return value has not been registered with Qt").arg(fullName())); | ||
| 495 | return QVariant(); | ||
| 496 | } else if (returnTypeId == QMetaType::Void) { | ||
| 430 | bool success = meta.invoke(qobject, Qt::DirectConnection, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3], | 497 | bool success = meta.invoke(qobject, Qt::DirectConnection, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3], |
| 431 | qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]); | 498 | qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]); |
| 432 | if (!success) { | 499 | if (!success) { |
| 433 | context->throwError("Native call failed"); | 500 | context->throwError(QString("Unexpected: Native call of %1 failed").arg(fullName())); |
| 434 | } | 501 | } |
| 435 | return QVariant(); | 502 | return QVariant(); |
| 436 | } else if (returnTypeId == scriptValueTypeId) { | 503 | } else if (returnTypeId == scriptValueTypeId) { |
| @@ -439,7 +506,7 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg · 2 unmodified lines | |||
| 439 | qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6], | 506 | qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6], |
| 440 | qGenArgs[7], qGenArgs[8], qGenArgs[9]); | 507 | qGenArgs[7], qGenArgs[8], qGenArgs[9]); |
| 441 | if (!success) { | 508 | if (!success) { |
| 442 | context->throwError("Native call failed"); | 509 | context->throwError(QString("Unexpected: Native call of %1 failed").arg(fullName())); |
| 443 | return QVariant(); | 510 | return QVariant(); |
| 444 | } | 511 | } |
| 445 | QScriptValue qResult = ScriptValueQtWrapper::fullUnwrap(_engine, result); | 512 | QScriptValue qResult = ScriptValueQtWrapper::fullUnwrap(_engine, result); |
| @@ -454,15 +521,53 @@ QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& arg · 8 unmodified lines | |||
| 454 | meta.invoke(qobject, Qt::DirectConnection, sRetVal, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3], | 521 | meta.invoke(qobject, Qt::DirectConnection, sRetVal, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3], |
| 455 | qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]); | 522 | qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]); |
| 456 | if (!success) { | 523 | if (!success) { |
| 457 | context->throwError("Native call failed"); | 524 | context->throwError(QString("Unexpected: Native call of %1 failed").arg(fullName())); |
| 458 | return QVariant(); | 525 | return QVariant(); |
| 459 | } | 526 | } |
| 460 | QScriptValue qResult = _engine->castVariantToValue(qRetVal); | 527 | QScriptValue qResult = _engine->castVariantToValue(qRetVal); |
| 461 | return QVariant::fromValue(qResult); | 528 | return QVariant::fromValue(qResult); |
| 462 | } | 529 | } |
| 463 | } | 530 | } |
| 464 | context->throwError("Native call failed: could not locate an overload with the requested arguments"); | 531 | |
| 532 | // we failed to convert the call to C++, try to create a somewhat sane error message | ||
| 533 | if (parameterConversionFailureCount == 0) { | ||
| 534 | context->throwError(QString("Native call of %1 failed: unexpected parameter count").arg(fullName())); | ||
| 535 | return QVariant(); | ||
| 536 | } | ||
| 537 | |||
| 538 | const QMetaMethod& meta = _object->metaObject()->method(parameterConversionFailureId); | ||
| 539 | int methodNumArgs = meta.parameterCount(); | ||
| 540 | Q_ASSERT(methodNumArgs == numArgs); | ||
| 541 | |||
| 542 | for (int arg = 0; arg < numArgs; ++arg) { | ||
| 543 | int methodArgTypeId = meta.parameterType(arg); | ||
| 544 | Q_ASSERT(methodArgTypeId != QMetaType::UnknownType); | ||
| 545 | QScriptValue argVal = context->argument(arg); | ||
| 546 | if (methodArgTypeId != scriptValueTypeId && methodArgTypeId != QMetaType::QVariant) { | ||
| 547 | QVariant varArgVal; | ||
| 548 | if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) { | ||
| 549 | QByteArray methodTypeName = QMetaType(methodArgTypeId).name(); | ||
| 550 | QByteArray argTypeName = _engine->valueType(argVal).toLatin1(); | ||
| 551 | context->throwError(QScriptContext::TypeError, QString("Native call of %1 failed: Cannot convert parameter %2 from %3 to %4") | ||
| 552 | .arg(fullName()).arg(arg+1).arg(argTypeName, methodTypeName)); | ||
| 553 | return QVariant(); | ||
| 554 | } | ||
| 555 | } | ||
| 556 | } | ||
| 557 | |||
| 558 | Q_ASSERT(false); // really shouldn't have gotten here -- it didn't work before and it's working now? | ||
| 465 | return QVariant(); | 559 | return QVariant(); |
| 560 | context->throwError(QString("Native call of %1 failed: could not locate an overload with the requested arguments").arg(fullName())); | ||
| 561 | } | ||
| 562 | |||
| 563 | QString ScriptSignalQtProxy::fullName() const { | ||
| 564 | Q_ASSERT(_object); | ||
| 565 | if (!_object) return ""; | ||
| 566 | QString objectName = _object->objectName(); | ||
| 567 | if (!objectName.isEmpty()) { | ||
| 568 | return QString("%1.%2").arg(objectName, _meta.name()); | ||
| 569 | } | ||
| 570 | return QString("%1::%2").arg(_object->metaObject()->className(), _meta.name()); | ||
| 466 | } | 571 | } |
| 467 | 572 | ||
| 468 | // Adapted from https://doc.qt.io/archives/qq/qq16-dynamicqobject.html, for connecting to a signal without a compile-time definition for it | 573 | // Adapted from https://doc.qt.io/archives/qq/qq16-dynamicqobject.html, for connecting to a signal without a compile-time definition for it |
| @@ -476,6 +581,7 @@ int ScriptSignalQtProxy::qt_metacall(QMetaObject::Call call, int id, void** argu · 7 unmodified lines | |||
| 476 | int numArgs = _meta.parameterCount(); | 581 | int numArgs = _meta.parameterCount(); |
| 477 | for (int arg = 0; arg < numArgs; ++arg) { | 582 | for (int arg = 0; arg < numArgs; ++arg) { |
| 478 | int methodArgTypeId = _meta.parameterType(arg); | 583 | int methodArgTypeId = _meta.parameterType(arg); |
| 584 | Q_ASSERT(methodArgTypeId != QMetaType::UnknownType); | ||
| 479 | QVariant argValue(methodArgTypeId, arguments[arg+1]); | 585 | QVariant argValue(methodArgTypeId, arguments[arg+1]); |
| 480 | args.append(_engine->castVariantToValue(argValue)); | 586 | args.append(_engine->castVariantToValue(argValue)); |
| 481 | } | 587 | } |