qmllint: Resolve generalized grouped properties

Change-Id: I4c407e2332823f1a4274f55b07635d50dc0186ed
Reviewed-by: Maximilian Goldstein <max.goldstein@qt.io>
This commit is contained in:
Ulf Hermann 2021-10-27 11:11:04 +02:00
parent 85b5413dc4
commit 8591568c75
9 changed files with 81 additions and 6 deletions

View File

@ -155,7 +155,12 @@ void QQmlJSImportVisitor::leaveEnvironment()
m_currentScope = m_currentScope->parentScope();
}
void QQmlJSImportVisitor::resolveAliases()
static bool mayBeUnresolvedGeneralizedGroupedProperty(const QQmlJSScope::ConstPtr &scope)
{
return scope->scopeType() == QQmlJSScope::GroupedPropertyScope && !scope->baseType();
}
void QQmlJSImportVisitor::resolveAliasesAndIds()
{
QQueue<QQmlJSScope::Ptr> objects;
objects.enqueue(m_exportedRootScope);
@ -234,8 +239,19 @@ void QQmlJSImportVisitor::resolveAliases()
}
const auto childScopes = object->childScopes();
for (const auto &childScope : childScopes)
for (const auto &childScope : childScopes) {
if (mayBeUnresolvedGeneralizedGroupedProperty(childScope)) {
const QString name = childScope->internalName();
if (object->isNameDeferred(name)) {
auto it = m_scopesById.find(name);
if (it != m_scopesById.end()) {
QQmlJSScope::resolveGeneralizedGroup(
childScope, *it, m_rootScopeImports, &m_usedTypes);
}
}
}
objects.enqueue(childScope);
}
if (doRequeue)
requeue.enqueue(object);
@ -349,8 +365,6 @@ void QQmlJSImportVisitor::endVisit(UiProgram *)
for (const auto &scope : m_objectDefinitionScopes) {
if (checkInheritanceCycle(scope) == CycleFound)
return;
checkGroupedAndAttachedScopes(scope);
}
for (const auto &scope : m_pendingDefaultProperties.keys()) {
@ -358,7 +372,11 @@ void QQmlJSImportVisitor::endVisit(UiProgram *)
return;
}
resolveAliases();
resolveAliasesAndIds();
for (const auto &scope : m_objectDefinitionScopes)
checkGroupedAndAttachedScopes(scope);
processDefaultProperties();
processPropertyTypes();
processPropertyBindings();

View File

@ -261,7 +261,7 @@ protected:
private:
void importBaseModules();
void resolveAliases();
void resolveAliasesAndIds();
void visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr);
void processImportWarnings(const QString &what, const QQmlJS::SourceLocation &srcLocation = QQmlJS::SourceLocation());
void addImportWithLocation(const QString &name, const QQmlJS::SourceLocation &loc);

View File

@ -432,6 +432,14 @@ void QQmlJSScope::resolveEnums(const QQmlJSScope::Ptr &self,
}
}
void QQmlJSScope::resolveGeneralizedGroup(const Ptr &self, const ConstPtr &baseType,
const QHash<QString, ConstPtr> &contextualTypes,
QSet<QString> *usedTypes)
{
self->m_baseType = baseType;
resolveNonEnumTypes(self, contextualTypes, usedTypes);
}
QQmlJSScope::ConstPtr QQmlJSScope::findCurrentQMLScope(const QQmlJSScope::ConstPtr &scope)
{
auto qmlScope = scope;

View File

@ -340,6 +340,10 @@ public:
static void resolveEnums(const QQmlJSScope::Ptr &self,
const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
QSet<QString> *usedTypes = nullptr);
static void resolveGeneralizedGroup(const QQmlJSScope::Ptr &self,
const QQmlJSScope::ConstPtr &baseType,
const QHash<QString, ConstPtr> &contextualTypes,
QSet<QString> *usedTypes = nullptr);
void setSourceLocation(const QQmlJS::SourceLocation &sourceLocation)
{

View File

@ -38,6 +38,14 @@ Module {
Property { name: "contentData"; type: "QObject"; isList: true; isReadonly: true }
Property { name: "contentChildren"; type: "QQuickItem"; isList: true; isReadonly: true }
}
Component {
name: "WithImmediate"
prototype: "QObject"
exports: ["Things/WithImmediate 1.0"]
exportMetaObjectRevisions: [256]
immediateNames: ["contentData"]
Property { name: "contentData"; type: "double" }
}
Component {
name: "MyScreen"
prototype: "QObject"

View File

@ -0,0 +1,9 @@
import QtQuick
import Things
Item {
id: self
WithImmediate {
self.aaaa: 15 - 1
}
}

View File

@ -0,0 +1,9 @@
import QtQuick
import Things
Item {
id: self
WithImmediate {
aself.x: 15 - 1
}
}

View File

@ -0,0 +1,9 @@
import QtQuick
import Things
Item {
id: self
WithImmediate {
self.x: 15 - 1
}
}

View File

@ -705,6 +705,15 @@ void TestQmllint::dirtyQmlCode_data()
<< QStringLiteral("cycleHead.qml")
<< QStringLiteral("MenuItem is part of an inheritance cycle: MenuItem -> MenuItem")
<< QString() << false;
QTest::newRow("badGeneralizedGroup1")
<< QStringLiteral("badGeneralizedGroup1.qml")
<< QStringLiteral("Binding assigned to \"aaaa\", "
"but no property \"aaaa\" exists in the current element")
<< QString() << false;
QTest::newRow("badGeneralizedGroup2")
<< QStringLiteral("badGeneralizedGroup2.qml")
<< QStringLiteral("unknown grouped property scope aself")
<< QString() << false;
}
void TestQmllint::dirtyQmlCode()
@ -859,6 +868,7 @@ void TestQmllint::cleanQmlCode_data()
QTest::newRow("bytearray") << QStringLiteral("bytearray.qml");
QTest::newRow("initReadonly") << QStringLiteral("initReadonly.qml");
QTest::newRow("connectionNoParent") << QStringLiteral("connectionNoParent.qml"); // QTBUG-97600
QTest::newRow("goodGeneralizedGroup") << QStringLiteral("goodGeneralizedGroup.qml");
}
void TestQmllint::cleanQmlCode()