aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSami Shalayel <[email protected]>2025-03-25 15:57:08 +0100
committerSami Shalayel <[email protected]>2025-04-04 14:51:15 +0200
commit934831b0625d9fcaaf5649a083afdd1c2026ebc9 (patch)
tree70d3e75aea01161f03f71f964d32b9f74deed369
parentec7b917ff377cc699f4c422908f048f18545680e (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.cpp21
-rw-r--r--src/qmlcompiler/qqmlsa_p.h121
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