From a4893077c6495746abfb09d20e2aeaa42c35feac Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 22 Sep 2021 14:48:58 +0200 Subject: [PATCH] qmllint: Support "length" property of sequence types In particular, you can set and get the length of QQmlListProperty. Change-Id: I5c8e03a752aad9bf9789faf85a0c3e280f0cbb4b Reviewed-by: Maximilian Goldstein Reviewed-by: Fabian Kosmale Reviewed-by: Andrei Golubev --- src/qmlcompiler/qqmljstyperesolver.cpp | 27 +++++++++++++-------- src/qmlcompiler/qqmljstyperesolver_p.h | 1 + tests/auto/qml/qmllint/data/listIndices.qml | 14 +++++++++++ tests/auto/qml/qmllint/tst_qmllint.cpp | 8 +++++- 4 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 tests/auto/qml/qmllint/data/listIndices.qml diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp index 6ef0ec1a53..ebdf5071cc 100644 --- a/src/qmlcompiler/qqmljstyperesolver.cpp +++ b/src/qmlcompiler/qqmljstyperesolver.cpp @@ -90,7 +90,7 @@ QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer, const QmlIR::Do QQmlJSScope::Ptr listPropertyType = QQmlJSScope::create(); listPropertyType->setInternalName(u"QQmlListProperty"_qs); listPropertyType->setFileName(u"qqmllist.h"_qs); - listPropertyType->setAccessSemantics(QQmlJSScope::AccessSemantics::Value); + listPropertyType->setAccessSemantics(QQmlJSScope::AccessSemantics::Sequence); m_listPropertyType = listPropertyType; // This is pre-sorted. Don't mess it up. @@ -754,6 +754,17 @@ bool QQmlJSTypeResolver::checkEnums(const QQmlJSScope::ConstPtr &scope, const QS return false; } +QQmlJSRegisterContent QQmlJSTypeResolver::lengthProperty( + bool isWritable, const QQmlJSScope::ConstPtr &scope) const +{ + QQmlJSMetaProperty prop; + prop.setPropertyName(u"length"_qs); + prop.setTypeName(u"int"_qs); + prop.setType(intType()); + prop.setIsWritable(isWritable); + return QQmlJSRegisterContent::create(intType(), prop, QQmlJSRegisterContent::Builtin, scope); +} + QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSScope::ConstPtr &type, const QString &name) const { @@ -769,13 +780,9 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSScope::ConstPtr QQmlJSRegisterContent::JavaScriptObjectProperty, type); } - if (type == stringType() && name == u"length"_qs) { - QQmlJSMetaProperty prop; - prop.setPropertyName(name); - prop.setTypeName(u"int"_qs); - prop.setType(intType()); - prop.setIsWritable(false); - return QQmlJSRegisterContent::create(intType(), prop, QQmlJSRegisterContent::Builtin, type); + if ((type == stringType() || type->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence) + && name == u"length"_qs) { + return lengthProperty(type != stringType(), type); } const auto check = [&](const QQmlJSScope::ConstPtr &scope, BaseOrExtension mode) { @@ -859,8 +866,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSRegisterContent } if (type.isProperty()) { const auto prop = type.property(); - if (prop.isList()) - return {}; + if (prop.isList() && name == u"length"_qs) + return lengthProperty(true, listPropertyType()); return memberType(prop.type(), name); } if (type.isEnumeration()) { diff --git a/src/qmlcompiler/qqmljstyperesolver_p.h b/src/qmlcompiler/qqmljstyperesolver_p.h index 072afff314..1c9ce82d86 100644 --- a/src/qmlcompiler/qqmljstyperesolver_p.h +++ b/src/qmlcompiler/qqmljstyperesolver_p.h @@ -158,6 +158,7 @@ protected: bool isNumeric(const QQmlJSScope::ConstPtr &type) const; bool checkEnums(const QQmlJSScope::ConstPtr &scope, const QString &name, QQmlJSRegisterContent *result, BaseOrExtension mode) const; + QQmlJSRegisterContent lengthProperty(bool isWritable, const QQmlJSScope::ConstPtr &scope) const; QQmlJSScope::ConstPtr m_voidType; QQmlJSScope::ConstPtr m_numberType; diff --git a/tests/auto/qml/qmllint/data/listIndices.qml b/tests/auto/qml/qmllint/data/listIndices.qml new file mode 100644 index 0000000000..b5fda4ef0d --- /dev/null +++ b/tests/auto/qml/qmllint/data/listIndices.qml @@ -0,0 +1,14 @@ +pragma Strict +import QtQml + +QtObject { + id: self + property list items + property int numItems: items.length + + Component.onCompleted: { + items.length = 3 + for (var i = 0; i < 3; ++i) + items[i] = self + } +} diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index bd417940ce..7147fa8755 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -71,6 +71,7 @@ private Q_SLOTS: void settingsFile(); void additionalImplicitImport(); + void listIndices(); private: QString runQmllint(const QString &fileToLint, std::function handleResult, @@ -947,7 +948,12 @@ void TestQmllint::additionalImplicitImport() QVERIFY(runQmllint("additionalImplicitImport.qml", true, QStringList() << "--resource" << testFile("implicitImportResource.qrc"), false) - .isEmpty()); + .isEmpty()); +} + +void TestQmllint::listIndices() +{ + QVERIFY(runQmllint("listIndices.qml", true, {"--compiler=warning"}, false).isEmpty()); } QTEST_MAIN(TestQmllint)