aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp25
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp21
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h4
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp8
-rw-r--r--tools/qmllint/findwarnings.cpp33
-rw-r--r--tools/qmllint/findwarnings.h2
6 files changed, 85 insertions, 8 deletions
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 04bb27dc84..bb789a1c66 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -51,7 +51,10 @@ void QQmlJSImportVisitor::enterEnvironment(QQmlJSScope::ScopeType type, const QS
const QQmlJS::SourceLocation &location)
{
m_currentScope = QQmlJSScope::create(type, m_currentScope);
- m_currentScope->setBaseTypeName(name);
+ if (type == QQmlJSScope::GroupedPropertyScope)
+ m_currentScope->setInternalName(name);
+ else
+ m_currentScope->setBaseTypeName(name);
m_currentScope->setIsComposite(true);
m_currentScope->setSourceLocation(location);
}
@@ -126,6 +129,7 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition)
void QQmlJSImportVisitor::endVisit(UiObjectDefinition *)
{
+ m_currentScope->resolveGroupedScopes();
leaveEnvironment();
}
@@ -235,11 +239,27 @@ void QQmlJSImportVisitor::endVisit(QQmlJS::AST::ClassExpression *)
bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
{
- if (scriptBinding->qualifiedId->name == QLatin1String("id")) {
+ const auto id = scriptBinding->qualifiedId;
+ if (!id->next && id->name == QLatin1String("id")) {
const auto *statement = cast<ExpressionStatement *>(scriptBinding->statement);
const auto *idExprension = cast<IdentifierExpression *>(statement->expression);
m_scopesById.insert(idExprension->name.toString(), m_currentScope);
+ } else {
+ 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.
+
+ enterEnvironment(QQmlJSScope::GroupedPropertyScope, name, group->firstSourceLocation());
+ }
+
+ // TODO: remember the actual binding, once we can process it.
+
+ while (m_currentScope->scopeType() == QQmlJSScope::GroupedPropertyScope)
+ leaveEnvironment();
}
+
return true;
}
@@ -448,6 +468,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
void QQmlJSImportVisitor::endVisit(QQmlJS::AST::UiObjectBinding *uiob)
{
+ m_currentScope->resolveGroupedScopes();
const QQmlJSScope::ConstPtr childScope = m_currentScope;
leaveEnvironment();
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index bea6c29932..0787e1062e 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -168,6 +168,27 @@ void QQmlJSScope::resolveTypes(const QHash<QString, QQmlJSScope::ConstPtr> &cont
}
}
+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();
+ for (const QQmlJSScope *type = this; type; type = type->baseType().data()) {
+ 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();
+ break;
+ }
+ }
+
+ childScope->resolveGroupedScopes();
+ }
+}
+
QQmlJSScope::ConstPtr QQmlJSScope::findCurrentQMLScope(const QQmlJSScope::ConstPtr &scope)
{
auto qmlScope = scope;
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index 175b2ecda1..99645a8071 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -94,7 +94,8 @@ public:
{
JSFunctionScope,
JSLexicalScope,
- QMLScope
+ QMLScope,
+ GroupedPropertyScope
};
enum class AccessSemantics {
@@ -221,6 +222,7 @@ public:
}
void resolveTypes(const QHash<QString, ConstPtr> &contextualTypes);
+ void resolveGroupedScopes();
void setSourceLocation(const QQmlJS::SourceLocation &sourceLocation)
{
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index d9671a6631..56dcd368c6 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -222,11 +222,11 @@ void TestQmllint::dirtyQmlCode_data()
<< QString();
QTest::newRow("nanchors2")
<< QStringLiteral("nanchors2.qml")
- << QString()
+ << QString("unknown grouped property scope nanchors.")
<< QString();
QTest::newRow("nanchors3")
<< QStringLiteral("nanchors3.qml")
- << QString()
+ << QString("unknown grouped property scope nanchors.")
<< QString();
QTest::newRow("badAliasObject")
<< QStringLiteral("badAliasObject.qml")
@@ -246,9 +246,7 @@ void TestQmllint::dirtyQmlCode()
QVERIFY(process.waitForFinished());
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
QEXPECT_FAIL("anchors3", "We don't see that QQuickItem cannot be assigned to QQuickAnchorLine", Abort);
- QEXPECT_FAIL("nanchors1", "Invalid grouped properties are not detected", Abort);
- QEXPECT_FAIL("nanchors2", "Invalid grouped properties are not detected", Abort);
- QEXPECT_FAIL("nanchors3", "Invalid grouped properties are not detected", Abort);
+ QEXPECT_FAIL("nanchors1", "Invalid grouped properties are not always detected", Abort);
QVERIFY(process.exitCode() != 0);
});
diff --git a/tools/qmllint/findwarnings.cpp b/tools/qmllint/findwarnings.cpp
index 06e647dcd5..d7880b0506 100644
--- a/tools/qmllint/findwarnings.cpp
+++ b/tools/qmllint/findwarnings.cpp
@@ -90,6 +90,28 @@ void FindWarningVisitor::checkInheritanceCycle(QQmlJSScope::ConstPtr scope)
}
}
+void FindWarningVisitor::checkGroupedScopes(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;
+ }
+
+ children.append(childScope->childScopes());
+ }
+}
+
void FindWarningVisitor::flushPendingSignalParameters()
{
const SignalHandler handler = m_signalHandlers[m_pendingSingalHandler];
@@ -349,6 +371,14 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
return true;
}
+void FindWarningVisitor::endVisit(QQmlJS::AST::UiObjectBinding *uiob)
+{
+ QQmlJSImportVisitor::endVisit(uiob);
+
+ if (m_warnUnqualified)
+ checkGroupedScopes(m_currentScope);
+}
+
bool FindWarningVisitor::visit(QQmlJS::AST::UiObjectDefinition *uiod)
{
using namespace QQmlJS::AST;
@@ -433,6 +463,9 @@ void FindWarningVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *uiod)
auto childScope = m_currentScope;
QQmlJSImportVisitor::endVisit(uiod);
+ if (m_warnUnqualified)
+ checkGroupedScopes(childScope);
+
if (m_currentScope == m_globalScope
|| m_currentScope->baseTypeName() == QStringLiteral("Component")) {
return;
diff --git a/tools/qmllint/findwarnings.h b/tools/qmllint/findwarnings.h
index 7ce8b569e8..96cd0c3897 100644
--- a/tools/qmllint/findwarnings.h
+++ b/tools/qmllint/findwarnings.h
@@ -91,6 +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 flushPendingSignalParameters();
void throwRecursionDepthError() override;
@@ -108,6 +109,7 @@ private:
/* --- end block handling --- */
bool visit(QQmlJS::AST::UiObjectBinding *uiob) override;
+ void endVisit(QQmlJS::AST::UiObjectBinding *uiob) override;
bool visit(QQmlJS::AST::UiObjectDefinition *uiod) override;
void endVisit(QQmlJS::AST::UiObjectDefinition *) override;
bool visit(QQmlJS::AST::UiScriptBinding *uisb) override;