aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2021-02-18 10:32:53 +0100
committerUlf Hermann <ulf.hermann@qt.io>2021-02-19 13:14:16 +0100
commite59957d2c46bb52ab5fefeb91ace7e192558373a (patch)
tree30d00552dff87d66a376df7f35706c7e7ffd52ab
parent33937b28180d8e653e47b9e34c03972553976c6f (diff)
qmllint: Resolve attached property scopes
Previously, all attached property scopes were just ignored. Task-number: QTBUG-84369 Change-Id: I324becf92402eacea9d150e6e51359edae562dde Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit f34ecc8f99522b69d1aaa3d5d233add9ed9b6da9)
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp16
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp39
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h4
-rw-r--r--tests/auto/qml/qmllint/data/attached.qml5
-rw-r--r--tests/auto/qml/qmllint/data/badAttached.qml5
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp5
-rw-r--r--tools/qmllint/findwarnings.cpp36
-rw-r--r--tools/qmllint/findwarnings.h2
8 files changed, 69 insertions, 43 deletions
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index a1de41e3ca..8b57ac9b54 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -52,7 +52,7 @@ void QQmlJSImportVisitor::enterEnvironment(QQmlJSScope::ScopeType type, const QS
const QQmlJS::SourceLocation &location)
{
m_currentScope = QQmlJSScope::create(type, m_currentScope);
- if (type == QQmlJSScope::GroupedPropertyScope)
+ if (type == QQmlJSScope::GroupedPropertyScope || type == QQmlJSScope::AttachedPropertyScope)
m_currentScope->setInternalName(name);
else
m_currentScope->setBaseTypeName(name);
@@ -136,7 +136,6 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition)
void QQmlJSImportVisitor::endVisit(UiObjectDefinition *)
{
m_currentScope->resolveTypes(m_rootScopeImports);
- m_currentScope->resolveGroupedScopes();
leaveEnvironment();
}
@@ -261,16 +260,20 @@ bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
for (auto group = id; group->next; group = group->next) {
const QString name = group->name.toString();
- if (name.isEmpty() || name.front().isUpper())
- break; // TODO: uppercase grouped scopes are attached properties. Handle them.
+ if (name.isEmpty())
+ break;
- enterEnvironment(QQmlJSScope::GroupedPropertyScope, name, group->firstSourceLocation());
+ enterEnvironment(name.front().isUpper() ? QQmlJSScope::AttachedPropertyScope
+ : QQmlJSScope::GroupedPropertyScope,
+ name, group->firstSourceLocation());
}
// TODO: remember the actual binding, once we can process it.
- while (m_currentScope->scopeType() == QQmlJSScope::GroupedPropertyScope)
+ while (m_currentScope->scopeType() == QQmlJSScope::GroupedPropertyScope
+ || m_currentScope->scopeType() == QQmlJSScope::AttachedPropertyScope) {
leaveEnvironment();
+ }
if (!statement || !statement->expression->asFunctionDefinition()) {
enterEnvironment(QQmlJSScope::JSFunctionScope, QStringLiteral("binding"),
@@ -497,7 +500,6 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
void QQmlJSImportVisitor::endVisit(QQmlJS::AST::UiObjectBinding *uiob)
{
m_currentScope->resolveTypes(m_rootScopeImports);
- m_currentScope->resolveGroupedScopes();
const QQmlJSScope::ConstPtr childScope = m_currentScope;
leaveEnvironment();
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index 1fe22ab5a8..64fa44ef82 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -237,28 +237,31 @@ void QQmlJSScope::resolveTypes(const QHash<QString, QQmlJSScope::ConstPtr> &cont
it->setParameterTypes(paramTypes);
}
-}
-void QQmlJSScope::resolveGroupedScopes()
-{
for (auto it = m_childScopes.begin(), end = m_childScopes.end(); it != end; ++it) {
QQmlJSScope::Ptr childScope = *it;
- if (childScope->scopeType() != QQmlJSScope::GroupedPropertyScope)
- continue;
-
- const QString propertyName = childScope->internalName();
- auto findProperty = [&](const QQmlJSScope *type) {
- auto propertyIt = type->m_properties.find(propertyName);
- if (propertyIt != type->m_properties.end()) {
- childScope->m_baseType = QQmlJSScope::ConstPtr(propertyIt->type());
- childScope->m_baseTypeName = propertyIt->typeName();
- return true;
+ switch (childScope->scopeType()) {
+ case QQmlJSScope::GroupedPropertyScope:
+ searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *type) {
+ const auto propertyIt = type->m_properties.find(childScope->internalName());
+ if (propertyIt != type->m_properties.end()) {
+ childScope->m_baseType = QQmlJSScope::ConstPtr(propertyIt->type());
+ childScope->m_baseTypeName = propertyIt->typeName();
+ return true;
+ }
+ return false;
+ });
+ break;
+ case QQmlJSScope::AttachedPropertyScope:
+ if (const auto attachedBase = findType(childScope->internalName())) {
+ childScope->m_baseType = attachedBase->attachedType();
+ childScope->m_baseTypeName = attachedBase->attachedTypeName();
}
- return false;
- };
-
- searchBaseAndExtensionTypes(this, findProperty);
- childScope->resolveGroupedScopes();
+ break;
+ default:
+ break;
+ }
+ childScope->resolveTypes(contextualTypes);
}
}
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index 9cb08c655e..8f095cffbf 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -95,7 +95,8 @@ public:
JSFunctionScope,
JSLexicalScope,
QMLScope,
- GroupedPropertyScope
+ GroupedPropertyScope,
+ AttachedPropertyScope
};
enum class AccessSemantics {
@@ -260,7 +261,6 @@ public:
}
void resolveTypes(const QHash<QString, ConstPtr> &contextualTypes);
- void resolveGroupedScopes();
void setSourceLocation(const QQmlJS::SourceLocation &sourceLocation)
{
diff --git a/tests/auto/qml/qmllint/data/attached.qml b/tests/auto/qml/qmllint/data/attached.qml
new file mode 100644
index 0000000000..0fcf3cacc6
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/attached.qml
@@ -0,0 +1,5 @@
+import QtQml
+
+QtObject {
+ Component.objectName: "foobar"
+}
diff --git a/tests/auto/qml/qmllint/data/badAttached.qml b/tests/auto/qml/qmllint/data/badAttached.qml
new file mode 100644
index 0000000000..93d64ec8ae
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/badAttached.qml
@@ -0,0 +1,5 @@
+import QtQml
+
+QtObject {
+ WrongAttached.foo: "bar"
+}
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index c8e0dd2db3..a86c202790 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -302,6 +302,10 @@ void TestQmllint::dirtyQmlCode_data()
<< QStringLiteral("onAssignment.qml")
<< QStringLiteral("Property \"loops\" not found on type \"bool\"")
<< QString();
+ QTest::newRow("BadAttached")
+ << QStringLiteral("badAttached.qml")
+ << QStringLiteral("unknown attached property scope WrongAttached.")
+ << QString();
}
void TestQmllint::dirtyQmlCode()
@@ -366,6 +370,7 @@ void TestQmllint::cleanQmlCode_data()
QTest::newRow("segFault") << QStringLiteral("SegFault.qml");
QTest::newRow("grouped scope failure") << QStringLiteral("groupedScope.qml");
QTest::newRow("layouts depends quick") << QStringLiteral("layouts.qml");
+ QTest::newRow("attached") << QStringLiteral("attached.qml");
}
void TestQmllint::cleanQmlCode()
diff --git a/tools/qmllint/findwarnings.cpp b/tools/qmllint/findwarnings.cpp
index 110f6d4627..c238f874e2 100644
--- a/tools/qmllint/findwarnings.cpp
+++ b/tools/qmllint/findwarnings.cpp
@@ -90,25 +90,31 @@ void FindWarningVisitor::checkInheritanceCycle(QQmlJSScope::ConstPtr scope)
}
}
-void FindWarningVisitor::checkGroupedScopes(QQmlJSScope::ConstPtr scope)
+void FindWarningVisitor::checkGroupedAndAttachedScopes(QQmlJSScope::ConstPtr scope)
{
auto children = scope->childScopes();
while (!children.isEmpty()) {
auto childScope = children.takeFirst();
- if (childScope->scopeType() != QQmlJSScope::GroupedPropertyScope)
- continue;
-
- if (!childScope->baseType()) {
- m_errors.append({
- QStringLiteral("unknown grouped property scope %1.")
- .arg(childScope->internalName()),
- QtWarningMsg,
- childScope->sourceLocation()
- });
- m_visitFailed = true;
+ const auto type = childScope->scopeType();
+ switch (type) {
+ case QQmlJSScope::GroupedPropertyScope:
+ case QQmlJSScope::AttachedPropertyScope:
+ if (!childScope->baseType()) {
+ m_errors.append({
+ QStringLiteral("unknown %1 property scope %2.")
+ .arg(type == QQmlJSScope::GroupedPropertyScope
+ ? QStringLiteral("grouped")
+ : QStringLiteral("attached"),
+ childScope->internalName()),
+ QtWarningMsg,
+ childScope->sourceLocation()
+ });
+ m_visitFailed = true;
+ }
+ children.append(childScope->childScopes());
+ default:
+ break;
}
-
- children.append(childScope->childScopes());
}
}
@@ -489,7 +495,7 @@ void FindWarningVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *uiod)
QQmlJSImportVisitor::endVisit(uiod);
if (m_warnUnqualified)
- checkGroupedScopes(childScope);
+ checkGroupedAndAttachedScopes(childScope);
if (m_currentScope == m_globalScope
|| m_currentScope->baseTypeName() == QStringLiteral("Component")) {
diff --git a/tools/qmllint/findwarnings.h b/tools/qmllint/findwarnings.h
index 138f83098d..30ee47705e 100644
--- a/tools/qmllint/findwarnings.h
+++ b/tools/qmllint/findwarnings.h
@@ -91,7 +91,7 @@ private:
QVarLengthArray<OutstandingConnection, 3> m_outstandingConnections; // Connections whose target we have not encountered
void checkInheritanceCycle(QQmlJSScope::ConstPtr scope);
- void checkGroupedScopes(QQmlJSScope::ConstPtr scope);
+ void checkGroupedAndAttachedScopes(QQmlJSScope::ConstPtr scope);
void flushPendingSignalParameters();
void throwRecursionDepthError() override;