1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#ifndef QQMLSA_H
5#define QQMLSA_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is part of the qmllint plugin API, with limited compatibility guarantees.
12// Usage of this API may make your code source and binary incompatible with
13// future versions of Qt.
14//
15
16#include <QtQmlCompiler/qqmlsaconstants.h>
17#include <QtQmlCompiler/qqmljsloggingutils.h>
18
19#include <QtQmlCompiler/qtqmlcompilerexports.h>
20
21#include <QtCore/qhash.h>
22#include <QtCore/qsharedpointer.h>
23#include <QtCore/qplugin.h>
24#include <QtQmlCompiler/qqmlsasourcelocation.h>
25
26#include <unordered_map>
27
28QT_BEGIN_NAMESPACE
29
30class QQmlJSImportVisitor; // needed for PassManager
31class QQmlJSTypeResolver; // needed for PassManager
32struct QQmlJSTypePropagator; // needed for PassManager
33
34namespace QQmlJS {
35class ConstPtrWrapperIterator; // needed for Element's child scope iterators
36} // namespace QQmlJS
37
38namespace QQmlSA {
39
40class BindingPrivate;
41class BindingsPrivate;
42class Element;
43class ElementPass;
44class FixSuggestion;
45class FixSuggestionPrivate;
46class GenericPassPrivate;
47class MethodPrivate;
48class MethodsPrivate;
49class PassManager;
50class PassManagerPrivate;
51class PropertyPass;
52class PropertyPrivate;
53enum class AccessSemantics;
54struct BindingInfo;
55struct PropertyPassInfo;
56
57enum class MethodType { Signal, Slot, Method, StaticMethod };
58
59class Q_QMLCOMPILER_EXPORT Binding
60{
61 Q_DECLARE_PRIVATE(Binding)
62
63public:
64 class Q_QMLCOMPILER_EXPORT Bindings
65 {
66 Q_DECLARE_PRIVATE(Bindings)
67
68 public:
69 Bindings();
70 Bindings(const Bindings &);
71 ~Bindings();
72
73 QMultiHash<QString, Binding>::const_iterator begin() const { return constBegin(); }
74 QMultiHash<QString, Binding>::const_iterator end() const { return constEnd(); }
75 QMultiHash<QString, Binding>::const_iterator constBegin() const;
76 QMultiHash<QString, Binding>::const_iterator constEnd() const;
77
78 private:
79 std::unique_ptr<BindingsPrivate> d_ptr;
80 };
81
82 Binding();
83 Binding(const Binding &);
84 Binding(Binding &&) noexcept;
85 Binding &operator=(const Binding &);
86 Binding &operator=(Binding &&) noexcept;
87 ~Binding();
88
89 Element groupType() const;
90 BindingType bindingType() const;
91 QString stringValue() const;
92 QString propertyName() const;
93 Element attachingType() const;
94 QQmlSA::SourceLocation sourceLocation() const;
95 double numberValue() const;
96 ScriptBindingKind scriptKind() const;
97 bool hasObject() const;
98 Element objectType() const;
99 Element literalType(const QQmlJSTypeResolver *) const;
100 bool hasUndefinedScriptValue() const;
101
102 friend bool operator==(const Binding &lhs, const Binding &rhs)
103 {
104 return operatorEqualsImpl(lhs, rhs);
105 }
106 friend bool operator!=(const Binding &lhs, const Binding &rhs)
107 {
108 return !operatorEqualsImpl(lhs, rhs);
109 }
110
111 static bool isLiteralBinding(BindingType);
112
113private:
114 static bool operatorEqualsImpl(const Binding &, const Binding &);
115
116 std::unique_ptr<BindingPrivate> d_ptr;
117};
118
119class Q_QMLCOMPILER_EXPORT Method
120{
121 Q_DECLARE_PRIVATE(Method)
122
123public:
124 class Q_QMLCOMPILER_EXPORT Methods
125 {
126 Q_DECLARE_PRIVATE(Methods)
127
128 public:
129 Methods();
130 Methods(const Methods &);
131 ~Methods();
132
133 QMultiHash<QString, Method>::const_iterator begin() const { return constBegin(); }
134 QMultiHash<QString, Method>::const_iterator end() const { return constEnd(); }
135 QMultiHash<QString, Method>::const_iterator constBegin() const;
136 QMultiHash<QString, Method>::const_iterator constEnd() const;
137
138 private:
139 std::unique_ptr<MethodsPrivate> d_ptr;
140 };
141
142 Method();
143 Method(const Method &);
144 Method(Method &&) noexcept;
145 Method &operator=(const Method &);
146 Method &operator=(Method &&) noexcept;
147 ~Method();
148
149 QString methodName() const;
150 MethodType methodType() const;
151
152 friend bool operator==(const Method &lhs, const Method &rhs)
153 {
154 return operatorEqualsImpl(lhs, rhs);
155 }
156 friend bool operator!=(const Method &lhs, const Method &rhs)
157 {
158 return !operatorEqualsImpl(lhs, rhs);
159 }
160
161private:
162 static bool operatorEqualsImpl(const Method &, const Method &);
163
164 std::unique_ptr<MethodPrivate> d_ptr;
165};
166
167class Q_QMLCOMPILER_EXPORT Property
168{
169 Q_DECLARE_PRIVATE(Property)
170
171public:
172 Property();
173 Property(const Property &);
174 Property(Property &&) noexcept;
175 Property &operator=(const Property &);
176 Property &operator=(Property &&) noexcept;
177 ~Property();
178
179 QString typeName() const;
180 bool isValid() const;
181
182 friend bool operator==(const Property &lhs, const Property &rhs)
183 {
184 return operatorEqualsImpl(lhs, rhs);
185 }
186
187 friend bool operator!=(const Property &lhs, const Property &rhs)
188 {
189 return !operatorEqualsImpl(lhs, rhs);
190 }
191
192private:
193 static bool operatorEqualsImpl(const Property &, const Property &);
194
195 std::unique_ptr<PropertyPrivate> d_ptr;
196};
197
198class Q_QMLCOMPILER_EXPORT Element
199{
200 friend class QT_PREPEND_NAMESPACE(QQmlJSScope);
201
202public:
203 Element();
204 Element(const Element &);
205 Element(Element &&other) noexcept
206 {
207 memcpy(dest: m_data, src: other.m_data, n: sizeofElement);
208 memset(s: other.m_data, c: 0, n: sizeofElement);
209 }
210 Element &operator=(const Element &);
211 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(Element)
212 ~Element();
213
214 ScopeType scopeType() const;
215 Element baseType() const;
216 QString baseTypeName() const;
217 Element parentScope() const;
218 bool inherits(const Element &) const;
219
220 bool isNull() const;
221 QString internalId() const;
222 AccessSemantics accessSemantics() const;
223 bool isComposite() const;
224
225 bool hasProperty(const QString &propertyName) const;
226 Property property(const QString &propertyName) const;
227 bool isPropertyRequired(const QString &propertyName) const;
228 QString defaultPropertyName() const;
229
230 bool hasMethod(const QString &methodName) const;
231 Method::Methods ownMethods() const;
232
233 QQmlSA::SourceLocation sourceLocation() const;
234 QString filePath() const;
235
236 bool hasPropertyBindings(const QString &name) const;
237 bool hasOwnPropertyBindings(const QString &propertyName) const;
238
239 Binding::Bindings ownPropertyBindings() const;
240 Binding::Bindings ownPropertyBindings(const QString &propertyName) const;
241 QList<Binding> propertyBindings(const QString &propertyName) const;
242
243 QQmlJS::ConstPtrWrapperIterator childScopesBegin() const;
244 QQmlJS::ConstPtrWrapperIterator childScopesEnd() const;
245
246 explicit operator bool() const;
247 bool operator!() const;
248
249 QString name() const;
250
251 friend inline bool operator==(const QQmlSA::Element &lhs, const QQmlSA::Element &rhs)
252 {
253 return operatorEqualsImpl(lhs, rhs);
254 }
255 friend inline bool operator!=(const Element &lhs, const Element &rhs) { return !(lhs == rhs); }
256
257 friend inline qsizetype qHash(const Element &key, qsizetype seed = 0) noexcept
258 {
259 return qHashImpl(key, seed);
260 }
261
262private:
263 static bool operatorEqualsImpl(const Element &, const Element &);
264 static qsizetype qHashImpl(const Element &key, qsizetype seed) noexcept;
265
266 static constexpr qsizetype sizeofElement = 2 * sizeof(QSharedPointer<int>);
267 alignas(QSharedPointer<int>) char m_data[sizeofElement];
268
269 void swap(Element &other) noexcept
270 {
271 char t[sizeofElement];
272 memcpy(dest: t, src: m_data, n: sizeofElement);
273 memcpy(dest: m_data, src: other.m_data, n: sizeofElement);
274 memcpy(dest: other.m_data, src: t, n: sizeofElement);
275 }
276 friend void swap(Element &lhs, Element &rhs) noexcept { lhs.swap(other&: rhs); }
277};
278
279class Q_QMLCOMPILER_EXPORT GenericPass
280{
281 Q_DECLARE_PRIVATE(GenericPass)
282 Q_DISABLE_COPY_MOVE(GenericPass)
283
284public:
285 GenericPass(PassManager *manager);
286 virtual ~GenericPass();
287
288 void emitWarning(QAnyStringView diagnostic, LoggerWarningId id);
289 void emitWarning(QAnyStringView diagnostic, LoggerWarningId id,
290 QQmlSA::SourceLocation srcLocation);
291 void emitWarning(QAnyStringView diagnostic, LoggerWarningId id,
292 QQmlSA::SourceLocation srcLocation, const QQmlSA::FixSuggestion &fix);
293
294 Element resolveTypeInFileScope(QAnyStringView typeName);
295 Element resolveAttachedInFileScope(QAnyStringView typeName);
296 Element resolveType(QAnyStringView moduleName, QAnyStringView typeName); // #### TODO: revisions
297 Element resolveBuiltinType(QAnyStringView typeName) const;
298 Element resolveAttached(QAnyStringView moduleName, QAnyStringView typeName);
299 Element resolveLiteralType(const Binding &binding);
300
301 Element resolveIdToElement(QAnyStringView id, const Element &context);
302 QString resolveElementToId(const Element &element, const Element &context);
303
304 QString sourceCode(QQmlSA::SourceLocation location);
305
306private:
307 std::unique_ptr<GenericPassPrivate> d_ptr;
308};
309
310class Q_QMLCOMPILER_EXPORT PassManager
311{
312 friend struct ::QQmlJSTypePropagator;
313 Q_DECLARE_PRIVATE(PassManager)
314
315public:
316 PassManager(QQmlJSImportVisitor *visitor, QQmlJSTypeResolver *resolver);
317 ~PassManager();
318
319 void registerElementPass(std::unique_ptr<ElementPass> pass);
320 bool registerPropertyPass(std::shared_ptr<PropertyPass> pass, QAnyStringView moduleName,
321 QAnyStringView typeName,
322 QAnyStringView propertyName = QAnyStringView(),
323 bool allowInheritance = true);
324 void analyze(const Element &root);
325
326 bool hasImportedModule(QAnyStringView name) const;
327
328 bool isCategoryEnabled(LoggerWarningId category) const;
329
330 std::vector<std::shared_ptr<ElementPass>> elementPasses() const;
331 std::multimap<QString, PropertyPassInfo> propertyPasses() const;
332 std::unordered_map<quint32, BindingInfo> bindingsByLocation() const;
333
334private:
335 std::unique_ptr<PassManagerPrivate> d_ptr;
336};
337
338class Q_QMLCOMPILER_EXPORT LintPlugin
339{
340public:
341 LintPlugin() = default;
342 virtual ~LintPlugin() = default;
343
344 Q_DISABLE_COPY_MOVE(LintPlugin)
345
346 virtual void registerPasses(PassManager *manager, const Element &rootElement) = 0;
347};
348
349class Q_QMLCOMPILER_EXPORT PropertyPass : public GenericPass
350{
351public:
352 PropertyPass(PassManager *manager);
353
354 virtual void onBinding(const QQmlSA::Element &element, const QString &propertyName,
355 const QQmlSA::Binding &binding, const QQmlSA::Element &bindingScope,
356 const QQmlSA::Element &value);
357 virtual void onRead(const QQmlSA::Element &element, const QString &propertyName,
358 const QQmlSA::Element &readScope, QQmlSA::SourceLocation location);
359 virtual void onWrite(const QQmlSA::Element &element, const QString &propertyName,
360 const QQmlSA::Element &value, const QQmlSA::Element &writeScope,
361 QQmlSA::SourceLocation location);
362};
363
364class Q_QMLCOMPILER_EXPORT ElementPass : public GenericPass
365{
366public:
367 ElementPass(PassManager *manager) : GenericPass(manager) { }
368
369 virtual bool shouldRun(const Element &element);
370 virtual void run(const Element &element) = 0;
371};
372
373class Q_QMLCOMPILER_EXPORT DebugElementPass : public ElementPass
374{
375 void run(const Element &element) override;
376};
377
378class Q_QMLCOMPILER_EXPORT DebugPropertyPass : public QQmlSA::PropertyPass
379{
380public:
381 DebugPropertyPass(QQmlSA::PassManager *manager);
382
383 void onRead(const QQmlSA::Element &element, const QString &propertyName,
384 const QQmlSA::Element &readScope, QQmlSA::SourceLocation location) override;
385 void onBinding(const QQmlSA::Element &element, const QString &propertyName,
386 const QQmlSA::Binding &binding, const QQmlSA::Element &bindingScope,
387 const QQmlSA::Element &value) override;
388 void onWrite(const QQmlSA::Element &element, const QString &propertyName,
389 const QQmlSA::Element &value, const QQmlSA::Element &writeScope,
390 QQmlSA::SourceLocation location) override;
391};
392
393class Q_QMLCOMPILER_EXPORT FixSuggestion
394{
395 Q_DECLARE_PRIVATE(FixSuggestion)
396
397public:
398 FixSuggestion(const QString &fixDescription, const QQmlSA::SourceLocation &location,
399 const QString &replacement = QString());
400 FixSuggestion(const FixSuggestion &);
401 FixSuggestion(FixSuggestion &&) noexcept;
402 FixSuggestion &operator=(const FixSuggestion &);
403 FixSuggestion &operator=(FixSuggestion &&) noexcept;
404 ~FixSuggestion();
405
406 QString fixDescription() const;
407 QQmlSA::SourceLocation location() const;
408 QString replacement() const;
409
410 void setFileName(const QString &);
411 QString fileName() const;
412
413 void setHint(const QString &);
414 QString hint() const;
415
416 void setAutoApplicable(bool autoApplicable = true);
417 bool isAutoApplicable() const;
418
419 friend bool operator==(const FixSuggestion &lhs, const FixSuggestion &rhs)
420 {
421 return operatorEqualsImpl(lhs, rhs);
422 }
423
424 friend bool operator!=(const FixSuggestion &lhs, const FixSuggestion &rhs)
425 {
426 return !operatorEqualsImpl(lhs, rhs);
427 }
428
429private:
430 static bool operatorEqualsImpl(const FixSuggestion &, const FixSuggestion &);
431
432 std::unique_ptr<FixSuggestionPrivate> d_ptr;
433};
434
435} // namespace QQmlSA
436
437#define QmlLintPluginInterface_iid "org.qt-project.Qt.Qml.SA.LintPlugin/1.0"
438
439Q_DECLARE_INTERFACE(QQmlSA::LintPlugin, QmlLintPluginInterface_iid)
440
441QT_END_NAMESPACE
442
443#endif // QQMLSA_H
444

source code of qtdeclarative/src/qmlcompiler/qqmlsa.h