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>
This commit is contained in:
parent
80f0bf64e4
commit
15efc5c323
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
QStringList typeNames { lookupName(element) };
|
||||
|
||||
for (auto it = pass.first; it != pass.second; it++)
|
||||
passes.push_back(it->second.get());
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue