Revision control
Copy as Markdown
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// Qt-Security score:significant
#ifndef QQMLSA_P_H
#define QQMLSA_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
#include <qtqmlcompilerexports.h>
#include <private/qqmljslogger_p.h>
#include <private/qqmlsasourcelocation_p.h>
#include "qqmljsmetatypes_p.h"
#include <unordered_map>
#include <vector>
#include <memory>
QT_BEGIN_NAMESPACE
class QQmlJSImportVisitor;
namespace QQmlSA {
enum class Flag {
Creatable = 0x1,
Composite = 0x2,
Singleton = 0x4,
Script = 0x8,
CustomParser = 0x10,
Array = 0x20,
InlineComponent = 0x40,
WrappedInImplicitComponent = 0x80,
HasBaseTypeError = 0x100,
HasExtensionNamespace = 0x200,
IsListProperty = 0x400,
};
struct PropertyPassInvocation
{
QString property;
std::shared_ptr<QQmlSA::PropertyPass> pass;
bool allowInheritance = true;
};
class BindingsPrivate
{
friend class QT_PREPEND_NAMESPACE(QQmlJSMetaPropertyBinding);
Q_DECLARE_PUBLIC(QQmlSA::Binding::Bindings)
public:
explicit BindingsPrivate(QQmlSA::Binding::Bindings *);
BindingsPrivate(QQmlSA::Binding::Bindings *, const BindingsPrivate &);
BindingsPrivate(QQmlSA::Binding::Bindings *, BindingsPrivate &&);
~BindingsPrivate() = default;
QMultiHash<QString, Binding>::const_iterator constBegin() const;
QMultiHash<QString, Binding>::const_iterator constEnd() const;
static QQmlSA::Binding::Bindings
createBindings(const QMultiHash<QString, QQmlJSMetaPropertyBinding> &);
static QQmlSA::Binding::Bindings
createBindings(std::pair<QMultiHash<QString, QQmlJSMetaPropertyBinding>::const_iterator,
QMultiHash<QString, QQmlJSMetaPropertyBinding>::const_iterator>);
private:
QMultiHash<QString, Binding> m_bindings;
QQmlSA::Binding::Bindings *q_ptr = nullptr;
};
class BindingPrivate
{
friend class QT_PREPEND_NAMESPACE(QQmlJSMetaPropertyBinding);
Q_DECLARE_PUBLIC(Binding)
public:
explicit BindingPrivate(Binding *);
BindingPrivate(Binding *, const BindingPrivate &);
static BindingPrivate *get(Binding *binding) { return binding->d_func(); }
static const BindingPrivate *get(const Binding *binding) { return binding->d_func(); }
static QQmlSA::Binding createBinding(const QQmlJSMetaPropertyBinding &);
static QQmlJSMetaPropertyBinding binding(QQmlSA::Binding &binding);
static const QQmlJSMetaPropertyBinding binding(const QQmlSA::Binding &binding);
void setPropertyName(QString name) { m_binding.setPropertyName(name); }
Element bindingScope() const { return m_bindingScope; }
void setBindingScope(Element bindingScope) { m_bindingScope = bindingScope; }
bool isAttached() const { return m_isAttached; }
void setIsAttached(bool isAttached) { m_isAttached = isAttached; }
private:
QQmlJSMetaPropertyBinding m_binding;
Element m_bindingScope;
Binding *q_ptr = nullptr;
bool m_isAttached = false;
};
bool isRegularBindingType(BindingType type);
class MethodPrivate
{
friend class QT_PREPEND_NAMESPACE(QQmlJSMetaMethod);
Q_DECLARE_PUBLIC(Method)
public:
explicit MethodPrivate(Method *);
MethodPrivate(Method *, const MethodPrivate &);
QString methodName() const;
QQmlSA::SourceLocation sourceLocation() const;
MethodType methodType() const;
static QQmlSA::Method createMethod(const QQmlJSMetaMethod &);
static QQmlJSMetaMethod method(const QQmlSA::Method &);
private:
QQmlJSMetaMethod m_method;
Method *q_ptr = nullptr;
};
class MethodsPrivate
{
friend class QT_PREPEND_NAMESPACE(QQmlJSMetaMethod);
Q_DECLARE_PUBLIC(QQmlSA::Method::Methods)
public:
explicit MethodsPrivate(QQmlSA::Method::Methods *);
MethodsPrivate(QQmlSA::Method::Methods *, const MethodsPrivate &);
MethodsPrivate(QQmlSA::Method::Methods *, MethodsPrivate &&);
~MethodsPrivate() = default;
QMultiHash<QString, Method>::const_iterator constBegin() const;
QMultiHash<QString, Method>::const_iterator constEnd() const;
static QQmlSA::Method::Methods createMethods(const QMultiHash<QString, QQmlJSMetaMethod> &);
private:
QMultiHash<QString, Method> m_methods;
QQmlSA::Method::Methods *q_ptr = nullptr;
};
class Q_QMLCOMPILER_EXPORT PropertyPrivate
{
friend class QT_PREPEND_NAMESPACE(QQmlJSMetaProperty);
Q_DECLARE_PUBLIC(QQmlSA::Property)
public:
explicit PropertyPrivate(Property *);
PropertyPrivate(Property *, const PropertyPrivate &);
PropertyPrivate(Property *, PropertyPrivate &&);
~PropertyPrivate() = default;
QString typeName() const;
bool isValid() const;
bool isReadonly() const;
QQmlSA::Element type() const;
static QQmlJSMetaProperty property(const QQmlSA::Property &property);
static QQmlSA::Property createProperty(const QQmlJSMetaProperty &);
private:
QQmlJSMetaProperty m_property;
QQmlSA::Property *q_ptr = nullptr;
};
class Q_QMLCOMPILER_EXPORT PassManagerPrivate
{
friend class QT_PREPEND_NAMESPACE(QQmlJSScope);
public:
Q_DISABLE_COPY_MOVE(PassManagerPrivate)
friend class GenericPass;
PassManagerPrivate(QQmlJSImportVisitor *visitor, QQmlJSTypeResolver *resolver)
: m_visitor(visitor), m_typeResolver(resolver)
{
}
static PassManagerPrivate *get(PassManager *manager) { return manager->d_func(); }
static const PassManagerPrivate *get(const PassManager *manager) { return manager->d_func(); }
static PassManager *createPassManager(QQmlJSImportVisitor *visitor, QQmlJSTypeResolver *resolver)
{
PassManager *result = new PassManager();
result->d_ptr = std::make_unique<PassManagerPrivate>(visitor, resolver);
return result;
}
static void deletePassManager(PassManager *q) { delete q; }
void registerElementPass(std::unique_ptr<ElementPass> pass);
bool registerPropertyPass(std::shared_ptr<PropertyPass> pass, QAnyStringView moduleName,
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;
static QQmlJSImportVisitor *visitor(const QQmlSA::PassManager &);
static QQmlJSTypeResolver *resolver(const QQmlSA::PassManager &);
QSet<PropertyPass *> findPropertyUsePasses(const QQmlSA::Element &element,
const QString &propertyName);
void analyzeWrite(const QQmlSA::Element &element, const QString &propertyName,
const QQmlSA::Element &value, const QQmlSA::Element &writeScope,
const QQmlSA::SourceLocation &location);
void analyzeRead(const QQmlSA::Element &element, const QString &propertyName,
const QQmlSA::Element &readScope, const QQmlSA::SourceLocation &location);
void analyzeCall(const QQmlSA::Element &element, const QString &propertyName,
const QQmlSA::Element &readScope, const QQmlSA::SourceLocation &location);
void analyzeBinding(const QQmlSA::Element &element, const QQmlSA::Element &value,
const QQmlSA::SourceLocation &location);
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<QString, PropertyPassInvocation> m_propertyPasses;
std::unordered_map<quint32, Binding> m_bindingsByLocation;
QQmlJSImportVisitor *m_visitor = nullptr;
QQmlJSTypeResolver *m_typeResolver = nullptr;
};
class FixSuggestionPrivate
{
Q_DECLARE_PUBLIC(FixSuggestion)
friend class QT_PREPEND_NAMESPACE(QQmlJSFixSuggestion);
public:
explicit FixSuggestionPrivate(FixSuggestion *);
FixSuggestionPrivate(
FixSuggestion *, const QString &description, const SourceLocation &location,
const QList<DocumentEdit> &documentEdits = {});
FixSuggestionPrivate(FixSuggestion *, const FixSuggestionPrivate &);
FixSuggestionPrivate(FixSuggestion *, FixSuggestionPrivate &&);
~FixSuggestionPrivate() = default;
SourceLocation location() const;
QString description() const;
void addDocumentEdit(const DocumentEdit &);
QList<DocumentEdit> documentEdits() const;
void setFileName(const QString &);
QString fileName() const;
void setAutoApplicable(bool autoApplicable = true);
bool isAutoApplicable() const;
static QQmlJSFixSuggestion &fixSuggestion(QQmlSA::FixSuggestion &);
static const QQmlJSFixSuggestion &fixSuggestion(const QQmlSA::FixSuggestion &);
static FixSuggestion createQQmlSAFixSuggestion(const QQmlJSFixSuggestion &);
private:
QQmlJSFixSuggestion m_fixSuggestion;
QQmlSA::FixSuggestion *q_ptr = nullptr;
};
class DocumentEditPrivate
{
Q_DECLARE_PUBLIC(DocumentEdit)
public:
DocumentEditPrivate(DocumentEdit *, const QString &filename,
const SourceLocation &location, const QString &replacement);
DocumentEditPrivate(DocumentEdit *, const DocumentEditPrivate &);
DocumentEditPrivate(DocumentEdit *, DocumentEditPrivate &&);
~DocumentEditPrivate() = default;
QString filename() const;
SourceLocation location() const;
QString replacement() const;
static QQmlJSDocumentEdit documentEdit(const DocumentEdit &edit);
static QList<QQmlJSDocumentEdit> documentEdits(const QList<DocumentEdit> &edits);
static DocumentEdit createQQmlSADocumentEdit(const QQmlJSDocumentEdit &edit);
private:
QQmlJSDocumentEdit m_documentEdit;
QQmlSA::DocumentEdit *q_ptr = nullptr;
};
Q_QMLCOMPILER_EXPORT void emitWarningWithOptionalFix(GenericPass &pass, QAnyStringView diagnostic,
const LoggerWarningId &id,
const QQmlSA::SourceLocation &srcLocation,
const std::optional<QQmlJSFixSuggestion> &fixSuggestion);
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
#endif