diff options
author | Andrei Golubev <andrei.golubev@qt.io> | 2021-03-02 16:32:56 +0100 |
---|---|---|
committer | Andrei Golubev <andrei.golubev@qt.io> | 2021-03-09 10:13:34 +0100 |
commit | 602982993cb73584d9bfae91f0073384bc1e6850 (patch) | |
tree | 34f5b8fb896952367ad5308c9b7efefbacc42c35 /tools/qmllint | |
parent | 220e6a5a76d2bc91df4e3c248e5272c3d2af9967 (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.cpp | 57 | ||||
-rw-r--r-- | tools/qmllint/findwarnings.h | 5 |
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; |