diff options
Diffstat (limited to 'src/qmlcompiler/qqmlsa.h')
-rw-r--r-- | src/qmlcompiler/qqmlsa.h | 435 |
1 files changed, 435 insertions, 0 deletions
diff --git a/src/qmlcompiler/qqmlsa.h b/src/qmlcompiler/qqmlsa.h new file mode 100644 index 0000000000..e63f9ea5ab --- /dev/null +++ b/src/qmlcompiler/qqmlsa.h @@ -0,0 +1,435 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef QQMLSA_H +#define QQMLSA_H + +// +// W A R N I N G +// ------------- +// +// This file is part of the qmllint plugin API, with limited compatibility guarantees. +// Usage of this API may make your code source and binary incompatible with +// future versions of Qt. +// + +#include <QtQmlCompiler/qqmlsaconstants.h> +#include <QtQmlCompiler/qqmljsloggingutils.h> + +#include <QtQmlCompiler/qtqmlcompilerexports.h> + +#include <QtCore/qhash.h> +#include <QtCore/qsharedpointer.h> +#include <QtCore/qplugin.h> +#include <QtQmlCompiler/qqmlsasourcelocation.h> + +#include <unordered_map> + +QT_BEGIN_NAMESPACE + +namespace QQmlSA { + +class BindingPrivate; +class BindingsPrivate; +class Element; +class ElementPass; +class FixSuggestion; +class FixSuggestionPrivate; +class GenericPassPrivate; +class MethodPrivate; +class MethodsPrivate; +class PassManager; +class PassManagerPrivate; +class PropertyPass; +class PropertyPrivate; +enum class AccessSemantics; +struct BindingInfo; +struct PropertyPassInfo; + +enum class MethodType { Signal, Slot, Method, StaticMethod }; + +class Q_QMLCOMPILER_EXPORT Binding +{ + Q_DECLARE_PRIVATE(Binding) + +public: + class Q_QMLCOMPILER_EXPORT Bindings + { + Q_DECLARE_PRIVATE(Bindings) + + public: + Bindings(); + Bindings(const Bindings &); + ~Bindings(); + + QMultiHash<QString, Binding>::const_iterator begin() const { return constBegin(); } + QMultiHash<QString, Binding>::const_iterator end() const { return constEnd(); } + QMultiHash<QString, Binding>::const_iterator constBegin() const; + QMultiHash<QString, Binding>::const_iterator constEnd() const; + + private: + std::unique_ptr<BindingsPrivate> d_ptr; + }; + + Binding(); + Binding(const Binding &); + Binding(Binding &&) noexcept; + Binding &operator=(const Binding &); + Binding &operator=(Binding &&) noexcept; + ~Binding(); + + Element groupType() const; + BindingType bindingType() const; + QString stringValue() const; + QString propertyName() const; + Element attachingType() const; + QQmlSA::SourceLocation sourceLocation() const; + double numberValue() const; + ScriptBindingKind scriptKind() const; + bool hasObject() const; + Element objectType() const; + bool hasUndefinedScriptValue() const; + + friend bool operator==(const Binding &lhs, const Binding &rhs) + { + return operatorEqualsImpl(lhs, rhs); + } + friend bool operator!=(const Binding &lhs, const Binding &rhs) + { + return !operatorEqualsImpl(lhs, rhs); + } + + static bool isLiteralBinding(BindingType); + +private: + static bool operatorEqualsImpl(const Binding &, const Binding &); + + std::unique_ptr<BindingPrivate> d_ptr; +}; + +class Q_QMLCOMPILER_EXPORT Method +{ + Q_DECLARE_PRIVATE(Method) + +public: + class Q_QMLCOMPILER_EXPORT Methods + { + Q_DECLARE_PRIVATE(Methods) + + public: + Methods(); + Methods(const Methods &); + ~Methods(); + + QMultiHash<QString, Method>::const_iterator begin() const { return constBegin(); } + QMultiHash<QString, Method>::const_iterator end() const { return constEnd(); } + QMultiHash<QString, Method>::const_iterator constBegin() const; + QMultiHash<QString, Method>::const_iterator constEnd() const; + + private: + std::unique_ptr<MethodsPrivate> d_ptr; + }; + + Method(); + Method(const Method &); + Method(Method &&) noexcept; + Method &operator=(const Method &); + Method &operator=(Method &&) noexcept; + ~Method(); + + QString methodName() const; + QQmlSA::SourceLocation sourceLocation() const; + MethodType methodType() const; + + friend bool operator==(const Method &lhs, const Method &rhs) + { + return operatorEqualsImpl(lhs, rhs); + } + friend bool operator!=(const Method &lhs, const Method &rhs) + { + return !operatorEqualsImpl(lhs, rhs); + } + +private: + static bool operatorEqualsImpl(const Method &, const Method &); + + std::unique_ptr<MethodPrivate> d_ptr; +}; + +class Q_QMLCOMPILER_EXPORT Property +{ + Q_DECLARE_PRIVATE(Property) + +public: + Property(); + Property(const Property &); + Property(Property &&) noexcept; + Property &operator=(const Property &); + Property &operator=(Property &&) noexcept; + ~Property(); + + QString typeName() const; + bool isValid() const; + bool isReadonly() const; + QQmlSA::Element type() const; + + friend bool operator==(const Property &lhs, const Property &rhs) + { + return operatorEqualsImpl(lhs, rhs); + } + + friend bool operator!=(const Property &lhs, const Property &rhs) + { + return !operatorEqualsImpl(lhs, rhs); + } + +private: + static bool operatorEqualsImpl(const Property &, const Property &); + + std::unique_ptr<PropertyPrivate> d_ptr; +}; + +class Q_QMLCOMPILER_EXPORT Element +{ + friend class QT_PREPEND_NAMESPACE(QQmlJSScope); + +public: + Element(); + Element(const Element &); + Element(Element &&other) noexcept + { + memcpy(m_data, other.m_data, sizeofElement); + memset(other.m_data, 0, sizeofElement); + } + Element &operator=(const Element &); + QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(Element) + ~Element(); + + ScopeType scopeType() const; + Element baseType() const; + QString baseTypeName() const; + Element parentScope() const; + bool inherits(const Element &) const; + + bool isNull() const; + QString internalId() const; + AccessSemantics accessSemantics() const; + bool isComposite() const; + + bool hasProperty(const QString &propertyName) const; + bool hasOwnProperty(const QString &propertyName) const; + Property property(const QString &propertyName) const; + bool isPropertyRequired(const QString &propertyName) const; + QString defaultPropertyName() const; + + bool hasMethod(const QString &methodName) const; + Method::Methods ownMethods() const; + + QQmlSA::SourceLocation sourceLocation() const; + QString filePath() const; + + bool hasPropertyBindings(const QString &name) const; + bool hasOwnPropertyBindings(const QString &propertyName) const; + + Binding::Bindings ownPropertyBindings() const; + Binding::Bindings ownPropertyBindings(const QString &propertyName) const; + QList<Binding> propertyBindings(const QString &propertyName) const; + + explicit operator bool() const; + bool operator!() const; + + QString name() const; + + friend inline bool operator==(const QQmlSA::Element &lhs, const QQmlSA::Element &rhs) + { + return operatorEqualsImpl(lhs, rhs); + } + friend inline bool operator!=(const Element &lhs, const Element &rhs) { return !(lhs == rhs); } + + friend inline qsizetype qHash(const Element &key, qsizetype seed = 0) noexcept + { + return qHashImpl(key, seed); + } + +private: + static bool operatorEqualsImpl(const Element &, const Element &); + static qsizetype qHashImpl(const Element &key, qsizetype seed) noexcept; + + static constexpr qsizetype sizeofElement = 2 * sizeof(QSharedPointer<int>); + alignas(QSharedPointer<int>) char m_data[sizeofElement]; + + void swap(Element &other) noexcept + { + char t[sizeofElement]; + memcpy(t, m_data, sizeofElement); + memcpy(m_data, other.m_data, sizeofElement); + memcpy(other.m_data, t, sizeofElement); + } + friend void swap(Element &lhs, Element &rhs) noexcept { lhs.swap(rhs); } +}; + +class Q_QMLCOMPILER_EXPORT GenericPass +{ + Q_DECLARE_PRIVATE(GenericPass) + Q_DISABLE_COPY_MOVE(GenericPass) + +public: + GenericPass(PassManager *manager); + virtual ~GenericPass(); + + void emitWarning(QAnyStringView diagnostic, LoggerWarningId id); + void emitWarning(QAnyStringView diagnostic, LoggerWarningId id, + QQmlSA::SourceLocation srcLocation); + void emitWarning(QAnyStringView diagnostic, LoggerWarningId id, + QQmlSA::SourceLocation srcLocation, const QQmlSA::FixSuggestion &fix); + + Element resolveTypeInFileScope(QAnyStringView typeName); + Element resolveAttachedInFileScope(QAnyStringView typeName); + Element resolveType(QAnyStringView moduleName, QAnyStringView typeName); // #### TODO: revisions + Element resolveBuiltinType(QAnyStringView typeName) const; + Element resolveAttached(QAnyStringView moduleName, QAnyStringView typeName); + Element resolveLiteralType(const Binding &binding); + + Element resolveIdToElement(QAnyStringView id, const Element &context); + QString resolveElementToId(const Element &element, const Element &context); + + QString sourceCode(QQmlSA::SourceLocation location); + +private: + std::unique_ptr<GenericPassPrivate> d_ptr; +}; + +class Q_QMLCOMPILER_EXPORT PassManager +{ + Q_DISABLE_COPY_MOVE(PassManager) + Q_DECLARE_PRIVATE(PassManager) + +public: + void registerElementPass(std::unique_ptr<ElementPass> pass); + bool registerPropertyPass(std::shared_ptr<PropertyPass> pass, QAnyStringView moduleName, + QAnyStringView typeName, + QAnyStringView propertyName = QAnyStringView(), + bool allowInheritance = true); + void analyze(const Element &root); + + bool hasImportedModule(QAnyStringView name) const; + + bool isCategoryEnabled(LoggerWarningId category) const; + + std::vector<std::shared_ptr<ElementPass>> elementPasses() const; + std::multimap<QString, PropertyPassInfo> propertyPasses() const; + std::unordered_map<quint32, BindingInfo> bindingsByLocation() const; + +private: + PassManager(); + ~PassManager(); + + std::unique_ptr<PassManagerPrivate> d_ptr; +}; + +class Q_QMLCOMPILER_EXPORT LintPlugin +{ +public: + LintPlugin() = default; + virtual ~LintPlugin() = default; + + Q_DISABLE_COPY_MOVE(LintPlugin) + + virtual void registerPasses(PassManager *manager, const Element &rootElement) = 0; +}; + +class Q_QMLCOMPILER_EXPORT PropertyPass : public GenericPass +{ +public: + PropertyPass(PassManager *manager); + + virtual void onBinding(const QQmlSA::Element &element, const QString &propertyName, + const QQmlSA::Binding &binding, const QQmlSA::Element &bindingScope, + const QQmlSA::Element &value); + virtual void onRead(const QQmlSA::Element &element, const QString &propertyName, + const QQmlSA::Element &readScope, QQmlSA::SourceLocation location); + virtual void onWrite(const QQmlSA::Element &element, const QString &propertyName, + const QQmlSA::Element &value, const QQmlSA::Element &writeScope, + QQmlSA::SourceLocation location); +}; + +class Q_QMLCOMPILER_EXPORT ElementPass : public GenericPass +{ +public: + ElementPass(PassManager *manager) : GenericPass(manager) { } + + virtual bool shouldRun(const Element &element); + virtual void run(const Element &element) = 0; +}; + +class Q_QMLCOMPILER_EXPORT DebugElementPass : public ElementPass +{ + void run(const Element &element) override; +}; + +class Q_QMLCOMPILER_EXPORT DebugPropertyPass : public QQmlSA::PropertyPass +{ +public: + DebugPropertyPass(QQmlSA::PassManager *manager); + + void onRead(const QQmlSA::Element &element, const QString &propertyName, + const QQmlSA::Element &readScope, QQmlSA::SourceLocation location) override; + void onBinding(const QQmlSA::Element &element, const QString &propertyName, + const QQmlSA::Binding &binding, const QQmlSA::Element &bindingScope, + const QQmlSA::Element &value) override; + void onWrite(const QQmlSA::Element &element, const QString &propertyName, + const QQmlSA::Element &value, const QQmlSA::Element &writeScope, + QQmlSA::SourceLocation location) override; +}; + +class Q_QMLCOMPILER_EXPORT FixSuggestion +{ + Q_DECLARE_PRIVATE(FixSuggestion) + +public: + FixSuggestion(const QString &fixDescription, const QQmlSA::SourceLocation &location, + const QString &replacement = QString()); + FixSuggestion(const FixSuggestion &); + FixSuggestion(FixSuggestion &&) noexcept; + FixSuggestion &operator=(const FixSuggestion &); + FixSuggestion &operator=(FixSuggestion &&) noexcept; + ~FixSuggestion(); + + QString fixDescription() const; + QQmlSA::SourceLocation location() const; + QString replacement() const; + + void setFileName(const QString &); + QString fileName() const; + + void setHint(const QString &); + QString hint() const; + + void setAutoApplicable(bool autoApplicable = true); + bool isAutoApplicable() const; + + friend bool operator==(const FixSuggestion &lhs, const FixSuggestion &rhs) + { + return operatorEqualsImpl(lhs, rhs); + } + + friend bool operator!=(const FixSuggestion &lhs, const FixSuggestion &rhs) + { + return !operatorEqualsImpl(lhs, rhs); + } + +private: + static bool operatorEqualsImpl(const FixSuggestion &, const FixSuggestion &); + + std::unique_ptr<FixSuggestionPrivate> d_ptr; +}; + +} // namespace QQmlSA + +#define QmlLintPluginInterface_iid "org.qt-project.Qt.Qml.SA.LintPlugin/1.0" + +Q_DECLARE_INTERFACE(QQmlSA::LintPlugin, QmlLintPluginInterface_iid) + +QT_END_NAMESPACE + +#endif // QQMLSA_H |