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
30namespace QQmlSA {
31
32class BindingPrivate;
33class BindingsPrivate;
34class Element;
35class ElementPass;
36class FixSuggestion;
37class FixSuggestionPrivate;
38class GenericPassPrivate;
39class MethodPrivate;
40class MethodsPrivate;
41class PassManager;
42class PassManagerPrivate;
43class PropertyPass;
44class PropertyPrivate;
45struct PropertyPassInfo;
46
47enum class MethodType { Signal, Slot, Method, StaticMethod };
48enum class AccessSemantics { Reference, Value, None, Sequence };
49
50class Q_QMLCOMPILER_EXPORT Binding
51{
52 Q_DECLARE_PRIVATE(Binding)
53
54public:
55 class Q_QMLCOMPILER_EXPORT Bindings
56 {
57 Q_DECLARE_PRIVATE(Bindings)
58
59 public:
60 Bindings();
61 Bindings(const Bindings &);
62 ~Bindings();
63
64 QMultiHash<QString, Binding>::const_iterator begin() const { return constBegin(); }
65 QMultiHash<QString, Binding>::const_iterator end() const { return constEnd(); }
66 QMultiHash<QString, Binding>::const_iterator constBegin() const;
67 QMultiHash<QString, Binding>::const_iterator constEnd() const;
68
69 private:
70 std::unique_ptr<BindingsPrivate> d_ptr;
71 };
72
73 Binding();
74 Binding(const Binding &);
75 Binding(Binding &&) noexcept;
76 Binding &operator=(const Binding &);
77 Binding &operator=(Binding &&) noexcept;
78 ~Binding();
79
80 Element groupType() const;
81 Element bindingScope() const;
82 BindingType bindingType() const;
83 QString stringValue() const;
84 QString propertyName() const;
85 bool isAttached() const;
86 Element attachedType() const;
87
88#if QT_DEPRECATED_SINCE(6, 9)
89 QT_DEPRECATED_X("Use attachedType()")
90 Element attachingType() const;
91#endif
92
93 QQmlSA::SourceLocation sourceLocation() const;
94 double numberValue() const;
95 ScriptBindingKind scriptKind() const;
96 bool hasObject() const;
97 Element objectType() const;
98 bool hasUndefinedScriptValue() const;
99 bool hasFunctionScriptValue() const;
100
101 friend bool operator==(const Binding &lhs, const Binding &rhs)
102 {
103 return operatorEqualsImpl(lhs, rhs);
104 }
105 friend bool operator!=(const Binding &lhs, const Binding &rhs)
106 {
107 return !operatorEqualsImpl(lhs, rhs);
108 }
109
110 static bool isLiteralBinding(BindingType);
111
112private:
113 static bool operatorEqualsImpl(const Binding &, const Binding &);
114
115 std::unique_ptr<BindingPrivate> d_ptr;
116};
117
118class Q_QMLCOMPILER_EXPORT Method
119{
120 Q_DECLARE_PRIVATE(Method)
121
122public:
123 class Q_QMLCOMPILER_EXPORT Methods
124 {
125 Q_DECLARE_PRIVATE(Methods)
126
127 public:
128 Methods();
129 Methods(const Methods &);
130 ~Methods();
131
132 QMultiHash<QString, Method>::const_iterator begin() const { return constBegin(); }
133 QMultiHash<QString, Method>::const_iterator end() const { return constEnd(); }
134 QMultiHash<QString, Method>::const_iterator constBegin() const;
135 QMultiHash<QString, Method>::const_iterator constEnd() const;
136
137 private:
138 std::unique_ptr<MethodsPrivate> d_ptr;
139 };
140
141 Method();
142 Method(const Method &);
143 Method(Method &&) noexcept;
144 Method &operator=(const Method &);
145 Method &operator=(Method &&) noexcept;
146 ~Method();
147
148 QString methodName() const;
149 QQmlSA::SourceLocation sourceLocation() 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 bool isReadonly() const;
182 QQmlSA::Element type() const;
183
184 friend bool operator==(const Property &lhs, const Property &rhs)
185 {
186 return operatorEqualsImpl(lhs, rhs);
187 }
188
189 friend bool operator!=(const Property &lhs, const Property &rhs)
190 {
191 return !operatorEqualsImpl(lhs, rhs);
192 }
193
194private:
195 static bool operatorEqualsImpl(const Property &, const Property &);
196
197 std::unique_ptr<PropertyPrivate> d_ptr;
198};
199
200class Q_QMLCOMPILER_EXPORT Element
201{
202 friend class QT_PREPEND_NAMESPACE(QQmlJSScope);
203
204public:
205 Element();
206 Element(const Element &);
207 Element(Element &&other) noexcept
208 {
209 memcpy(dest: m_data, src: other.m_data, n: sizeofElement);
210 memset(s: other.m_data, c: 0, n: sizeofElement);
211 }
212 Element &operator=(const Element &);
213 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(Element)
214 ~Element();
215
216 ScopeType scopeType() const;
217 Element baseType() const;
218 QString baseTypeName() const;
219 Element parentScope() const;
220 bool inherits(const Element &) const;
221 bool isFileRootComponent() const;
222
223 bool isNull() const;
224 QString internalId() const;
225 AccessSemantics accessSemantics() const;
226 bool isComposite() const;
227
228 bool hasProperty(const QString &propertyName) const;
229 bool hasOwnProperty(const QString &propertyName) const;
230 Property property(const QString &propertyName) const;
231 bool isPropertyRequired(const QString &propertyName) const;
232 QString defaultPropertyName() const;
233
234 bool hasMethod(const QString &methodName) const;
235 Method::Methods ownMethods() const;
236
237 QQmlSA::SourceLocation sourceLocation() const;
238 QQmlSA::SourceLocation idSourceLocation() const;
239 QString filePath() const;
240
241 bool hasPropertyBindings(const QString &name) const;
242 bool hasOwnPropertyBindings(const QString &propertyName) const;
243
244 Binding::Bindings ownPropertyBindings() const;
245 Binding::Bindings ownPropertyBindings(const QString &propertyName) const;
246 QList<Binding> propertyBindings(const QString &propertyName) const;
247
248 explicit operator bool() const;
249 bool operator!() const;
250
251 QString name() const;
252
253 friend inline bool operator==(const QQmlSA::Element &lhs, const QQmlSA::Element &rhs)
254 {
255 return operatorEqualsImpl(lhs, rhs);
256 }
257 friend inline bool operator!=(const Element &lhs, const Element &rhs) { return !(lhs == rhs); }
258
259 friend inline qsizetype qHash(const Element &key, qsizetype seed = 0) noexcept
260 {
261 return qHashImpl(key, seed);
262 }
263
264private:
265 static bool operatorEqualsImpl(const Element &, const Element &);
266 static qsizetype qHashImpl(const Element &key, qsizetype seed) noexcept;
267
268 static constexpr qsizetype sizeofElement = 2 * sizeof(QSharedPointer<int>);
269 alignas(QSharedPointer<int>) char m_data[sizeofElement];
270
271 void swap(Element &other) noexcept
272 {
273 char t[sizeofElement];
274 memcpy(dest: t, src: m_data, n: sizeofElement);
275 memcpy(dest: m_data, src: other.m_data, n: sizeofElement);
276 memcpy(dest: other.m_data, src: t, n: sizeofElement);
277 }
278 friend void swap(Element &lhs, Element &rhs) noexcept { lhs.swap(other&: rhs); }
279};
280
281class Q_QMLCOMPILER_EXPORT GenericPass
282{
283 Q_DECLARE_PRIVATE(GenericPass)
284 Q_DISABLE_COPY_MOVE(GenericPass)
285
286public:
287 GenericPass(PassManager *manager);
288 virtual ~GenericPass();
289
290 void emitWarning(QAnyStringView diagnostic, LoggerWarningId id);
291 void emitWarning(QAnyStringView diagnostic, LoggerWarningId id,
292 QQmlSA::SourceLocation srcLocation);
293 void emitWarning(QAnyStringView diagnostic, LoggerWarningId id,
294 QQmlSA::SourceLocation srcLocation, const QQmlSA::FixSuggestion &fix);
295
296 Element resolveTypeInFileScope(QAnyStringView typeName);
297 Element resolveAttachedInFileScope(QAnyStringView typeName);
298 Element resolveType(QAnyStringView moduleName, QAnyStringView typeName); // #### TODO: revisions
299 Element resolveBuiltinType(QAnyStringView typeName) const;
300 Element resolveAttached(QAnyStringView moduleName, QAnyStringView typeName);
301 Element resolveLiteralType(const Binding &binding);
302
303 Element resolveIdToElement(QAnyStringView id, const Element &context);
304 QString resolveElementToId(const Element &element, const Element &context);
305
306 QString sourceCode(QQmlSA::SourceLocation location);
307
308private:
309 std::unique_ptr<GenericPassPrivate> d_ptr;
310};
311
312class Q_QMLCOMPILER_EXPORT PassManager
313{
314 Q_DISABLE_COPY_MOVE(PassManager)
315 Q_DECLARE_PRIVATE(PassManager)
316
317public:
318 void registerElementPass(std::unique_ptr<ElementPass> pass);
319 bool registerPropertyPass(std::shared_ptr<PropertyPass> pass, QAnyStringView moduleName,
320 QAnyStringView typeName,
321 QAnyStringView propertyName = QAnyStringView(),
322 bool allowInheritance = true);
323 void analyze(const Element &root);
324
325 bool hasImportedModule(QAnyStringView name) const;
326
327 bool isCategoryEnabled(LoggerWarningId category) const;
328
329 std::unordered_map<quint32, Binding> bindingsByLocation() const;
330
331private:
332 PassManager();
333 ~PassManager();
334
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 onCall(const QQmlSA::Element &element, const QString &propertyName,
360 const QQmlSA::Element &readScope, QQmlSA::SourceLocation location);
361 virtual void onWrite(const QQmlSA::Element &element, const QString &propertyName,
362 const QQmlSA::Element &value, const QQmlSA::Element &writeScope,
363 QQmlSA::SourceLocation location);
364};
365
366class Q_QMLCOMPILER_EXPORT ElementPass : public GenericPass
367{
368public:
369 ElementPass(PassManager *manager) : GenericPass(manager) { }
370
371 virtual bool shouldRun(const Element &element);
372 virtual void run(const Element &element) = 0;
373};
374
375class Q_QMLCOMPILER_EXPORT DebugElementPass : public ElementPass
376{
377 void run(const Element &element) override;
378};
379
380class Q_QMLCOMPILER_EXPORT DebugPropertyPass : public QQmlSA::PropertyPass
381{
382public:
383 DebugPropertyPass(QQmlSA::PassManager *manager);
384
385 void onRead(const QQmlSA::Element &element, const QString &propertyName,
386 const QQmlSA::Element &readScope, QQmlSA::SourceLocation location) override;
387 void onBinding(const QQmlSA::Element &element, const QString &propertyName,
388 const QQmlSA::Binding &binding, const QQmlSA::Element &bindingScope,
389 const QQmlSA::Element &value) override;
390 void onWrite(const QQmlSA::Element &element, const QString &propertyName,
391 const QQmlSA::Element &value, const QQmlSA::Element &writeScope,
392 QQmlSA::SourceLocation location) override;
393};
394
395class Q_QMLCOMPILER_EXPORT FixSuggestion
396{
397 Q_DECLARE_PRIVATE(FixSuggestion)
398
399public:
400 FixSuggestion(const QString &fixDescription, const QQmlSA::SourceLocation &location,
401 const QString &replacement = QString());
402 FixSuggestion(const FixSuggestion &);
403 FixSuggestion(FixSuggestion &&) noexcept;
404 FixSuggestion &operator=(const FixSuggestion &);
405 FixSuggestion &operator=(FixSuggestion &&) noexcept;
406 ~FixSuggestion();
407
408 QString fixDescription() const;
409 QQmlSA::SourceLocation location() const;
410 QString replacement() const;
411
412 void setFileName(const QString &);
413 QString fileName() const;
414
415 void setHint(const QString &);
416 QString hint() const;
417
418 void setAutoApplicable(bool autoApplicable = true);
419 bool isAutoApplicable() const;
420
421 friend bool operator==(const FixSuggestion &lhs, const FixSuggestion &rhs)
422 {
423 return operatorEqualsImpl(lhs, rhs);
424 }
425
426 friend bool operator!=(const FixSuggestion &lhs, const FixSuggestion &rhs)
427 {
428 return !operatorEqualsImpl(lhs, rhs);
429 }
430
431private:
432 static bool operatorEqualsImpl(const FixSuggestion &, const FixSuggestion &);
433
434 std::unique_ptr<FixSuggestionPrivate> d_ptr;
435};
436
437} // namespace QQmlSA
438
439#define QmlLintPluginInterface_iid "org.qt-project.Qt.Qml.SA.LintPlugin/1.0"
440
441Q_DECLARE_INTERFACE(QQmlSA::LintPlugin, QmlLintPluginInterface_iid)
442
443QT_END_NAMESPACE
444
445#endif // QQMLSA_H
446

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