QmlCompiler: Introduce grouped scopes
This way we can analyze the left hand part of things like "anchors.fill: parent" in qmllint. Change-Id: I0f58312566c3d5062e0fb301c2bad908ab8b8cbb Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
23813a3198
commit
ed8127cf41
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue