aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeniy A. Dushistov <dushistov@mail.ru>2020-06-18 21:52:58 +0300
committerEvgeniy A. Dushistov <dushistov@mail.ru>2020-06-19 16:35:16 +0300
commitaa8d5a45930dcfce7f25878fa36c1595b1dfc023 (patch)
treec456df207790ca5af31d9367ab184037d6696c3e
parent9139373c9b3a8cd8541e0253bdf72cf939726e92 (diff)
qmllint: search methods and properties also in attached type
I changed the strategy of traverse via related types. Before: traversal happens only via linked list type -> type->superClass After: traversal via binary tree formed by attachedType and superClass I use pre-order strategy, current type, then all attached types, then all super classes Fixes: QTBUG-84861 Change-Id: I4a8fce869bc541de6900514d29575174d2753f02 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--tests/auto/qml/qmllint/data/AttachedType.qml5
-rw-r--r--tests/auto/qml/qmllint/data/Things/plugins.qmltypes25
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp1
-rw-r--r--tools/qmllint/checkidentifiers.cpp67
4 files changed, 76 insertions, 22 deletions
diff --git a/tests/auto/qml/qmllint/data/AttachedType.qml b/tests/auto/qml/qmllint/data/AttachedType.qml
new file mode 100644
index 0000000000..02fa514e83
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/AttachedType.qml
@@ -0,0 +1,5 @@
+import Things 1.0
+
+Item {
+ property real test: Screen.pixelDensity * 0.5
+}
diff --git a/tests/auto/qml/qmllint/data/Things/plugins.qmltypes b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
index 95ff95eb7d..448a966145 100644
--- a/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
+++ b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
@@ -30,4 +30,29 @@ Module {
Property { name: "contentData"; type: "QObject"; isList: true; isReadonly: true }
Property { name: "contentChildren"; type: "QQuickItem"; isList: true; isReadonly: true }
}
+ Component {
+ name: "MyScreen"
+ prototype: "QObject"
+ exports: [
+ "Things.Window/Screen 1.0",
+ ]
+ isCreatable: false
+ attachedType: "MyScreenAttached"
+ }
+ Component {
+ name: "MyScreenAttached"
+ prototype: "MyScreenInfo"
+ exports: [
+ "Things.Window/ScreenAttached 1.0",
+ ]
+ }
+ Component {
+ name: "MyScreenInfo"
+ prototype: "QObject"
+ exports: [
+ "Things.Window/ScreenInfo 1.0",
+ ]
+ isCreatable: false
+ Property { name: "pixelDensity"; type: "double"; isReadonly: true }
+ }
}
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index 7459a813be..d5912def6b 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -223,6 +223,7 @@ void TestQmllint::cleanQmlCode_data()
QTest::newRow("EnumAccess1") << QStringLiteral("EnumAccess1.qml");
QTest::newRow("EnumAccess2") << QStringLiteral("EnumAccess2.qml");
QTest::newRow("ListProperty") << QStringLiteral("ListProperty.qml");
+ QTest::newRow("AttachedType") << QStringLiteral("AttachedType.qml");
}
void TestQmllint::cleanQmlCode()
diff --git a/tools/qmllint/checkidentifiers.cpp b/tools/qmllint/checkidentifiers.cpp
index 32eb4ce025..2771e1cfb2 100644
--- a/tools/qmllint/checkidentifiers.cpp
+++ b/tools/qmllint/checkidentifiers.cpp
@@ -31,6 +31,7 @@
#include <QtCore/qqueue.h>
#include <QtCore/qsharedpointer.h>
+#include <stack>
class IssueLocationWithContext
{
@@ -82,6 +83,30 @@ void CheckIdentifiers::printContext(const QQmlJS::SourceLocation &location) cons
+ QLatin1Char('\n'), Normal);
}
+static bool walkViaParentAndAttachedScopes(ScopeTree::ConstPtr rootType,
+ const QHash<QString, ScopeTree::ConstPtr> &allTypes,
+ std::function<bool(ScopeTree::ConstPtr)> visit)
+{
+ if (rootType == nullptr)
+ return false;
+ std::stack<ScopeTree::ConstPtr> stack;
+ stack.push(rootType);
+ while (!stack.empty()) {
+ const auto type = stack.top();
+ stack.pop();
+
+ if (visit(type))
+ return true;
+
+ if (auto superType = allTypes.value(type->superclassName()))
+ stack.push(superType);
+
+ if (auto attachedType = allTypes.value(type->attachedTypeName()))
+ stack.push(attachedType);
+ }
+ return false;
+}
+
bool CheckIdentifiers::checkMemberAccess(const QVector<ScopeTree::FieldMember> &members,
const ScopeTree::ConstPtr &outerScope,
const MetaProperty *prop) const
@@ -199,29 +224,27 @@ bool CheckIdentifiers::checkMemberAccess(const QVector<ScopeTree::FieldMember> &
if (!detectedRestrictiveName.isEmpty())
continue;
- auto type = m_types.value(access.m_parentType.isEmpty() ? scopeName : access.m_parentType);
- bool typeFound = false;
- while (type) {
- const auto typeProperties = type->properties();
- const auto typeIt = typeProperties.find(access.m_name);
- if (typeIt != typeProperties.end()) {
- const ScopeTree::ConstPtr propType = typeIt->type();
- scope = propType ? propType : m_types.value(typeIt->typeName());
- typeFound = true;
- break;
- }
-
- const auto typeMethods = type->methods();
- const auto typeMethodIt = typeMethods.find(access.m_name);
- if (typeMethodIt != typeMethods.end()) {
- detectedRestrictiveName = access.m_name;
- detectedRestrictiveKind = QLatin1String("method");
- typeFound = true;
- break;
- }
+ auto rootType =
+ m_types.value(access.m_parentType.isEmpty() ? scopeName : access.m_parentType);
+ bool typeFound =
+ walkViaParentAndAttachedScopes(rootType, m_types, [&](ScopeTree::ConstPtr type) {
+ const auto typeProperties = type->properties();
+ const auto typeIt = typeProperties.find(access.m_name);
+ if (typeIt != typeProperties.end()) {
+ const ScopeTree::ConstPtr propType = typeIt->type();
+ scope = propType ? propType : m_types.value(typeIt->typeName());
+ return true;
+ }
- type = m_types.value(type->superclassName());
- }
+ const auto typeMethods = type->methods();
+ const auto typeMethodIt = typeMethods.find(access.m_name);
+ if (typeMethodIt != typeMethods.end()) {
+ detectedRestrictiveName = access.m_name;
+ detectedRestrictiveKind = QLatin1String("method");
+ return true;
+ }
+ return false;
+ });
if (typeFound)
continue;