diff options
author | Maximilian Goldstein <max.goldstein@qt.io> | 2022-05-20 11:53:40 +0200 |
---|---|---|
committer | Maximilian Goldstein <max.goldstein@qt.io> | 2022-06-02 10:07:40 +0200 |
commit | 15efc5c32369f5852c7f83696fe0d21f6d338972 (patch) | |
tree | 7c2eaa7631f79f0a4f9b78d28b9204e3198d67b6 /src | |
parent | 80f0bf64e49f07a73712998ddc8a0eebd1b660b6 (diff) |
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 <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-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; |