aboutsummaryrefslogtreecommitdiffstats
path: root/tools/qmllint
diff options
context:
space:
mode:
authorAndrei Golubev <andrei.golubev@qt.io>2021-03-02 16:32:56 +0100
committerAndrei Golubev <andrei.golubev@qt.io>2021-03-09 10:13:34 +0100
commit602982993cb73584d9bfae91f0073384bc1e6850 (patch)
tree34f5b8fb896952367ad5308c9b7efefbacc42c35 /tools/qmllint
parent220e6a5a76d2bc91df4e3c248e5272c3d2af9967 (diff)
qmllint: check default properties
Implement the check for default properties Default aliases are not included in this patch [ChangeLog][QML][qmllint] Add support for default properties Change-Id: I2d0330e32c1f49c83d3a4ed602250b6bfd4ec674 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'tools/qmllint')
-rw-r--r--tools/qmllint/findwarnings.cpp57
-rw-r--r--tools/qmllint/findwarnings.h5
2 files changed, 62 insertions, 0 deletions
diff --git a/tools/qmllint/findwarnings.cpp b/tools/qmllint/findwarnings.cpp
index 437b32ede3..01c5f30ef7 100644
--- a/tools/qmllint/findwarnings.cpp
+++ b/tools/qmllint/findwarnings.cpp
@@ -153,6 +153,60 @@ void FindWarningVisitor::flushPendingSignalParameters()
m_pendingSingalHandler = QQmlJS::SourceLocation();
}
+void FindWarningVisitor::checkDefaultProperty(const QQmlJSScope::ConstPtr &scope)
+{
+ if (scope == m_exportedRootScope) // inapplicable
+ return;
+
+ const QQmlJSScope *scopeOfDefaultProperty = nullptr;
+ QString defaultPropertyName;
+ // NB: start looking for default property in parent scope (because this
+ // scope is not suitable), but progress through baseType()
+ for (auto s = scope->parentScope(); s; s = s->baseType()) {
+ defaultPropertyName = s->defaultPropertyName();
+ if (!defaultPropertyName.isEmpty()) {
+ scopeOfDefaultProperty = s.data();
+ break;
+ }
+ }
+ if (defaultPropertyName.isEmpty()) {
+ m_errors.append({ QStringLiteral("Cannot assign to non-existent default property"),
+ QtWarningMsg, scope->sourceLocation() });
+ m_visitFailed = true;
+ return;
+ }
+
+ Q_ASSERT(scopeOfDefaultProperty);
+ Q_ASSERT(scope->parentScope());
+ QQmlJSMetaProperty defaultProp = scopeOfDefaultProperty->property(defaultPropertyName);
+
+ // abuse QHash feature to construct default value through
+ // operator[]. default bool is false, which is what's needed
+ if (m_scopeHasDefaultPropertyAssignment[scopeOfDefaultProperty] && !defaultProp.isList()) {
+ // already has some object assigned to a default property and
+ // this default property is not a list property
+ m_errors.append(
+ { QStringLiteral("Cannot assign multiple objects to a default non-list property"),
+ QtWarningMsg, scope->sourceLocation() });
+ m_visitFailed = true;
+ }
+ m_scopeHasDefaultPropertyAssignment[scopeOfDefaultProperty] = true;
+
+ auto propType = defaultProp.type().data();
+ if (!propType) // should be an error somewhere else
+ return;
+
+ // scope's type hierarchy has to have property type
+ for (const QQmlJSScope *type = scope.data(); type; type = type->baseType().data()) {
+ if (type == propType)
+ return;
+ }
+
+ m_errors.append({ QStringLiteral("Cannot assign to default property of incompatible type"),
+ QtWarningMsg, scope->sourceLocation() });
+ m_visitFailed = true;
+}
+
void FindWarningVisitor::throwRecursionDepthError()
{
QQmlJSImportVisitor::throwRecursionDepthError();
@@ -524,6 +578,9 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiObjectDefinition *uiod)
m_currentScope->addOwnMethod(method);
}
}
+
+ checkDefaultProperty(m_currentScope);
+
return true;
}
diff --git a/tools/qmllint/findwarnings.h b/tools/qmllint/findwarnings.h
index 30ee47705e..21ebb0825d 100644
--- a/tools/qmllint/findwarnings.h
+++ b/tools/qmllint/findwarnings.h
@@ -90,9 +90,14 @@ private:
QVarLengthArray<OutstandingConnection, 3> m_outstandingConnections; // Connections whose target we have not encountered
+ // records of whether a default property has object assigned to it. for
+ // correctness, the scope that defines the default property acts as a key
+ QHash<const QQmlJSScope *, bool> m_scopeHasDefaultPropertyAssignment;
+
void checkInheritanceCycle(QQmlJSScope::ConstPtr scope);
void checkGroupedAndAttachedScopes(QQmlJSScope::ConstPtr scope);
void flushPendingSignalParameters();
+ void checkDefaultProperty(const QQmlJSScope::ConstPtr &scope);
void throwRecursionDepthError() override;