From 531c757f300119d237bab5e72ccb762b7ed86e19 Mon Sep 17 00:00:00 2001 From: Andrei Golubev Date: Mon, 19 Jul 2021 16:32:18 +0200 Subject: Align qmllint default property handling with QQmlComponent model Make qmllint work on default properties that come from the base type of the scope and not from the scope itself. Otherwise, cases like: QtObject { default property QtObject child QtObject {} } become valid in qmllint (and related tooling), while this code produces an error when QQmlComponent reads it Change-Id: I347a2753b8674e53aaad6febb239c44089f08a8a Reviewed-by: Fabian Kosmale (cherry picked from commit df351e07396429b9eab35eec0cb8c0271b2b6bcf) --- src/qmlcompiler/qqmljsimportvisitor.cpp | 16 ++++++++++++---- .../qml/qmllint/data/TypeWithDefaultListProperty.qml | 4 ++++ tests/auto/qml/qmllint/data/TypeWithDefaultProperty.qml | 4 ++++ .../qml/qmllint/data/TypeWithDefaultStringProperty.qml | 4 ++++ .../auto/qml/qmllint/data/TypeWithDefaultVarProperty.qml | 4 ++++ tests/auto/qml/qmllint/data/defaultProperty.qml | 3 +-- tests/auto/qml/qmllint/data/defaultPropertyList.qml | 3 +-- tests/auto/qml/qmllint/data/defaultPropertyVar.qml | 4 +--- .../qmllint/data/defaultPropertyWithDoubleAssignment.qml | 3 +-- .../qml/qmllint/data/defaultPropertyWithWrongType.qml | 4 ++-- .../qmllint/data/defaultPropertyWithinTheSameType.qml | 6 ++++++ .../data/qmldirImport/QtObjectWithDefaultProperty.qml | 4 ++++ tests/auto/qml/qmllint/data/qmldirImport/duplicate.qml | 4 +--- .../QtObjectWithDefaultProperty.qml | 4 ++++ .../auto/qml/qmllint/data/qmldirImportAndDepend/good.qml | 3 +-- tests/auto/qml/qmllint/tst_qmllint.cpp | 8 ++++++-- 16 files changed, 56 insertions(+), 22 deletions(-) create mode 100644 tests/auto/qml/qmllint/data/TypeWithDefaultListProperty.qml create mode 100644 tests/auto/qml/qmllint/data/TypeWithDefaultProperty.qml create mode 100644 tests/auto/qml/qmllint/data/TypeWithDefaultStringProperty.qml create mode 100644 tests/auto/qml/qmllint/data/TypeWithDefaultVarProperty.qml create mode 100644 tests/auto/qml/qmllint/data/defaultPropertyWithinTheSameType.qml create mode 100644 tests/auto/qml/qmllint/data/qmldirImport/QtObjectWithDefaultProperty.qml create mode 100644 tests/auto/qml/qmllint/data/qmldirImportAndDepend/QtObjectWithDefaultProperty.qml diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp index 4aaf294835..3a3fd5d2ce 100644 --- a/src/qmlcompiler/qqmljsimportvisitor.cpp +++ b/src/qmlcompiler/qqmljsimportvisitor.cpp @@ -402,11 +402,19 @@ void QQmlJSImportVisitor::processDefaultProperties() const QQmlJSScope *scopeOfDefaultProperty = nullptr; QString defaultPropertyName; - // NB: start looking for default property in parent scope (because this - // scope is not suitable), but progress through baseType() - bool isComponent = false; - for (const auto *s = it.key().get(); s; s = s->baseType().get()) { + /* consider: + * + * QtObject { // <- it.key() + * default property var p // (1) + * QtObject {} // (2) + * } + * + * `p` (1) is a property of a subtype of QtObject, it couldn't be used + * in a property binding (2) + */ + // thus, use a base type of it.key() to detect a default property + for (const auto *s = it.key()->baseType().get(); s; s = s->baseType().get()) { defaultPropertyName = s->defaultPropertyName(); if (!defaultPropertyName.isEmpty()) { scopeOfDefaultProperty = s; diff --git a/tests/auto/qml/qmllint/data/TypeWithDefaultListProperty.qml b/tests/auto/qml/qmllint/data/TypeWithDefaultListProperty.qml new file mode 100644 index 0000000000..e30314a825 --- /dev/null +++ b/tests/auto/qml/qmllint/data/TypeWithDefaultListProperty.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + default property list children +} diff --git a/tests/auto/qml/qmllint/data/TypeWithDefaultProperty.qml b/tests/auto/qml/qmllint/data/TypeWithDefaultProperty.qml new file mode 100644 index 0000000000..e64befb764 --- /dev/null +++ b/tests/auto/qml/qmllint/data/TypeWithDefaultProperty.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + default property QtObject child +} diff --git a/tests/auto/qml/qmllint/data/TypeWithDefaultStringProperty.qml b/tests/auto/qml/qmllint/data/TypeWithDefaultStringProperty.qml new file mode 100644 index 0000000000..98c446870c --- /dev/null +++ b/tests/auto/qml/qmllint/data/TypeWithDefaultStringProperty.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + default property string child +} diff --git a/tests/auto/qml/qmllint/data/TypeWithDefaultVarProperty.qml b/tests/auto/qml/qmllint/data/TypeWithDefaultVarProperty.qml new file mode 100644 index 0000000000..9fa89833d5 --- /dev/null +++ b/tests/auto/qml/qmllint/data/TypeWithDefaultVarProperty.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + default property var child +} diff --git a/tests/auto/qml/qmllint/data/defaultProperty.qml b/tests/auto/qml/qmllint/data/defaultProperty.qml index 6284cca15c..be9368c7aa 100644 --- a/tests/auto/qml/qmllint/data/defaultProperty.qml +++ b/tests/auto/qml/qmllint/data/defaultProperty.qml @@ -1,6 +1,5 @@ import QtQml 2.0 -QtObject { - default property QtObject child +TypeWithDefaultProperty { QtObject {} } diff --git a/tests/auto/qml/qmllint/data/defaultPropertyList.qml b/tests/auto/qml/qmllint/data/defaultPropertyList.qml index fd4f0f7f98..ebf6357c34 100644 --- a/tests/auto/qml/qmllint/data/defaultPropertyList.qml +++ b/tests/auto/qml/qmllint/data/defaultPropertyList.qml @@ -1,8 +1,7 @@ import QtQml 2.0 import QtQuick 2.15 -QtObject { - default property list children +TypeWithDefaultListProperty { QtObject {} Rectangle {} } diff --git a/tests/auto/qml/qmllint/data/defaultPropertyVar.qml b/tests/auto/qml/qmllint/data/defaultPropertyVar.qml index 7aac1a9a75..1202d5384d 100644 --- a/tests/auto/qml/qmllint/data/defaultPropertyVar.qml +++ b/tests/auto/qml/qmllint/data/defaultPropertyVar.qml @@ -1,7 +1,5 @@ import QtQml 2.0 -QtObject { - default property var child - +TypeWithDefaultVarProperty { QtObject {} } diff --git a/tests/auto/qml/qmllint/data/defaultPropertyWithDoubleAssignment.qml b/tests/auto/qml/qmllint/data/defaultPropertyWithDoubleAssignment.qml index af05983f02..8c2d09fb97 100644 --- a/tests/auto/qml/qmllint/data/defaultPropertyWithDoubleAssignment.qml +++ b/tests/auto/qml/qmllint/data/defaultPropertyWithDoubleAssignment.qml @@ -1,7 +1,6 @@ import QtQml 2.0 -QtObject { - default property QtObject child +TypeWithDefaultProperty { QtObject {} QtObject {} } diff --git a/tests/auto/qml/qmllint/data/defaultPropertyWithWrongType.qml b/tests/auto/qml/qmllint/data/defaultPropertyWithWrongType.qml index b846e24790..d04fecda49 100644 --- a/tests/auto/qml/qmllint/data/defaultPropertyWithWrongType.qml +++ b/tests/auto/qml/qmllint/data/defaultPropertyWithWrongType.qml @@ -1,6 +1,6 @@ import QtQml 2.0 -QtObject { - default property string child +TypeWithDefaultStringProperty { + // default property has type `string`, so cannot assing an object to it QtObject {} } diff --git a/tests/auto/qml/qmllint/data/defaultPropertyWithinTheSameType.qml b/tests/auto/qml/qmllint/data/defaultPropertyWithinTheSameType.qml new file mode 100644 index 0000000000..6284cca15c --- /dev/null +++ b/tests/auto/qml/qmllint/data/defaultPropertyWithinTheSameType.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 + +QtObject { + default property QtObject child + QtObject {} +} diff --git a/tests/auto/qml/qmllint/data/qmldirImport/QtObjectWithDefaultProperty.qml b/tests/auto/qml/qmllint/data/qmldirImport/QtObjectWithDefaultProperty.qml new file mode 100644 index 0000000000..d33d0b5c94 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qmldirImport/QtObjectWithDefaultProperty.qml @@ -0,0 +1,4 @@ +import DuplicateImport // imports QtQml +QtObject { + default property QtObject child +} diff --git a/tests/auto/qml/qmllint/data/qmldirImport/duplicate.qml b/tests/auto/qml/qmllint/data/qmldirImport/duplicate.qml index 0040e67f7c..22f454ad44 100644 --- a/tests/auto/qml/qmllint/data/qmldirImport/duplicate.qml +++ b/tests/auto/qml/qmllint/data/qmldirImport/duplicate.qml @@ -1,8 +1,6 @@ import DuplicateImport // imports QtQml directly and indirectly via QtQuick -QtObject { - default property QtObject child - +QtObjectWithDefaultProperty { // for default property ItemDerived { // item derived has compatible QtObject type x: 4 } diff --git a/tests/auto/qml/qmllint/data/qmldirImportAndDepend/QtObjectWithDefaultProperty.qml b/tests/auto/qml/qmllint/data/qmldirImportAndDepend/QtObjectWithDefaultProperty.qml new file mode 100644 index 0000000000..fb856d0b29 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qmldirImportAndDepend/QtObjectWithDefaultProperty.qml @@ -0,0 +1,4 @@ +import Things // imports QtQml +QtObject { + default property QtObject child +} diff --git a/tests/auto/qml/qmllint/data/qmldirImportAndDepend/good.qml b/tests/auto/qml/qmllint/data/qmldirImportAndDepend/good.qml index 4e97bd6a64..987301ef76 100644 --- a/tests/auto/qml/qmllint/data/qmldirImportAndDepend/good.qml +++ b/tests/auto/qml/qmllint/data/qmldirImportAndDepend/good.qml @@ -1,7 +1,6 @@ import Things -QtObject { - default property QtObject child +QtObjectWithDefaultProperty { // for default property objectName: "QtQml was imported from Things/qmldir" ItemDerived { diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index a2cdcb07b8..79225d92de 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -510,8 +510,12 @@ void TestQmllint::dirtyQmlCode_data() << false; QTest::newRow("MissingDefaultProperty") << QStringLiteral("defaultPropertyWithoutKeyword.qml") - << QStringLiteral("Cannot assign to non-existent default property") << QString() << false; - + << QStringLiteral("Cannot assign to non-existent default property") << QString() + << false; + QTest::newRow("MissingDefaultPropertyDefinedInTheSameType") + << QStringLiteral("defaultPropertyWithinTheSameType.qml") + << QStringLiteral("Cannot assign to non-existent default property") << QString() + << false; QTest::newRow("DoubleAssignToDefaultProperty") << QStringLiteral("defaultPropertyWithDoubleAssignment.qml") << QStringLiteral("Cannot assign multiple objects to a default non-list property") -- cgit v1.2.3