diff options
| author | Sami Shalayel <[email protected]> | 2025-03-25 15:57:08 +0100 |
|---|---|---|
| committer | Sami Shalayel <[email protected]> | 2025-04-04 14:51:15 +0200 |
| commit | 934831b0625d9fcaaf5649a083afdd1c2026ebc9 (patch) | |
| tree | 70d3e75aea01161f03f71f964d32b9f74deed369 | |
| parent | ec7b917ff377cc699f4c422908f048f18545680e (diff) | |
qmllint: add helpers to create small PropertyPasses
This commit should make implementing small PropertyPasses easier:
instead of having to create a new class and registering the PropertyPass
into the PassManager, create a Builder that creates a PropertyPass from
lambdas and registers it into the pass manager.
This avoids having to create a new class inheriting from PropertyPass
for each check that will be added with QTBUG-129307.
Also add a method to PassManagerPrivate to be able to register
propertypasses on builtin objects. This is needed to warn about usages
of 'eval()' in a later commit.
Task-number: QTBUG-129307
Change-Id: If3ea8d092acae4733aacd62ca7769011f0a7633c
Reviewed-by: Fabian Kosmale <[email protected]>
| -rw-r--r-- | src/qmlcompiler/qqmlsa.cpp | 21 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmlsa_p.h | 121 |
2 files changed, 142 insertions, 0 deletions
diff --git a/src/qmlcompiler/qqmlsa.cpp b/src/qmlcompiler/qqmlsa.cpp index b4f973af2c..bf4893e06b 100644 --- a/src/qmlcompiler/qqmlsa.cpp +++ b/src/qmlcompiler/qqmlsa.cpp @@ -1505,6 +1505,27 @@ bool PassManagerPrivate::registerPropertyPass(std::shared_ptr<PropertyPass> pass return true; } +bool PassManagerPrivate::registerPropertyPassOnBuiltinType(std::shared_ptr<PropertyPass> pass, + QAnyStringView builtinTypeName, + QAnyStringView propertyName, + bool allowInheritance) +{ + auto typeImporter = m_visitor->importer(); + const auto scope = typeImporter->builtinInternalNames().type(builtinTypeName.toString()).scope; + const auto element = QQmlJSScope::createQQmlSAElement(scope); + + if (element.isNull()) + return false; + + const QString name = lookupName(element, Register); + + const QQmlSA::PropertyPassInvocation passInfo{ propertyName.toString(), std::move(pass), + allowInheritance }; + m_propertyPasses.insert({ name, passInfo }); + + return true; +} + void PassManagerPrivate::addBindingSourceLocations(const Element &element, const Element &scope, const QString prefix, bool isAttached) { diff --git a/src/qmlcompiler/qqmlsa_p.h b/src/qmlcompiler/qqmlsa_p.h index 95b86e0d64..dde1268943 100644 --- a/src/qmlcompiler/qqmlsa_p.h +++ b/src/qmlcompiler/qqmlsa_p.h @@ -201,6 +201,11 @@ public: QAnyStringView typeName, QAnyStringView propertyName = QAnyStringView(), bool allowInheritance = true); + bool registerPropertyPassOnBuiltinType(std::shared_ptr<PropertyPass> pass, + QAnyStringView typeName, + QAnyStringView propertyName = QAnyStringView(), + bool allowInheritance = true); + void analyze(const Element &root); bool hasImportedModule(QAnyStringView name) const; @@ -272,6 +277,122 @@ Q_QMLCOMPILER_EXPORT void emitWarningWithOptionalFix(GenericPass &pass, QAnyStri const QQmlSA::SourceLocation &srcLocation, const std::optional<QQmlJSFixSuggestion> &fix); +struct GenericPropertyPass : public PropertyPass +{ + using PropertyPass::PropertyPass; + + static void onBindingDefault(PropertyPass *, const Element &, const QString &, const Binding &, + const Element &, const Element &) + { + } + static void onReadDefault(PropertyPass *, const Element &, const QString &, const Element &, + SourceLocation) + { + } + static void onCallDefault(PropertyPass *, const Element &, const QString &, const Element &, + SourceLocation) + { + } + static void onWriteDefault(PropertyPass *, const Element &, const QString &, const Element &, + const Element &, SourceLocation) + { + } + + using OnBinding = decltype(&onBindingDefault); + using OnRead = decltype(&onReadDefault); + using OnCall = decltype(&onCallDefault); + using OnWrite = decltype(&onWriteDefault); + + void onBinding(const Element &element, const QString &propertyName, const Binding &binding, + const Element &bindingScope, const Element &value) override + { + m_onBinding(this, element, propertyName, binding, bindingScope, value); + } + void onRead(const Element &element, const QString &propertyName, const Element &readScope, + SourceLocation location) override + { + m_onRead(this, element, propertyName, readScope, location); + } + void onCall(const Element &element, const QString &propertyName, const Element &readScope, + SourceLocation location) override + { + m_onCall(this, element, propertyName, readScope, location); + } + void onWrite(const Element &element, const QString &propertyName, const Element &value, + const Element &writeScope, SourceLocation location) override + { + m_onWrite(this, element, propertyName, value, writeScope, location); + } + + OnBinding m_onBinding = &onBindingDefault; + OnRead m_onRead = &onReadDefault; + OnCall m_onCall = &onCallDefault; + OnWrite m_onWrite = &onWriteDefault; +}; + +class PropertyPassBuilder +{ +public: + PropertyPassBuilder(PassManager *passManager) + : m_pass(std::make_unique<GenericPropertyPass>(passManager)), m_passManager(passManager) + { + Q_ASSERT(m_passManager); + } + + PropertyPassBuilder() = delete; + Q_DISABLE_COPY_MOVE(PropertyPassBuilder) + ~PropertyPassBuilder() + { + Q_ASSERT_X(!m_pass, "GenericPropertyPassBuilder", "Built PropertyPass was not registered!"); + } + + PropertyPassBuilder &withOnBinding(GenericPropertyPass::OnBinding onBinding) + { + Q_ASSERT_X(m_pass, "GenericPropertyPassBuilder", + "PropertyPasses can't be modified after registration"); + m_pass->m_onBinding = onBinding; + return *this; + } + PropertyPassBuilder &withOnRead(GenericPropertyPass::OnRead onRead) + { + Q_ASSERT_X(m_pass, "GenericPropertyPassBuilder", + "PropertyPasses can't be modified after registration"); + m_pass->m_onRead = onRead; + return *this; + } + PropertyPassBuilder &withOnCall(GenericPropertyPass::OnCall onCall) + { + Q_ASSERT_X(m_pass, "GenericPropertyPassBuilder", + "PropertyPasses can't be modified after registration"); + m_pass->m_onCall = onCall; + return *this; + } + PropertyPassBuilder &withOnWrite(GenericPropertyPass::OnWrite onWrite) + { + Q_ASSERT_X(m_pass, "GenericPropertyPassBuilder", + "PropertyPasses can't be modified after registration"); + m_pass->m_onWrite = onWrite; + return *this; + } + void registerOn(QAnyStringView module, QAnyStringView type, QAnyStringView property) + { + Q_ASSERT_X(m_pass, "GenericPropertyPassBuilder", + "Current PropertyPass was already registered"); + m_passManager->registerPropertyPass(std::move(m_pass), module, type, property); + } + void registerOnBuiltin(QAnyStringView type, QAnyStringView property) + { + Q_ASSERT_X(m_pass, "GenericPropertyPassBuilder", + "Current PropertyPass was already registered"); + PassManagerPrivate::get(m_passManager) + ->registerPropertyPassOnBuiltinType(std::move(m_pass), type, property); + } + +private: + std::unique_ptr<GenericPropertyPass> m_pass; + PassManager *m_passManager; +}; + } // namespace QQmlSA QT_END_NAMESPACE |
