diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2021-02-18 10:32:53 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2021-02-19 13:14:16 +0100 |
commit | e59957d2c46bb52ab5fefeb91ace7e192558373a (patch) | |
tree | 30d00552dff87d66a376df7f35706c7e7ffd52ab | |
parent | 33937b28180d8e653e47b9e34c03972553976c6f (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.cpp | 16 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsscope.cpp | 39 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsscope_p.h | 4 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/data/attached.qml | 5 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/data/badAttached.qml | 5 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/tst_qmllint.cpp | 5 | ||||
-rw-r--r-- | tools/qmllint/findwarnings.cpp | 36 | ||||
-rw-r--r-- | tools/qmllint/findwarnings.h | 2 |
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; |