diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-10-24 01:01:06 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2019-10-24 15:42:35 +0200 |
commit | 328b97a0acdf294f6ba3c902d23ece374a0f11ba (patch) | |
tree | 3a005d1948a91bfaacda69dc0dfba1b66d491714 | |
parent | 1e94466b06190061a86e9918c5e45279171e600f (diff) | |
parent | 45652a0491aa32ecdf1d05c236501f78bcea71f8 (diff) |
Merge remote-tracking branch 'origin/5.14' into 5.15
Conflicts:
src/qml/qml/qqmlpropertyvalidator.cpp
tests/auto/qml/qmlmin/tst_qmlmin.cpp
Change-Id: I920c133e839d980ed32c179a0bc4fa44c46e2296
26 files changed, 224 insertions, 33 deletions
diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index c4ecaf367c..401e099ebf 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -464,22 +464,24 @@ Unlike an ordinary property, an alias has the following restrictions: must be provided when the alias is first declared. \li It cannot refer to \l {Attached Properties and Attached Signal Handlers} {attached properties}. -\li It cannot refer to grouped properties; the following code will not work: +\li It cannot refer to properties inside a hierarchy with depth 3 or greater. The + following code will not work: \code - property alias color: rectangle.border.color + property alias color: myItem.myRect.border.color - Rectangle { - id: rectangle + Item { + id: myItem + property Rectangle myRect } \endcode - However, aliases to \l {QML Basic Types}{value type} properties do work: + However, aliases to properties that are up to two levels deep will work. + \code - property alias rectX: object.rectProperty.x + property alias color: rectangle.border.color - Item { - id: object - property rect rectProperty + Rectangle { + id: rectangle } \endcode \endlist diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 2b5e8bd2b9..5a81f24e06 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1622,7 +1622,7 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const int methodMatchScore = 0; for (int ii = 0; ii < methodArgumentCount; ++ii) { - methodMatchScore += MatchScore((v = Value::fromStaticValue(callArgs->args[ii])), + methodMatchScore += MatchScore((v = QV4::Value::fromStaticValue(callArgs->args[ii])), methodArgTypes[ii]); } @@ -2268,7 +2268,7 @@ ReturnedValue QMetaObjectWrapper::callOverloadedConstructor(QV4::ExecutionEngine int methodMatchScore = 0; for (int ii = 0; ii < methodArgumentCount; ++ii) { - methodMatchScore += MatchScore((v = Value::fromStaticValue(callArgs->args[ii])), + methodMatchScore += MatchScore((v = QV4::Value::fromStaticValue(callArgs->args[ii])), methodArgTypes[ii]); } diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index e4aceef3ee..12a6381e6f 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -70,7 +70,7 @@ struct ScopedValue; #define CHECK_EXCEPTION() \ do { \ - if (scope.hasException()) { \ + if (scope.hasException() || scope.engine->isInterrupted.loadAcquire()) { \ return QV4::Encode::undefined(); \ } \ } while (false) diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h index bf689a74bc..616fa9a5a9 100644 --- a/src/qml/jsruntime/qv4stackframe_p.h +++ b/src/qml/jsruntime/qv4stackframe_p.h @@ -117,7 +117,7 @@ struct Q_QML_EXPORT CppStackFrame { void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope, const Value &thisObject, const Value &newTarget = Value::undefinedValue()) { setupJSFrame(stackSpace, function, scope, thisObject, newTarget, - v4Function->nFormals, v4Function->compiledFunction->nRegisters); + v4Function->compiledFunction->nFormals, v4Function->compiledFunction->nRegisters); } void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope, const Value &thisObject, const Value &newTarget, uint nFormals, uint nRegisters) diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 27d518f5c6..ad5a6ebc8c 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -364,7 +364,7 @@ static inline Heap::CallContext *getScope(QV4::Value *stack, int level) static inline const QV4::Value &constant(Function *function, int index) { - return function->compilationUnit->constants[index].asValue<Value>(); + return function->compilationUnit->constants[index].asValue<QV4::Value>(); } static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs) diff --git a/src/qml/qml/ftw/qflagpointer_p.h b/src/qml/qml/ftw/qflagpointer_p.h index 71b41cd30b..a10e57aeca 100644 --- a/src/qml/qml/ftw/qflagpointer_p.h +++ b/src/qml/qml/ftw/qflagpointer_p.h @@ -55,6 +55,17 @@ QT_BEGIN_NAMESPACE +namespace QtPrivate { +template <typename T> struct QFlagPointerAlignment +{ + enum : size_t { Value = Q_ALIGNOF(T) }; +}; +template <> struct QFlagPointerAlignment<void> +{ + enum : size_t { Value = ~size_t(0) }; +}; +} + template<typename T> class QFlagPointer { public: @@ -133,6 +144,7 @@ template<typename T> QFlagPointer<T>::QFlagPointer(T *v) : ptr_value(quintptr(v)) { + Q_STATIC_ASSERT_X(Q_ALIGNOF(T) >= 4, "Type T does not have sufficient alignment"); Q_ASSERT((ptr_value & FlagsMask) == 0); } @@ -247,6 +259,8 @@ template<typename T, typename T2> QBiPointer<T, T2>::QBiPointer(T *v) : ptr_value(quintptr(v)) { + Q_STATIC_ASSERT_X(QtPrivate::QFlagPointerAlignment<T>::Value >= 4, + "Type T does not have sufficient alignment"); Q_ASSERT((quintptr(v) & FlagsMask) == 0); } @@ -254,6 +268,8 @@ template<typename T, typename T2> QBiPointer<T, T2>::QBiPointer(T2 *v) : ptr_value(quintptr(v) | Flag2Bit) { + Q_STATIC_ASSERT_X(QtPrivate::QFlagPointerAlignment<T2>::Value >= 4, + "Type T2 does not have sufficient alignment"); Q_ASSERT((quintptr(v) & FlagsMask) == 0); } diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp index e961ed3d0d..7d2ad354d6 100644 --- a/src/qml/qml/ftw/qqmlthread.cpp +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -131,6 +131,9 @@ QQmlThreadPrivate::QQmlThreadPrivate(QQmlThread *q) m_mainThreadWaiting(false), mainSync(nullptr), m_mainObject(this) { setObjectName(QStringLiteral("QQmlThread")); + // This size is aligned with the recursion depth limits in the parser/codegen. In case of + // absurd content we want to hit the recursion checks instead of running out of stack. + setStackSize(8 * 1024 * 1024); } bool QQmlThreadPrivate::event(QEvent *e) diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index 254b6cc3db..9157bb95c3 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -532,6 +532,9 @@ QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int ind void QQmlContextPrivate::dropDestroyedQObject(const QString &name, QObject *destroyed) { + if (!data->isValid()) + return; + const int idx = data->propertyNames().value(name); Q_ASSERT(idx >= 0); if (qvariant_cast<QObject *>(propertyValues[idx]) != destroyed) diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 73546bd795..21ca24d38b 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -1824,7 +1824,8 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader, if (qmldirPath.size() > 25 && qmldirPath.at(0) == QLatin1Char(':') && qmldirPath.at(1) == QLatin1Char('/') && qmldirPath.startsWith(QStringLiteral(":/android_rcc_bundle/qml/"), Qt::CaseInsensitive)) { QString pluginName = qmldirPath.mid(21) + Slash + baseName; - auto bundledPath = resolvedPath + QLatin1String("lib") + pluginName.replace(QLatin1Char('/'), QLatin1Char('_')); + pluginName.replace(QLatin1Char('/'), QLatin1Char('_')); + QString bundledPath = resolvedPath + QLatin1String("lib") + pluginName; for (const QString &suffix : suffixes) { const QString absolutePath = typeLoader->absoluteFilePath(bundledPath + suffix); if (!absolutePath.isEmpty()) diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index eff3e94fbd..9e6819891c 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1373,8 +1373,9 @@ bool QQmlPropertyPrivate::write(QObject *object, } } if (!ok) { - // the only other option is that they are assigning a single value + // the only other options are that they are assigning a single value // to a sequence type property (eg, an int to a QList<int> property). + // or that we encountered an interface type // Note that we've already handled single-value assignment to QList<QUrl> properties. if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) { QList<int> list; @@ -1405,6 +1406,15 @@ bool QQmlPropertyPrivate::write(QObject *object, } } + if (!ok && QQmlMetaType::isInterface(propertyType)) { + auto valueAsQObject = qvariant_cast<QObject *>(value); + if (valueAsQObject && valueAsQObject->qt_metacast(QQmlMetaType::interfaceIId(propertyType))) { + // this case can occur when object has an interface type + // and the variant contains a type implementing the interface + return property.writeProperty(object, const_cast<void *>(value.constData()), flags); + } + } + if (ok) { return property.writeProperty(object, const_cast<void *>(v.constData()), flags); } else { diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp index d7361ea2c6..238a535b89 100644 --- a/src/qml/qml/qqmlpropertyvalidator.cpp +++ b/src/qml/qml/qqmlpropertyvalidator.cpp @@ -728,12 +728,12 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope return noError; } else if (isPrimitiveType(propType)) { auto typeName = QString::fromUtf8(QMetaType::typeName(propType)); - return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting \"%3\"") + return qQmlCompileError(binding->location, tr("Cannot assign value of type \"%1\" to property \"%2\", expecting \"%3\"") .arg(rhsType()) .arg(propertyName) .arg(typeName)); } else if (QQmlValueTypeFactory::isValueType(propType)) { - return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object") + return qQmlCompileError(binding->location, tr("Cannot assign value of type \"%1\" to property \"%2\", expecting an object") .arg(rhsType()).arg(propertyName)); } else if (propType == qMetaTypeId<QQmlScriptString>()) { return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected")); diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp index d3dc4978f2..46b2c6386c 100644 --- a/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp +++ b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp @@ -88,10 +88,20 @@ Texture *Atlas::create(const QByteArray &data, int dataLength, int dataOffset, c void Atlas::generateTexture() { + int bytesPerBlock = 8; + switch (m_format) { + case QOpenGLTexture::RGBA8_ETC2_EAC: + case QOpenGLTexture::RGBA_DXT3: + case QOpenGLTexture::RGBA_DXT5: + bytesPerBlock = 16; + default: + break; + } + QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); funcs->glCompressedTexImage2D(GL_TEXTURE_2D, 0, m_format, m_size.width(), m_size.height(), 0, - (m_size.width() * m_size.height()) / 2, + (m_size.width() / 4 * m_size.height() / 4) * bytesPerBlock, nullptr); } diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 86d9590863..dc1f97de54 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -807,9 +807,7 @@ void QSGRenderThread::syncAndRender(QImage *grabImage) } } if (current) { - const QSize outputSize = rhi ? cd->swapchain->currentPixelSize() : windowSize; - - d->renderSceneGraph(outputSize); + d->renderSceneGraph(windowSize, rhi ? cd->swapchain->currentPixelSize() : QSize()); if (profileFrames) renderTime = threadTimer.nsecsElapsed(); diff --git a/src/quick/scenegraph/util/qsgopenglatlastexture.cpp b/src/quick/scenegraph/util/qsgopenglatlastexture.cpp index ae7d9cf8cc..75a874424a 100644 --- a/src/quick/scenegraph/util/qsgopenglatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgopenglatlastexture.cpp @@ -150,6 +150,10 @@ QSGTexture *Manager::create(const QSGCompressedTextureFactory *factory) case QOpenGLTexture::RGB8_ETC2: case QOpenGLTexture::RGBA8_ETC2_EAC: case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2: + case QOpenGLTexture::RGB_DXT1: + case QOpenGLTexture::RGBA_DXT1: + case QOpenGLTexture::RGBA_DXT3: + case QOpenGLTexture::RGBA_DXT5: break; default: return t; @@ -158,8 +162,12 @@ QSGTexture *Manager::create(const QSGCompressedTextureFactory *factory) QSize size = factory->m_textureData.size(); if (size.width() < m_atlas_size_limit && size.height() < m_atlas_size_limit) { QHash<unsigned int, QSGCompressedAtlasTexture::Atlas*>::iterator i = m_atlases.find(format); - if (i == m_atlases.end()) - i = m_atlases.insert(format, new QSGCompressedAtlasTexture::Atlas(m_atlas_size, format)); + if (i == m_atlases.end()) { + // must be multiple of 4 + QSize paddedSize(((m_atlas_size.width() + 3) / 4) * 4, ((m_atlas_size.height() + 3) / 4) * 4); + i = m_atlases.insert(format, new QSGCompressedAtlasTexture::Atlas(paddedSize, format)); + } + // must be multiple of 4 QSize paddedSize(((size.width() + 3) / 4) * 4, ((size.height() + 3) / 4) * 4); QByteArray data = factory->m_textureData.data(); diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 1c895eb793..f1ff396d4f 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -4888,6 +4888,7 @@ void tst_QJSEngine::interrupt_data() QTest::addRow("labeled continue / %s", mode) << i << "a: while (true) { for (;;) { continue a; } }"; QTest::addRow("labeled break / %s", mode) << i << "while (true) { a: for (;;) { break a; } }"; QTest::addRow("tail call / %s", mode) << i << "'use strict';\nfunction x() { return x(); }; x();"; + QTest::addRow("huge array join / %s", mode) << i << "Array(1E9)|1"; } } diff --git a/tests/auto/qml/qmlcachegen/data/parameterAdjustment.qml b/tests/auto/qml/qmlcachegen/data/parameterAdjustment.qml new file mode 100644 index 0000000000..2128a54d81 --- /dev/null +++ b/tests/auto/qml/qmlcachegen/data/parameterAdjustment.qml @@ -0,0 +1,7 @@ +import QtQml 2.12 + +QtObject { + signal testSignal(string a, int b, string c, bool d, bool e, real f, real g, bool h, int i, int j, string k, int l, string m, string n) + onTestSignal: {} + Component.onCompleted: testSignal("a", 1, "b", true, true, 0.1, 0.1, true, 1, 1, "a", 1, "a", "a") +} diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro index 1a334b68ce..452bd7d04a 100644 --- a/tests/auto/qml/qmlcachegen/qmlcachegen.pro +++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro @@ -17,7 +17,8 @@ RESOURCES += \ data/jsmoduleimport.qml \ data/script.mjs \ data/module.mjs \ - data/utils.mjs + data/utils.mjs \ + data/parameterAdjustment.qml workerscripts_test.files = \ data/worker.js \ diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index 5d87c319f3..f940f9c476 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -73,6 +73,8 @@ private slots: void reproducibleCache_data(); void reproducibleCache(); + + void parameterAdjustment(); }; // A wrapper around QQmlComponent to ensure the temporary reference counts @@ -664,6 +666,14 @@ void tst_qmlcachegen::reproducibleCache() QCOMPARE(contents1, contents2); } +void tst_qmlcachegen::parameterAdjustment() +{ + QQmlEngine engine; + CleanlyLoadingComponent component(&engine, QUrl("qrc:///data/parameterAdjustment.qml")); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); // Doesn't crash +} + QTEST_GUILESS_MAIN(tst_qmlcachegen) #include "tst_qmlcachegen.moc" diff --git a/tests/auto/qml/qmlmin/tst_qmlmin.cpp b/tests/auto/qml/qmlmin/tst_qmlmin.cpp index 79a73299a4..e7498a8583 100644 --- a/tests/auto/qml/qmlmin/tst_qmlmin.cpp +++ b/tests/auto/qml/qmlmin/tst_qmlmin.cpp @@ -130,6 +130,7 @@ void tst_qmlmin::initTestCase() invalidFiles << "tests/auto/qml/qjsengine/script/com/trolltech/syntaxerror/__init__.js"; invalidFiles << "tests/auto/qml/debugger/qqmlpreview/data/broken.qml"; invalidFiles << "tests/auto/qml/qqmllanguage/data/fuzzed.2.qml"; + invalidFiles << "tests/auto/qml/qqmllanguage/data/fuzzed.3.qml"; invalidFiles << "tests/auto/qml/qqmllanguage/data/requiredProperties.2.qml"; invalidFiles << "tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml"; // generatorFunction.qml is not invalid per se, but the minifier cannot handle yield statements diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index d9cb6673df..6754f22049 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -895,16 +895,27 @@ void tst_qqmlcontext::contextObjectHierarchy() void tst_qqmlcontext::destroyContextProperty() { - QQmlEngine engine; - QQmlContext context(&engine); - + QScopedPointer<QQmlContext> context; + QScopedPointer<QObject> objectThatOutlivesEngine(new QObject); { - QObject object; - context.setContextProperty(QLatin1String("a"), &object); - QCOMPARE(qvariant_cast<QObject *>(context.contextProperty(QLatin1String("a"))), &object); + QQmlEngine engine; + context.reset(new QQmlContext(&engine)); + + { + QObject object; + context->setContextProperty(QLatin1String("a"), &object); + QCOMPARE(qvariant_cast<QObject *>(context->contextProperty(QLatin1String("a"))), &object); + } + + QCOMPARE(qvariant_cast<QObject *>(context->contextProperty(QLatin1String("a"))), nullptr); + context->setContextProperty(QLatin1String("b"), objectThatOutlivesEngine.data()); } - QCOMPARE(qvariant_cast<QObject *>(context.contextProperty(QLatin1String("a"))), nullptr); + // dropDestroyedObject() should not crash, even if the engine is gone. + objectThatOutlivesEngine.reset(); + + // We're not allowed to call context->contextProperty("b") anymore. + // TODO: Or are we? } QTEST_MAIN(tst_qqmlcontext) diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.3.errors.txt b/tests/auto/qml/qqmllanguage/data/fuzzed.3.errors.txt new file mode 100644 index 0000000000..da17dc5599 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/fuzzed.3.errors.txt @@ -0,0 +1,2 @@ +3:2:Unexpected token `version number' +1:1:Expected a qualified name id or a string literal diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.3.qml b/tests/auto/qml/qqmllanguage/data/fuzzed.3.qml Binary files differnew file mode 100644 index 0000000000..6861ebf8a9 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/fuzzed.3.qml diff --git a/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt b/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt index 043f714636..887d87b9fb 100644 --- a/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt +++ b/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt @@ -1 +1 @@ -4:18:Can not assign value of type "MyTypeObject" to property "x", expecting "int" +4:18:Cannot assign value of type "MyTypeObject" to property "x", expecting "int" diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 4b7e643a26..380925ded8 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -627,6 +627,7 @@ void tst_qqmllanguage::errors_data() QTest::newRow("fuzzed.1") << "fuzzed.1.qml" << "fuzzed.1.errors.txt" << false; QTest::newRow("fuzzed.2") << "fuzzed.2.qml" << "fuzzed.2.errors.txt" << false; + QTest::newRow("fuzzed.3") << "fuzzed.3.qml" << "fuzzed.3.errors.txt" << false; QTest::newRow("bareQmlImport") << "bareQmlImport.qml" << "bareQmlImport.errors.txt" << false; diff --git a/tests/auto/qml/qqmlproperty/data/interfaceBinding.qml b/tests/auto/qml/qqmlproperty/data/interfaceBinding.qml new file mode 100644 index 0000000000..4e72a75f42 --- /dev/null +++ b/tests/auto/qml/qqmlproperty/data/interfaceBinding.qml @@ -0,0 +1,27 @@ +import QtQuick 2.12 +import io.qt.bugreports 1.0 +Item { + InterfaceConsumer { + objectName: "a1" + i: A { + property int i: 42 + } + } + + InterfaceConsumer { + objectName: "a2" + property A a: A { + property int i: 43 + } + i: a + } + + InterfaceConsumer { + objectName: "a3" + property A a: A { + id : aa + property int i: 44 + } + i: aa + } +} diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 1a5927fa74..51267f1662 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -40,6 +40,7 @@ #endif #include <QtCore/private/qobject_p.h> #include "../../shared/util.h" +#include "qobject.h" #include <QDebug> class MyQmlObject : public QObject @@ -148,6 +149,7 @@ private slots: void readOnlyDynamicProperties(); void aliasToIdWithMatchingQmlFileNameOnCaseInsensitiveFileSystem(); void nullPropertyBinding(); + void interfaceBinding(); void floatToStringPrecision_data(); void floatToStringPrecision(); @@ -2083,6 +2085,83 @@ void tst_qqmlproperty::nullPropertyBinding() QMetaObject::invokeMethod(root.get(), "tog"); } +struct Interface { +}; + +QT_BEGIN_NAMESPACE +#define MyInterface_iid "io.qt.bugreports.Interface" +Q_DECLARE_INTERFACE(Interface, MyInterface_iid); +QT_END_NAMESPACE + +class A : public QObject, Interface { + Q_OBJECT + Q_INTERFACES(Interface) +}; + +class B : public QObject, Interface { + Q_OBJECT + Q_INTERFACES(Interface) +}; + +class C : public QObject { + Q_OBJECT +}; + +class InterfaceConsumer : public QObject { + Q_OBJECT + Q_PROPERTY(Interface* i READ interface WRITE setInterface NOTIFY interfaceChanged) + Q_PROPERTY(int testValue READ testValue NOTIFY testValueChanged) + + +public: + + Interface* interface() const + { + return m_interface; + } + void setInterface(Interface* interface) + { + QObject* object = reinterpret_cast<QObject*>(interface); + m_testValue = object->property("i").toInt(); + emit testValueChanged(); + if (m_interface == interface) + return; + + m_interface = interface; + emit interfaceChanged(); + } + + int testValue() { + return m_testValue; + } + +signals: + void interfaceChanged(); + void testValueChanged(); + +private: + Interface* m_interface = nullptr; + int m_testValue = 0; +}; +void tst_qqmlproperty::interfaceBinding() +{ + + qmlRegisterInterface<Interface>("Interface"); + qmlRegisterType<A>("io.qt.bugreports", 1, 0, "A"); + qmlRegisterType<B>("io.qt.bugreports", 1, 0, "B"); + qmlRegisterType<C>("io.qt.bugreports", 1, 0, "C"); + qmlRegisterType<InterfaceConsumer>("io.qt.bugreports", 1, 0, "InterfaceConsumer"); + + const QUrl url = testFileUrl("interfaceBinding.qml"); + QQmlEngine engine; + QQmlComponent component(&engine, url); + QScopedPointer<QObject> root(component.create()); + QVERIFY(root); + QCOMPARE(root->findChild<QObject*>("a1")->property("testValue").toInt(), 42); + QCOMPARE(root->findChild<QObject*>("a2")->property("testValue").toInt(), 43); + QCOMPARE(root->findChild<QObject*>("a3")->property("testValue").toInt(), 44); +} + void tst_qqmlproperty::floatToStringPrecision_data() { QTest::addColumn<QString>("propertyName"); |