diff options
-rw-r--r-- | src/qmlcompiler/qqmljstypepropagator.cpp | 12 | ||||
-rw-r--r-- | src/qmlcompiler/qqmlsa.cpp | 52 | ||||
-rw-r--r-- | src/qmlcompiler/qqmlsa_p.h | 17 |
3 files changed, 55 insertions, 26 deletions
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 <memory> @@ -101,7 +102,7 @@ static QString lookupName(const QQmlSA::Element &element, LookupMode mode = Look bool PassManager::registerPropertyPass(std::shared_ptr<PropertyPass> 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<PropertyPass> 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<PropertyPass *> PassManager::findPropertyUsePasses(const QQmlSA::Element &element, - const QString &propertyName) +QSet<PropertyPass *> PassManager::findPropertyUsePasses(const QQmlSA::Element &element, + const QString &propertyName) { - const QString typeName = lookupName(element); - std::vector<PropertyPass *> 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<PropertyPass *> 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 <qtqmlcompilerexports.h> #include <private/qqmljsscope_p.h> +#include <QtCore/qset.h> #include <map> #include <unordered_map> @@ -126,7 +127,8 @@ public: void registerElementPass(std::unique_ptr<ElementPass> pass); bool registerPropertyPass(std::shared_ptr<PropertyPass> 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<PropertyPass *> findPropertyUsePasses(const QQmlSA::Element &element, - const QString &propertyName); + QSet<PropertyPass *> 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<PropertyPass> 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<std::unique_ptr<ElementPass>> m_elementPasses; - std::multimap<std::pair<QString, QString>, std::shared_ptr<PropertyPass>> m_propertyPasses; + std::multimap<QString, PropertyPassInfo> m_propertyPasses; std::unordered_map<quint32, BindingInfo> m_bindingsByLocation; QQmlJSImportVisitor *m_visitor; QQmlJSTypeResolver *m_typeResolver; |