QML: Take care of QVariant when converting function arguments

We cannot convert to QVariant using QMetaType::convert(). But we can
just construct a QVariant with the desired type and data. This will
become an issue once we automatically convert argument types to match
the desired type inside the function.

As a side effect, also allow declaring "var" arguments to functions.

Change-Id: Idc14021d8d85d3d09ee7b7f286de91b56ea02bfd
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Ulf Hermann 2022-02-22 13:40:09 +01:00
parent 6b5aa14596
commit c8e756e560
7 changed files with 53 additions and 7 deletions

View File

@ -271,9 +271,9 @@ Notice the parameter and return type specified after the colon. You can use \l
{QML Value Types}{value types} and \l {QML Object Types}{object types} as type
names.
If the type is omitted in QML, then you must specify QVariant as type with
Q_RETURN_ARG() and Q_ARG() when calling QMetaObject::invokeMethod.
If the type is omitted or specified as \c var in QML, then you must pass
QVariant as type with Q_RETURN_ARG() and Q_ARG() when calling
QMetaObject::invokeMethod.
\section2 Connecting to QML Signals

View File

@ -461,9 +461,17 @@ void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
Q_ASSERT(argumentType.sizeOf() > 0);
Q_ALLOCA_VAR(void, arg, argumentType.sizeOf());
if (argumentType == QMetaType::fromType<QVariant>()) {
if (frame->argc() > i)
new (arg) QVariant(frame->argTypes()[i], frame->argv()[i]);
else
new (arg) QVariant();
} else {
argumentType.construct(arg);
if (frame->argc() > i)
QMetaType::convert(frame->argTypes()[i], frame->argv()[i], argumentType, arg);
}
transformedArguments[i] = arg;
}

View File

@ -1680,6 +1680,9 @@ Type: UiQualifiedId;
} break;
./
Type: T_VAR;
/. case $rule_number: Q_FALLTHROUGH(); ./
Type: T_VOID;
/.
case $rule_number: {

View File

@ -4,7 +4,7 @@ qt_internal_add_test(tst_qmlcppcodegen
SOURCES
tst_qmlcppcodegen.cpp
LIBRARIES
Qt::Qml
Qt::QmlPrivate
Qt::Gui
codegen_test_module
codegen_test_moduleplugin

View File

@ -65,6 +65,7 @@ set(qml_files
functionLookup.qml
funcWithParams.qml
functionReturningVoid.qml
functionTakingVar.qml
globals.qml
idAccess.qml
immediateQuit.qml

View File

@ -0,0 +1,11 @@
pragma Strict
import QtQml
QtObject {
property var c;
function a(b: var) {
c = b;
}
}

View File

@ -23,6 +23,8 @@
#include <data/cppbaseclass.h>
#include <data/objectwithmethod.h>
#include <QtQml/private/qqmlengine_p.h>
#include <QtTest>
#include <QtQml>
#include <QtGui/qcolor.h>
@ -121,6 +123,7 @@ private slots:
void blockComments();
void functionLookup();
void objectInVar();
void functionTakingVar();
};
void tst_QmlCppCodegen::simpleBinding()
@ -1824,6 +1827,26 @@ void tst_QmlCppCodegen::objectInVar()
QVERIFY(!result);
}
void tst_QmlCppCodegen::functionTakingVar()
{
QQmlEngine engine;
const QUrl document(u"qrc:/TestTypes/functionTakingVar.qml"_qs);
QQmlComponent c(&engine, document);
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
QScopedPointer<QObject> o(c.create());
QVERIFY(o);
QVERIFY(!o->property("c").isValid());
int value = 11;
QQmlEnginePrivate *e = QQmlEnginePrivate::get(&engine);
void *args[] = { nullptr, reinterpret_cast<void *>(std::addressof(value)) };
QMetaType types[] = { QMetaType::fromType<void>(), QMetaType::fromType<std::decay_t<int>>() };
e->executeRuntimeFunction(document, 0, o.data(), 1, args, types);
QCOMPARE(o->property("c"), QVariant::fromValue<int>(11));
}
void tst_QmlCppCodegen::runInterpreted()
{
if (qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER"))