aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2021-02-09 14:29:24 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-02-22 14:20:19 +0000
commit0c029b420ea9b7631cf87d427c0821320064c01b (patch)
tree2f4a5fec2d7d135caa64df3cdb1619668288ecc2
parent911191793f10b6c160b282b98e7cf585103ca47c (diff)
Fix QJSValue singletons only supporting object types
Now primitives such as integers and strings should also work. Fixes: QTBUG-85615 Change-Id: I201d1844b7272ca50e32f1e33e9ac357b5e68dfe Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> (cherry picked from commit 64102ae231317eb6f637304918e55153dadef72d) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h5
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp23
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp42
3 files changed, 62 insertions, 8 deletions
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 6232d78a57..950e5da768 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -138,8 +138,9 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
int scriptIndex;
} qmlContextScriptLookup;
struct {
- Heap::Object *singleton;
- quintptr unused;
+ Heap::Base *singletonObject;
+ quintptr unused2;
+ QV4::ReturnedValue singletonValue;
} qmlContextSingletonLookup;
struct {
quintptr unused1;
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index ec3aa00341..5581ea9a53 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -240,15 +240,22 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine());
if (r.type.isQObjectSingleton() || r.type.isCompositeSingleton()) {
e->singletonInstance<QObject*>(r.type);
- lookup->qmlContextSingletonLookup.singleton =
- static_cast<Heap::Object*>(
+ lookup->qmlContextSingletonLookup.singletonObject =
Value::fromReturnedValue(
QQmlTypeWrapper::create(v4, nullptr, r.type)
- ).heapObject());
+ ).heapObject();
} else {
QJSValue singleton = e->singletonInstance<QJSValue>(r.type);
- QV4::ScopedObject o(scope, QJSValuePrivate::asReturnedValue(&singleton));
- lookup->qmlContextSingletonLookup.singleton = o->d();
+
+ // QSrting values should already have been put on the engine heap at this point
+ // to manage their memory. We later assume this has already happened.
+ Q_ASSERT(!QJSValuePrivate::asQString(&singleton));
+
+ if (QV4::Value *val = QJSValuePrivate::takeManagedValue(&singleton)) {
+ lookup->qmlContextSingletonLookup.singletonObject = val->heapObject();
+ } else {
+ lookup->qmlContextSingletonLookup.singletonValue = QJSValuePrivate::asReturnedValue(&singleton);
+ }
}
lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupSingleton;
return lookup->qmlContextPropertyGetter(lookup, v4, base);
@@ -539,7 +546,11 @@ ReturnedValue QQmlContextWrapper::lookupSingleton(Lookup *l, ExecutionEngine *en
{
Q_UNUSED(engine);
Q_UNUSED(base);
- return Value::fromHeapObject(l->qmlContextSingletonLookup.singleton).asReturnedValue();
+
+ if (l->qmlContextSingletonLookup.singletonObject != nullptr)
+ return l->qmlContextSingletonLookup.singletonObject->asReturnedValue();
+
+ return l->qmlContextSingletonLookup.singletonValue;
}
ReturnedValue QQmlContextWrapper::lookupIdObject(Lookup *l, ExecutionEngine *engine, Value *base)
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 66beb839f0..3b527a8f50 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -352,6 +352,8 @@ private slots:
void invalidInlineComponent();
void warnOnInjectedParameters();
+ void qtbug_85615();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -6206,6 +6208,46 @@ void tst_qqmllanguage::qtbug_86482()
QCOMPARE(o->property("result").toString(), QStringLiteral("Hello world!"));
}
+void tst_qqmllanguage::qtbug_85615()
+{
+ qmlRegisterSingletonType("Test.Singleton", 1, 0, "SingletonString", [](QQmlEngine *, QJSEngine *) -> QJSValue {
+ return QJSValue("Test");
+ });
+ qmlRegisterSingletonType("Test.Singleton", 1, 0, "SingletonInt", [](QQmlEngine *, QJSEngine *) -> QJSValue {
+ return QJSValue(123);
+ });
+ qmlRegisterSingletonType("Test.Singleton", 1, 0, "SingletonDouble", [](QQmlEngine *, QJSEngine *) -> QJSValue {
+ return QJSValue(1.23);
+ });
+ qmlRegisterSingletonType("Test.Singleton", 1, 0, "SingletonUndefined", [](QQmlEngine *, QJSEngine *) -> QJSValue {
+ return QJSValue(QJSValue::UndefinedValue);
+ });
+ qmlRegisterSingletonType("Test.Singleton", 1, 0, "SingletonNull", [](QQmlEngine *, QJSEngine *) -> QJSValue {
+ return QJSValue(QJSValue::NullValue);
+ });
+
+ QQmlEngine e;
+ QQmlComponent c(&engine);
+ c.setData("import QtQml 2.0\n"
+ "import Test.Singleton\n"
+ "QtObject {\n"
+ " property var resultString: SingletonString\n"
+ " property var resultInt: SingletonInt\n"
+ " property var resultDouble: SingletonDouble\n"
+ " property var resultUndefined: SingletonUndefined\n"
+ " property var resultNull: SingletonNull\n"
+ "}", QUrl());
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+
+ QScopedPointer<QObject> o(c.create());
+ QCOMPARE(o->property("resultString").toString(), "Test");
+ QCOMPARE(o->property("resultInt").toInt(), 123);
+ QCOMPARE(o->property("resultDouble").toDouble(), 1.23);
+ QVERIFY(!o->property("resultUndefined").isValid());
+ QCOMPARE(o->property("resultUndefined").metaType(), QMetaType(QMetaType::UnknownType));
+ QCOMPARE(o->property("resultNull").metaType(), QMetaType(QMetaType::Nullptr));
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"