From 15efc5c32369f5852c7f83696fe0d21f6d338972 Mon Sep 17 00:00:00 2001 From: Maximilian Goldstein Date: Fri, 20 May 2022 11:53:40 +0200 Subject: qqmlsa: Make property pass check base and extension types as well In many cases we need to also check base an extension types since we don't always have direct inheritance (i.e. very common with QtQuick.Controls) Change-Id: I66307b7d0081d49611a9e61847e4363d5819bf82 Reviewed-by: Qt CI Bot Reviewed-by: Fabian Kosmale --- src/qmlcompiler/qqmljstypepropagator.cpp | 12 ++++---- src/qmlcompiler/qqmlsa.cpp | 52 ++++++++++++++++++++++---------- src/qmlcompiler/qqmlsa_p.h | 17 ++++++++--- 3 files changed, 55 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp index 27e120a832..44822371b5 100644 --- a/src/qmlcompiler/qqmljstypepropagator.cpp +++ b/src/qmlcompiler/qqmljstypepropagator.cpp @@ -97,6 +97,12 @@ QQmlJSCompilePass::InstructionAnnotations QQmlJSTypePropagator::run( void QQmlJSTypePropagator::generate_Ret() { + if (m_passManager != nullptr && m_function->isProperty) { + m_passManager->analyzeBinding(m_function->qmlScope, + m_typeResolver->containedType(m_state.accumulatorIn()), + getCurrentBindingSourceLocation()); + } + if (m_function->isSignalHandler) { // Signal handlers cannot return anything. } else if (!m_returnType.isValid() && m_state.accumulatorIn().isValid() @@ -125,12 +131,6 @@ void QQmlJSTypePropagator::generate_Ret() addReadAccumulator(m_returnType); } - if (m_passManager != nullptr && m_function->isProperty) { - m_passManager->analyzeBinding(m_function->qmlScope, - m_typeResolver->containedType(m_state.accumulatorIn()), - getCurrentBindingSourceLocation()); - } - m_state.setHasSideEffects(true); m_state.skipInstructionsUntilNextJumpTarget = true; } diff --git a/src/qmlcompiler/qqmlsa.cpp b/src/qmlcompiler/qqmlsa.cpp index 184ac79ee0..31fedc9ff4 100644 --- a/src/qmlcompiler/qqmlsa.cpp +++ b/src/qmlcompiler/qqmlsa.cpp @@ -32,6 +32,7 @@ #include "qqmljslogger_p.h" #include "qqmljstyperesolver_p.h" #include "qqmljsimportvisitor_p.h" +#include "qqmljsutils_p.h" #include @@ -101,7 +102,7 @@ static QString lookupName(const QQmlSA::Element &element, LookupMode mode = Look bool PassManager::registerPropertyPass(std::shared_ptr pass, QAnyStringView moduleName, QAnyStringView typeName, - QAnyStringView propertyName) + QAnyStringView propertyName, bool allowInheritance) { QString name; if (!moduleName.isEmpty() && !typeName.isEmpty()) { @@ -114,7 +115,11 @@ bool PassManager::registerPropertyPass(std::shared_ptr pass, name = lookupName(element, Register); } - m_propertyPasses.insert({ std::make_pair<>(name, propertyName.toString()), std::move(pass) }); + const PassManager::PropertyPassInfo passInfo { + propertyName.isEmpty() ? QStringList {} : QStringList { propertyName.toString() }, + std::move(pass), allowInheritance + }; + m_propertyPasses.insert({ name, passInfo }); return true; } @@ -195,7 +200,7 @@ void PassManager::analyzeBinding(const Element &element, const QQmlSA::Element & for (PropertyPass *pass : findPropertyUsePasses(element, propertyName)) pass->onBinding(element, propertyName, binding, bindingScope, value); - if (!info->second.isAttached) + if (!info->second.isAttached || bindingScope->baseType().isNull()) return; for (PropertyPass *pass : findPropertyUsePasses(bindingScope->baseType(), propertyName)) @@ -207,20 +212,35 @@ bool PassManager::hasImportedModule(QAnyStringView module) const return m_visitor->imports().contains(u"$module$." + module.toString()); } -std::vector PassManager::findPropertyUsePasses(const QQmlSA::Element &element, - const QString &propertyName) +QSet PassManager::findPropertyUsePasses(const QQmlSA::Element &element, + const QString &propertyName) { - const QString typeName = lookupName(element); - std::vector passes; - for (const auto &key : - { std::make_pair<>(typeName, propertyName), std::make_pair<>(QString(), propertyName), - std::make_pair<>(typeName, QString()) }) { - auto pass = m_propertyPasses.equal_range(key); - if (pass.first == pass.second) - continue; - - for (auto it = pass.first; it != pass.second; it++) - passes.push_back(it->second.get()); + QStringList typeNames { lookupName(element) }; + + QQmlJSUtils::searchBaseAndExtensionTypes( + element, [&](const QQmlJSScope::ConstPtr &scope, QQmlJSScope::ExtensionKind mode) { + Q_UNUSED(mode); + typeNames.append(lookupName(scope)); + return false; + }); + + QSet passes; + + for (const QString &typeName : typeNames) { + for (auto &pass : + { m_propertyPasses.equal_range(u""_s), m_propertyPasses.equal_range(typeName) }) { + if (pass.first == pass.second) + continue; + + for (auto it = pass.first; it != pass.second; it++) { + if (typeName != typeNames.constFirst() && !it->second.allowInheritance) + continue; + if (it->second.properties.isEmpty() + || it->second.properties.contains(propertyName)) { + passes.insert(it->second.pass.get()); + } + } + } } return passes; } diff --git a/src/qmlcompiler/qqmlsa_p.h b/src/qmlcompiler/qqmlsa_p.h index 5f2ebcd91a..7e1eeb1c27 100644 --- a/src/qmlcompiler/qqmlsa_p.h +++ b/src/qmlcompiler/qqmlsa_p.h @@ -42,6 +42,7 @@ #include #include +#include #include #include @@ -126,7 +127,8 @@ public: void registerElementPass(std::unique_ptr pass); bool registerPropertyPass(std::shared_ptr pass, QAnyStringView moduleName, QAnyStringView typeName, - QAnyStringView propertyName = QAnyStringView()); + QAnyStringView propertyName = QAnyStringView(), + bool allowInheritance = true); void analyze(const Element &root); bool hasImportedModule(QAnyStringView name) const; @@ -134,8 +136,8 @@ public: private: friend struct ::QQmlJSTypePropagator; - std::vector findPropertyUsePasses(const QQmlSA::Element &element, - const QString &propertyName); + QSet findPropertyUsePasses(const QQmlSA::Element &element, + const QString &propertyName); void analyzeWrite(const QQmlSA::Element &element, QString propertyName, const QQmlSA::Element &value, const QQmlSA::Element &writeScope, @@ -153,12 +155,19 @@ private: bool isAttached; }; + struct PropertyPassInfo + { + QStringList properties; + std::shared_ptr pass; + bool allowInheritance = true; + }; + void addBindingSourceLocations(const QQmlSA::Element &element, const QQmlSA::Element &scope = QQmlSA::Element(), const QString prefix = QString(), bool isAttached = false); std::vector> m_elementPasses; - std::multimap, std::shared_ptr> m_propertyPasses; + std::multimap m_propertyPasses; std::unordered_map m_bindingsByLocation; QQmlJSImportVisitor *m_visitor; QQmlJSTypeResolver *m_typeResolver; -- cgit v1.2.3