1// Copyright (C) 2022 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_P_H
5#define QQMLSA_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16
17#include <qtqmlcompilerexports.h>
18
19#include <private/qqmljslogger_p.h>
20#include <private/qqmlsasourcelocation_p.h>
21#include "qqmljsmetatypes_p.h"
22
23#include <unordered_map>
24#include <vector>
25#include <memory>
26
27QT_BEGIN_NAMESPACE
28
29class QQmlJSImportVisitor;
30
31namespace QQmlSA {
32
33enum class Flag {
34 Creatable = 0x1,
35 Composite = 0x2,
36 Singleton = 0x4,
37 Script = 0x8,
38 CustomParser = 0x10,
39 Array = 0x20,
40 InlineComponent = 0x40,
41 WrappedInImplicitComponent = 0x80,
42 HasBaseTypeError = 0x100,
43 HasExtensionNamespace = 0x200,
44 IsListProperty = 0x400,
45};
46
47struct PropertyPassInvocation
48{
49 QString property;
50 std::shared_ptr<QQmlSA::PropertyPass> pass;
51 bool allowInheritance = true;
52};
53
54class BindingsPrivate
55{
56 friend class QT_PREPEND_NAMESPACE(QQmlJSMetaPropertyBinding);
57 Q_DECLARE_PUBLIC(QQmlSA::Binding::Bindings)
58
59public:
60 explicit BindingsPrivate(QQmlSA::Binding::Bindings *);
61 BindingsPrivate(QQmlSA::Binding::Bindings *, const BindingsPrivate &);
62 BindingsPrivate(QQmlSA::Binding::Bindings *, BindingsPrivate &&);
63 ~BindingsPrivate() = default;
64
65 QMultiHash<QString, Binding>::const_iterator constBegin() const;
66 QMultiHash<QString, Binding>::const_iterator constEnd() const;
67
68 static QQmlSA::Binding::Bindings
69 createBindings(const QMultiHash<QString, QQmlJSMetaPropertyBinding> &);
70 static QQmlSA::Binding::Bindings
71 createBindings(std::pair<QMultiHash<QString, QQmlJSMetaPropertyBinding>::const_iterator,
72 QMultiHash<QString, QQmlJSMetaPropertyBinding>::const_iterator>);
73
74private:
75 QMultiHash<QString, Binding> m_bindings;
76 QQmlSA::Binding::Bindings *q_ptr = nullptr;
77};
78
79class BindingPrivate
80{
81 friend class QT_PREPEND_NAMESPACE(QQmlJSMetaPropertyBinding);
82 Q_DECLARE_PUBLIC(Binding)
83
84public:
85 explicit BindingPrivate(Binding *);
86 BindingPrivate(Binding *, const BindingPrivate &);
87
88 static BindingPrivate *get(Binding *binding) { return binding->d_func(); }
89 static const BindingPrivate *get(const Binding *binding) { return binding->d_func(); }
90
91 static QQmlSA::Binding createBinding(const QQmlJSMetaPropertyBinding &);
92 static QQmlJSMetaPropertyBinding binding(QQmlSA::Binding &binding);
93 static const QQmlJSMetaPropertyBinding binding(const QQmlSA::Binding &binding);
94
95 void setPropertyName(QString name) { m_binding.setPropertyName(name); }
96
97 Element bindingScope() const { return m_bindingScope; }
98 void setBindingScope(Element bindingScope) { m_bindingScope = bindingScope; }
99
100 bool isAttached() const { return m_isAttached; }
101 void setIsAttached(bool isAttached) { m_isAttached = isAttached; }
102
103private:
104 QQmlJSMetaPropertyBinding m_binding;
105 Element m_bindingScope;
106 Binding *q_ptr = nullptr;
107 bool m_isAttached = false;
108};
109
110bool isRegularBindingType(BindingType type);
111
112class MethodPrivate
113{
114 friend class QT_PREPEND_NAMESPACE(QQmlJSMetaMethod);
115 Q_DECLARE_PUBLIC(Method)
116
117public:
118 explicit MethodPrivate(Method *);
119 MethodPrivate(Method *, const MethodPrivate &);
120
121 QString methodName() const;
122 QQmlSA::SourceLocation sourceLocation() const;
123 MethodType methodType() const;
124
125 static QQmlSA::Method createMethod(const QQmlJSMetaMethod &);
126 static QQmlJSMetaMethod method(const QQmlSA::Method &);
127
128private:
129 QQmlJSMetaMethod m_method;
130 Method *q_ptr = nullptr;
131};
132
133class MethodsPrivate
134{
135 friend class QT_PREPEND_NAMESPACE(QQmlJSMetaMethod);
136 Q_DECLARE_PUBLIC(QQmlSA::Method::Methods)
137
138public:
139 explicit MethodsPrivate(QQmlSA::Method::Methods *);
140 MethodsPrivate(QQmlSA::Method::Methods *, const MethodsPrivate &);
141 MethodsPrivate(QQmlSA::Method::Methods *, MethodsPrivate &&);
142 ~MethodsPrivate() = default;
143
144 QMultiHash<QString, Method>::const_iterator constBegin() const;
145 QMultiHash<QString, Method>::const_iterator constEnd() const;
146
147 static QQmlSA::Method::Methods createMethods(const QMultiHash<QString, QQmlJSMetaMethod> &);
148
149private:
150 QMultiHash<QString, Method> m_methods;
151 QQmlSA::Method::Methods *q_ptr = nullptr;
152};
153
154class PropertyPrivate
155{
156 friend class QT_PREPEND_NAMESPACE(QQmlJSMetaProperty);
157 Q_DECLARE_PUBLIC(QQmlSA::Property)
158
159public:
160 explicit PropertyPrivate(Property *);
161 PropertyPrivate(Property *, const PropertyPrivate &);
162 PropertyPrivate(Property *, PropertyPrivate &&);
163 ~PropertyPrivate() = default;
164
165 QString typeName() const;
166 bool isValid() const;
167 bool isReadonly() const;
168 QQmlSA::Element type() const;
169
170 static QQmlJSMetaProperty property(const QQmlSA::Property &property);
171 static QQmlSA::Property createProperty(const QQmlJSMetaProperty &);
172
173private:
174 QQmlJSMetaProperty m_property;
175 QQmlSA::Property *q_ptr = nullptr;
176};
177
178class Q_QMLCOMPILER_EXPORT PassManagerPrivate
179{
180 friend class QT_PREPEND_NAMESPACE(QQmlJSScope);
181
182public:
183 Q_DISABLE_COPY_MOVE(PassManagerPrivate)
184
185 friend class GenericPass;
186 PassManagerPrivate(QQmlJSImportVisitor *visitor, QQmlJSTypeResolver *resolver)
187 : m_visitor(visitor), m_typeResolver(resolver)
188 {
189 }
190
191 static PassManagerPrivate *get(PassManager *manager) { return manager->d_func(); }
192 static const PassManagerPrivate *get(const PassManager *manager) { return manager->d_func(); }
193 static PassManager *createPassManager(QQmlJSImportVisitor *visitor, QQmlJSTypeResolver *resolver)
194 {
195 PassManager *result = new PassManager();
196 result->d_ptr = std::make_unique<PassManagerPrivate>(args&: visitor, args&: resolver);
197 return result;
198 }
199 static void deletePassManager(PassManager *q) { delete q; }
200
201 void registerElementPass(std::unique_ptr<ElementPass> pass);
202 bool registerPropertyPass(std::shared_ptr<PropertyPass> pass, QAnyStringView moduleName,
203 QAnyStringView typeName,
204 QAnyStringView propertyName = QAnyStringView(),
205 bool allowInheritance = true);
206 bool registerPropertyPassOnBuiltinType(std::shared_ptr<PropertyPass> pass,
207 QAnyStringView typeName,
208 QAnyStringView propertyName = QAnyStringView(),
209 bool allowInheritance = true);
210
211 void analyze(const Element &root);
212
213 bool hasImportedModule(QAnyStringView name) const;
214
215 static QQmlJSImportVisitor *visitor(const QQmlSA::PassManager &);
216 static QQmlJSTypeResolver *resolver(const QQmlSA::PassManager &);
217
218
219 QSet<PropertyPass *> findPropertyUsePasses(const QQmlSA::Element &element,
220 const QString &propertyName);
221
222 void analyzeWrite(const QQmlSA::Element &element, const QString &propertyName,
223 const QQmlSA::Element &value, const QQmlSA::Element &writeScope,
224 const QQmlSA::SourceLocation &location);
225 void analyzeRead(const QQmlSA::Element &element, const QString &propertyName,
226 const QQmlSA::Element &readScope, const QQmlSA::SourceLocation &location);
227 void analyzeCall(const QQmlSA::Element &element, const QString &propertyName,
228 const QQmlSA::Element &readScope, const QQmlSA::SourceLocation &location);
229 void analyzeBinding(const QQmlSA::Element &element, const QQmlSA::Element &value,
230 const QQmlSA::SourceLocation &location);
231
232 void addBindingSourceLocations(const QQmlSA::Element &element,
233 const QQmlSA::Element &scope = QQmlSA::Element(),
234 const QString prefix = QString(), bool isAttached = false);
235
236 std::vector<std::unique_ptr<ElementPass>> m_elementPasses;
237 std::multimap<QString, PropertyPassInvocation> m_propertyPasses;
238 std::unordered_map<quint32, Binding> m_bindingsByLocation;
239 QQmlJSImportVisitor *m_visitor = nullptr;
240 QQmlJSTypeResolver *m_typeResolver = nullptr;
241};
242
243class FixSuggestionPrivate
244{
245 Q_DECLARE_PUBLIC(FixSuggestion)
246 friend class QT_PREPEND_NAMESPACE(QQmlJSFixSuggestion);
247
248public:
249 explicit FixSuggestionPrivate(FixSuggestion *);
250 FixSuggestionPrivate(FixSuggestion *, const QString &fixDescription,
251 const QQmlSA::SourceLocation &location, const QString &replacement);
252 FixSuggestionPrivate(FixSuggestion *, const FixSuggestionPrivate &);
253 FixSuggestionPrivate(FixSuggestion *, FixSuggestionPrivate &&);
254 ~FixSuggestionPrivate() = default;
255
256 QString fixDescription() const;
257 QQmlSA::SourceLocation location() const;
258 QString replacement() const;
259
260 void setFileName(const QString &);
261 QString fileName() const;
262
263 void setHint(const QString &);
264 QString hint() const;
265
266 void setAutoApplicable(bool autoApplicable = true);
267 bool isAutoApplicable() const;
268
269 static QQmlJSFixSuggestion &fixSuggestion(QQmlSA::FixSuggestion &);
270 static const QQmlJSFixSuggestion &fixSuggestion(const QQmlSA::FixSuggestion &);
271
272private:
273 QQmlJSFixSuggestion m_fixSuggestion;
274 QQmlSA::FixSuggestion *q_ptr = nullptr;
275};
276
277Q_QMLCOMPILER_EXPORT void emitWarningWithOptionalFix(GenericPass &pass, QAnyStringView diagnostic,
278 const LoggerWarningId &id,
279 const QQmlSA::SourceLocation &srcLocation,
280 const std::optional<QQmlJSFixSuggestion> &fix);
281
282struct GenericPropertyPass : public PropertyPass
283{
284 using PropertyPass::PropertyPass;
285
286 static void onBindingDefault(PropertyPass *, const Element &, const QString &, const Binding &,
287 const Element &, const Element &)
288 {
289 }
290 static void onReadDefault(PropertyPass *, const Element &, const QString &, const Element &,
291 SourceLocation)
292 {
293 }
294 static void onCallDefault(PropertyPass *, const Element &, const QString &, const Element &,
295 SourceLocation)
296 {
297 }
298 static void onWriteDefault(PropertyPass *, const Element &, const QString &, const Element &,
299 const Element &, SourceLocation)
300 {
301 }
302
303 using OnBinding = decltype(&onBindingDefault);
304 using OnRead = decltype(&onReadDefault);
305 using OnCall = decltype(&onCallDefault);
306 using OnWrite = decltype(&onWriteDefault);
307
308 void onBinding(const Element &element, const QString &propertyName, const Binding &binding,
309 const Element &bindingScope, const Element &value) override
310 {
311 m_onBinding(this, element, propertyName, binding, bindingScope, value);
312 }
313 void onRead(const Element &element, const QString &propertyName, const Element &readScope,
314 SourceLocation location) override
315 {
316 m_onRead(this, element, propertyName, readScope, location);
317 }
318 void onCall(const Element &element, const QString &propertyName, const Element &readScope,
319 SourceLocation location) override
320 {
321 m_onCall(this, element, propertyName, readScope, location);
322 }
323 void onWrite(const Element &element, const QString &propertyName, const Element &value,
324 const Element &writeScope, SourceLocation location) override
325 {
326 m_onWrite(this, element, propertyName, value, writeScope, location);
327 }
328
329 OnBinding m_onBinding = &onBindingDefault;
330 OnRead m_onRead = &onReadDefault;
331 OnCall m_onCall = &onCallDefault;
332 OnWrite m_onWrite = &onWriteDefault;
333};
334
335class PropertyPassBuilder
336{
337public:
338 PropertyPassBuilder(PassManager *passManager)
339 : m_pass(std::make_unique<GenericPropertyPass>(args&: passManager)), m_passManager(passManager)
340 {
341 Q_ASSERT(m_passManager);
342 }
343
344 PropertyPassBuilder() = delete;
345 Q_DISABLE_COPY_MOVE(PropertyPassBuilder)
346 ~PropertyPassBuilder()
347 {
348 Q_ASSERT_X(!m_pass, "GenericPropertyPassBuilder", "Built PropertyPass was not registered!");
349 }
350
351 PropertyPassBuilder &withOnBinding(GenericPropertyPass::OnBinding onBinding)
352 {
353 Q_ASSERT_X(m_pass, "GenericPropertyPassBuilder",
354 "PropertyPasses can't be modified after registration");
355 m_pass->m_onBinding = onBinding;
356 return *this;
357 }
358 PropertyPassBuilder &withOnRead(GenericPropertyPass::OnRead onRead)
359 {
360 Q_ASSERT_X(m_pass, "GenericPropertyPassBuilder",
361 "PropertyPasses can't be modified after registration");
362 m_pass->m_onRead = onRead;
363 return *this;
364 }
365 PropertyPassBuilder &withOnCall(GenericPropertyPass::OnCall onCall)
366 {
367 Q_ASSERT_X(m_pass, "GenericPropertyPassBuilder",
368 "PropertyPasses can't be modified after registration");
369 m_pass->m_onCall = onCall;
370 return *this;
371 }
372 PropertyPassBuilder &withOnWrite(GenericPropertyPass::OnWrite onWrite)
373 {
374 Q_ASSERT_X(m_pass, "GenericPropertyPassBuilder",
375 "PropertyPasses can't be modified after registration");
376 m_pass->m_onWrite = onWrite;
377 return *this;
378 }
379 void registerOn(QAnyStringView module, QAnyStringView type, QAnyStringView property)
380 {
381 Q_ASSERT_X(m_pass, "GenericPropertyPassBuilder",
382 "Current PropertyPass was already registered");
383 m_passManager->registerPropertyPass(pass: std::move(m_pass), moduleName: module, typeName: type, propertyName: property);
384 }
385 void registerOnBuiltin(QAnyStringView type, QAnyStringView property)
386 {
387 Q_ASSERT_X(m_pass, "GenericPropertyPassBuilder",
388 "Current PropertyPass was already registered");
389 PassManagerPrivate::get(manager: m_passManager)
390 ->registerPropertyPassOnBuiltinType(pass: std::move(m_pass), typeName: type, propertyName: property);
391 }
392
393private:
394 std::unique_ptr<GenericPropertyPass> m_pass;
395 PassManager *m_passManager;
396};
397
398} // namespace QQmlSA
399
400QT_END_NAMESPACE
401
402#endif
403

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