diff options
-rw-r--r-- | src/qmlcompiler/qqmljsscope.cpp | 65 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsscope_p.h | 7 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljstypedescriptionreader.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/tst_qmllint.cpp | 2 | ||||
-rw-r--r-- | tools/qmllint/checkidentifiers.cpp | 13 |
5 files changed, 83 insertions, 6 deletions
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp index 202e292838..85c84420a3 100644 --- a/src/qmlcompiler/qqmljsscope.cpp +++ b/src/qmlcompiler/qqmljsscope.cpp @@ -78,18 +78,38 @@ bool QQmlJSScope::isIdInCurrentScope(const QString &id) const bool QQmlJSScope::hasMethod(const QString &name) const { + const QQmlJSScope *nonCompositeBase = isComposite() ? this : nullptr; for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) { if (scope->m_methods.contains(name)) return true; + if (!nonCompositeBase && !scope->isComposite()) + nonCompositeBase = scope; } + + if (nonCompositeBase && nonCompositeBase != this) { + if (QQmlJSScope::ConstPtr extension = nonCompositeBase->extensionType()) + return extension->hasMethod(name); + } + return false; } QList<QQmlJSMetaMethod> QQmlJSScope::methods(const QString &name) const { QList<QQmlJSMetaMethod> results; - for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) + + const QQmlJSScope *nonCompositeBase = isComposite() ? this : nullptr; + for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) { results.append(scope->ownMethods(name)); + if (!nonCompositeBase && !scope->isComposite()) + nonCompositeBase = scope; + } + + if (nonCompositeBase && nonCompositeBase != this) { + if (QQmlJSScope::ConstPtr extension = nonCompositeBase->extensionType()) + results.append(extension->methods(name)); + } + return results; } @@ -157,6 +177,9 @@ void QQmlJSScope::resolveTypes(const QHash<QString, QQmlJSScope::ConstPtr> &cont if (!m_valueType && !m_valueTypeName.isEmpty()) m_valueType = findType(m_valueTypeName); + if (!m_extensionType && !m_extensionTypeName.isEmpty()) + m_extensionType = findType(m_extensionTypeName); + for (auto it = m_properties.begin(), end = m_properties.end(); it != end; ++it) { const QString typeName = it->typeName(); if (!it->type() && !typeName.isEmpty()) @@ -192,12 +215,30 @@ void QQmlJSScope::resolveGroupedScopes() continue; const QString propertyName = childScope->internalName(); - for (const QQmlJSScope *type = this; type; type = type->baseType().data()) { + auto findProperty = [&](const QQmlJSScope *type) { 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(); + return true; + } + return false; + }; + + const QQmlJSScope *nonCompositeBase = isComposite() ? this : nullptr; + for (const QQmlJSScope *type = this; type; type = type->baseType().data()) { + if (findProperty(type)) break; + + if (!nonCompositeBase && !type->isComposite()) + nonCompositeBase = type; + } + + if (!childScope->m_baseType && nonCompositeBase && nonCompositeBase != this) { + for (const QQmlJSScope *type = nonCompositeBase->extensionType().data(); type; + type = type->baseType().data()) { + if (findProperty(type)) + break; } } @@ -221,20 +262,40 @@ void QQmlJSScope::addExport(const QString &name, const QString &package, bool QQmlJSScope::hasProperty(const QString &name) const { + const QQmlJSScope *nonCompositeBase = isComposite() ? this : nullptr; for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) { if (scope->m_properties.contains(name)) return true; + + if (!nonCompositeBase && !scope->isComposite()) + nonCompositeBase = scope; + } + + if (nonCompositeBase && nonCompositeBase != this) { + if (QQmlJSScope::ConstPtr extension = nonCompositeBase->extensionType()) + return extension->hasProperty(name); } + return false; } QQmlJSMetaProperty QQmlJSScope::property(const QString &name) const { + const QQmlJSScope *nonCompositeBase = isComposite() ? this : nullptr; for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) { const auto it = scope->m_properties.find(name); if (it != scope->m_properties.end()) return *it; + + if (!nonCompositeBase && !scope->isComposite()) + nonCompositeBase = scope; } + + if (nonCompositeBase && nonCompositeBase != this) { + if (QQmlJSScope::ConstPtr extension = nonCompositeBase->extensionType()) + return extension->property(name); + } + return {}; } diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h index f0833a18a0..1902c46263 100644 --- a/src/qmlcompiler/qqmljsscope_p.h +++ b/src/qmlcompiler/qqmljsscope_p.h @@ -218,6 +218,10 @@ public: void setAttachedTypeName(const QString &name) { m_attachedTypeName = name; } QQmlJSScope::ConstPtr attachedType() const { return m_attachedType; } + QString extensionTypeName() const { return m_extensionTypeName; } + void setExtensionTypeName(const QString &name) { m_extensionTypeName = name; } + QQmlJSScope::ConstPtr extensionType() const { return m_extensionType; } + QString valueTypeName() const { return m_valueTypeName; } void setValueTypeName(const QString &name) { m_valueTypeName = name; } QQmlJSScope::ConstPtr valueType() const { return m_valueType; } @@ -304,6 +308,9 @@ private: QString m_valueTypeName; QQmlJSScope::WeakConstPtr m_valueType; + QString m_extensionTypeName; + QQmlJSScope::WeakConstPtr m_extensionType; + Flags m_flags; AccessSemantics m_semantics = AccessSemantics::Reference; diff --git a/src/qmlcompiler/qqmljstypedescriptionreader.cpp b/src/qmlcompiler/qqmljstypedescriptionreader.cpp index b24722b37c..b1a1d18bfe 100644 --- a/src/qmlcompiler/qqmljstypedescriptionreader.cpp +++ b/src/qmlcompiler/qqmljstypedescriptionreader.cpp @@ -249,7 +249,7 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast) tr("Unknown access semantics \"%1\".").arg(semantics)); } } else if (name == QLatin1String("extension")) { - // not implemented + scope->setExtensionTypeName(readStringBinding(script)); } else { addWarning(script->firstSourceLocation(), tr("Expected only name, prototype, defaultProperty, attachedType, " diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index 0a2f8ed6b1..3f674fb5cc 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -317,7 +317,6 @@ void TestQmllint::cleanQmlCode() { QFETCH(QString, filename); const QString warnings = runQmllint(filename, true); - QEXPECT_FAIL("unknownBuiltinFont", "Broken extended support", Continue); QVERIFY2(warnings.isEmpty(), qPrintable(warnings)); } @@ -362,7 +361,6 @@ QString TestQmllint::runQmllint(const QString &fileToLint, bool shouldSucceed, c return runQmllint(fileToLint, [&](QProcess &process) { QVERIFY(process.waitForFinished()); QCOMPARE(process.exitStatus(), QProcess::NormalExit); - QEXPECT_FAIL("unknownBuiltinFont", "Broken extended support", Continue); if (shouldSucceed) QCOMPARE(process.exitCode(), 0); else diff --git a/tools/qmllint/checkidentifiers.cpp b/tools/qmllint/checkidentifiers.cpp index b718f0f691..90456f97aa 100644 --- a/tools/qmllint/checkidentifiers.cpp +++ b/tools/qmllint/checkidentifiers.cpp @@ -86,6 +86,12 @@ static bool walkViaParentAndAttachedScopes(QQmlJSScope::ConstPtr rootType, return false; std::stack<QQmlJSScope::ConstPtr> stack; stack.push(rootType); + + if (!rootType->isComposite()) { + if (auto extension = rootType->extensionType()) + stack.push(extension); + } + while (!stack.empty()) { const auto type = stack.top(); stack.pop(); @@ -93,8 +99,13 @@ static bool walkViaParentAndAttachedScopes(QQmlJSScope::ConstPtr rootType, if (visit(type)) return true; - if (auto superType = type->baseType()) + if (auto superType = type->baseType()) { stack.push(superType); + if (type->isComposite() && !superType->isComposite()) { + if (auto extension = superType->extensionType()) + stack.push(extension); + } + } if (auto attachedType = type->attachedType()) stack.push(attachedType); |