aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier De Cannière <olivier.decanniere@qt.io>2023-09-27 12:07:27 +0200
committerOlivier De Cannière <olivier.decanniere@qt.io>2023-10-02 10:26:26 +0200
commite6ec87d354a55e6e6f4e0231250b1568e34ffe01 (patch)
treeca9c4a515e1f42d357fab6a5ddf0057b99b8ce23
parent5a643eb8c35afec5a4d6c33d4faf8b707fb7a705 (diff)
TypeResolver: Change the way member types of scopes are searched for
When searching for a member of a scope, we now first search the starting scope and its base and extension scopes for QML properties and methods. Then, if the member has not been found yet, we search for a JS identifier in the part of the scope hierarchy that are JS scopes. This change fixes an issue in qmllint where it would warn of functions not being found when they were, in fact, being called and thus found at runtime. For example, an object with an invokable function 'print' would generate a warning that the function could not be found because it was being confused with the global function print, interupting the search. The latter was later discarded as a valid result for the search thus leading to the warning that no function was found. Fixes: QTBUG-117077 Change-Id: I9899cefe452ed33b7f7f9b3cbceb1f5a5e080269 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Sami Shalayel <sami.shalayel@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> (cherry picked from commit 42daf587473aff0789306c92ebc0e7621b57149c) (cherry picked from commit 0a8390881019cf9845c4cad5bb0ca9a47e25ac54)
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp7
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h1
-rw-r--r--src/qmlcompiler/qqmljstyperesolver.cpp30
-rw-r--r--tests/auto/qml/qmllint/data/TestTypes/testtypes.qmltypes7
-rw-r--r--tests/auto/qml/qmllint/data/findMemberPrint.qml13
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp1
6 files changed, 45 insertions, 14 deletions
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index e3d8bafeb3..ad9c0a4d3d 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -326,6 +326,13 @@ QQmlJSScope::findJSIdentifier(const QString &id) const
return std::optional<JavaScriptIdentifier>{};
}
+std::optional<QQmlJSScope::JavaScriptIdentifier> QQmlJSScope::JSIdentifier(const QString &id) const
+{
+ if (const auto it = m_jsIdentifiers.find(id); it != m_jsIdentifiers.cend())
+ return *it;
+ return {};
+}
+
static QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr>
qFindInlineComponents(QStringView typeName, const QQmlJSScope::ContextualTypes &contextualTypes)
{
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index b58536a688..60c84825de 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -573,6 +573,7 @@ QT_WARNING_POP
bool isIdInjectedFromSignal(const QString &id) const;
std::optional<JavaScriptIdentifier> findJSIdentifier(const QString &id) const;
+ std::optional<JavaScriptIdentifier> JSIdentifier(const QString &id) const;
ConstPtrWrapperIterator childScopesBegin() const { return m_childScopes.constBegin(); }
ConstPtrWrapperIterator childScopesEnd() const { return m_childScopes.constEnd(); }
diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp
index e8bfc7dc70..bf8bffd80b 100644
--- a/src/qmlcompiler/qqmljstyperesolver.cpp
+++ b/src/qmlcompiler/qqmljstyperesolver.cpp
@@ -1077,20 +1077,6 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSScope::ConstPtr
scope);
return true;
}
-
- if (std::optional<QQmlJSScope::JavaScriptIdentifier> identifier =
- scope->findJSIdentifier(name);
- identifier.has_value()) {
- QQmlJSMetaProperty prop;
- prop.setPropertyName(name);
- prop.setTypeName(u"QJSValue"_s);
- prop.setType(jsValueType());
- prop.setIsWritable(!identifier->isConst);
-
- result = QQmlJSRegisterContent::create(
- jsValueType(), prop, QQmlJSRegisterContent::JavaScriptObject, type);
- return true;
- }
}
return checkEnums(scope, name, &result, mode);
@@ -1099,6 +1085,22 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSScope::ConstPtr
if (QQmlJSUtils::searchBaseAndExtensionTypes(type, check))
return result;
+ for (auto scope = type;
+ scope && (scope->scopeType() == QQmlJSScope::ScopeType::JSFunctionScope
+ || scope->scopeType() == QQmlJSScope::ScopeType::JSLexicalScope);
+ scope = scope->parentScope()) {
+ if (auto ownIdentifier = scope->JSIdentifier(name)) {
+ QQmlJSMetaProperty prop;
+ prop.setPropertyName(name);
+ prop.setTypeName(u"QJSValue"_s);
+ prop.setType(jsValueType());
+ prop.setIsWritable(!(ownIdentifier.value().isConst));
+
+ return QQmlJSRegisterContent::create(jsValueType(), prop,
+ QQmlJSRegisterContent::JavaScriptObject, scope);
+ }
+ }
+
if (QQmlJSScope::ConstPtr attachedBase = typeForName(name)) {
if (QQmlJSScope::ConstPtr attached = attachedBase->attachedType()) {
if (!genericType(attached)) {
diff --git a/tests/auto/qml/qmllint/data/TestTypes/testtypes.qmltypes b/tests/auto/qml/qmllint/data/TestTypes/testtypes.qmltypes
index 562e6ea066..77ad6a3cef 100644
--- a/tests/auto/qml/qmllint/data/TestTypes/testtypes.qmltypes
+++ b/tests/auto/qml/qmllint/data/TestTypes/testtypes.qmltypes
@@ -191,4 +191,11 @@ Module {
index: 0
}
}
+ Component {
+ file: "foo.h"
+ name: "Foo"
+ prototype: "QObject"
+ exports: ["TestTypes/Foo 1.0"]
+ Method { name: "print" }
+ }
}
diff --git a/tests/auto/qml/qmllint/data/findMemberPrint.qml b/tests/auto/qml/qmllint/data/findMemberPrint.qml
new file mode 100644
index 0000000000..69146eb06b
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/findMemberPrint.qml
@@ -0,0 +1,13 @@
+import QtQml
+
+import TestTypes
+
+QtObject {
+ property var foooooooo: Foo {
+ id: foo
+ }
+
+ function f(): void {
+ foo.print()
+ }
+}
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index 44747434fb..c39464e0a3 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -1247,6 +1247,7 @@ void TestQmllint::cleanQmlCode_data()
QTest::newRow("VariantMapGetPropertyLookup") << QStringLiteral("variantMapLookup.qml");
QTest::newRow("ScriptInTemplate") << QStringLiteral("scriptInTemplate.qml");
QTest::newRow("WriteListProperty") << QStringLiteral("writeListProperty.qml");
+ QTest::newRow("dontConfuseMemberPrintWithGlobalPrint") << QStringLiteral("findMemberPrint.qml");
}
void TestQmllint::cleanQmlCode()