1 | // Copyright (C) 2019 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 QQMLJSSCOPE_P_H |
5 | #define QQMLJSSCOPE_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 <private/qtqmlcompilerexports_p.h> |
18 | |
19 | #include "qqmljsmetatypes_p.h" |
20 | #include "qdeferredpointer_p.h" |
21 | #include "qqmljsannotation_p.h" |
22 | #include "qqmlsaconstants.h" |
23 | #include "qqmlsa_p.h" |
24 | |
25 | #include <QtQml/private/qqmljssourcelocation_p.h> |
26 | |
27 | #include <QtCore/qfileinfo.h> |
28 | #include <QtCore/qhash.h> |
29 | #include <QtCore/qset.h> |
30 | #include <QtCore/qstring.h> |
31 | #include <QtCore/qversionnumber.h> |
32 | #include "qqmlsaconstants.h" |
33 | |
34 | #include <optional> |
35 | |
36 | QT_BEGIN_NAMESPACE |
37 | |
38 | class QQmlJSImporter; |
39 | |
40 | namespace QQmlJS { |
41 | |
42 | class ConstPtrWrapperIterator |
43 | { |
44 | public: |
45 | using Ptr = QDeferredSharedPointer<QQmlJSScope>; |
46 | using ConstPtr = QDeferredSharedPointer<const QQmlJSScope>; |
47 | using iterator_category = std::forward_iterator_tag; |
48 | using difference_type = std::ptrdiff_t; |
49 | using value_type = ConstPtr; |
50 | using pointer = value_type *; |
51 | using reference = value_type &; |
52 | |
53 | ConstPtrWrapperIterator(QList<Ptr>::const_iterator iterator) : m_iterator(iterator) { } |
54 | |
55 | friend bool operator==(const ConstPtrWrapperIterator &a, const ConstPtrWrapperIterator &b) |
56 | { |
57 | return a.m_iterator == b.m_iterator; |
58 | } |
59 | friend bool operator!=(const ConstPtrWrapperIterator &a, const ConstPtrWrapperIterator &b) |
60 | { |
61 | return a.m_iterator != b.m_iterator; |
62 | } |
63 | |
64 | reference operator*() |
65 | { |
66 | if (!m_pointer) |
67 | m_pointer = *m_iterator; |
68 | return m_pointer; |
69 | } |
70 | pointer operator->() |
71 | { |
72 | if (!m_pointer) |
73 | m_pointer = *m_iterator; |
74 | return &m_pointer; |
75 | } |
76 | |
77 | ConstPtrWrapperIterator &operator++() |
78 | { |
79 | m_iterator++; |
80 | m_pointer = {}; |
81 | return *this; |
82 | } |
83 | ConstPtrWrapperIterator operator++(int) |
84 | { |
85 | auto before = *this; |
86 | ++(*this); |
87 | return before; |
88 | } |
89 | |
90 | private: |
91 | QList<Ptr>::const_iterator m_iterator; |
92 | ConstPtr m_pointer; |
93 | }; |
94 | |
95 | } // namespace QQmlJS |
96 | |
97 | class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSScope |
98 | { |
99 | friend QQmlSA::Element; |
100 | |
101 | public: |
102 | explicit QQmlJSScope(const QString &internalName); |
103 | QQmlJSScope(QQmlJSScope &&) = default; |
104 | QQmlJSScope &operator=(QQmlJSScope &&) = default; |
105 | |
106 | using Ptr = QDeferredSharedPointer<QQmlJSScope>; |
107 | using WeakPtr = QDeferredWeakPointer<QQmlJSScope>; |
108 | using ConstPtr = QDeferredSharedPointer<const QQmlJSScope>; |
109 | using WeakConstPtr = QDeferredWeakPointer<const QQmlJSScope>; |
110 | |
111 | using AccessSemantics = QQmlSA::AccessSemantics; |
112 | using ScopeType = QQmlSA::ScopeType; |
113 | |
114 | using InlineComponentNameType = QString; |
115 | using RootDocumentNameType = std::monostate; // an empty type that has std::hash |
116 | /*! |
117 | * A Hashable type to differentiate document roots from different inline components. |
118 | */ |
119 | using InlineComponentOrDocumentRootName = |
120 | std::variant<InlineComponentNameType, RootDocumentNameType>; |
121 | |
122 | enum Flag { |
123 | Creatable = 0x1, |
124 | Composite = 0x2, |
125 | Singleton = 0x4, |
126 | Script = 0x8, |
127 | CustomParser = 0x10, |
128 | Array = 0x20, |
129 | InlineComponent = 0x40, |
130 | WrappedInImplicitComponent = 0x80, |
131 | HasBaseTypeError = 0x100, |
132 | HasExtensionNamespace = 0x200, |
133 | IsListProperty = 0x400, |
134 | }; |
135 | Q_DECLARE_FLAGS(Flags, Flag) |
136 | Q_FLAGS(Flags); |
137 | |
138 | class Import |
139 | { |
140 | public: |
141 | Import() = default; |
142 | Import(QString prefix, QString name, QTypeRevision version, bool isFile, bool isDependency); |
143 | |
144 | bool isValid() const; |
145 | |
146 | QString prefix() const { return m_prefix; } |
147 | QString name() const { return m_name; } |
148 | QTypeRevision version() const { return m_version; } |
149 | bool isFile() const { return m_isFile; } |
150 | bool isDependency() const { return m_isDependency; } |
151 | |
152 | private: |
153 | QString m_prefix; |
154 | QString m_name; |
155 | QTypeRevision m_version; |
156 | bool m_isFile = false; |
157 | bool m_isDependency = false; |
158 | |
159 | friend inline size_t qHash(const Import &key, size_t seed = 0) noexcept |
160 | { |
161 | return qHashMulti(seed, args: key.m_prefix, args: key.m_name, args: key.m_version, |
162 | args: key.m_isFile, args: key.m_isDependency); |
163 | } |
164 | |
165 | friend inline bool operator==(const Import &a, const Import &b) |
166 | { |
167 | return a.m_prefix == b.m_prefix && a.m_name == b.m_name && a.m_version == b.m_version |
168 | && a.m_isFile == b.m_isFile && a.m_isDependency == b.m_isDependency; |
169 | } |
170 | }; |
171 | |
172 | class Export { |
173 | public: |
174 | Export() = default; |
175 | Export(QString package, QString type, QTypeRevision version, QTypeRevision revision); |
176 | |
177 | bool isValid() const; |
178 | |
179 | QString package() const { return m_package; } |
180 | QString type() const { return m_type; } |
181 | QTypeRevision version() const { return m_version; } |
182 | QTypeRevision revision() const { return m_revision; } |
183 | |
184 | private: |
185 | QString m_package; |
186 | QString m_type; |
187 | QTypeRevision m_version; |
188 | QTypeRevision m_revision; |
189 | }; |
190 | |
191 | template<typename Pointer> |
192 | struct ExportedScope { |
193 | Pointer scope; |
194 | QList<QQmlJSScope::Export> exports; |
195 | }; |
196 | |
197 | template<typename Pointer> |
198 | struct ImportedScope { |
199 | Pointer scope; |
200 | QTypeRevision revision; |
201 | }; |
202 | |
203 | /*! \internal |
204 | * Maps type names to types and the compile context of the types. The context can be |
205 | * INTERNAl (for c++ and synthetic jsrootgen types) or QML (for qml types). |
206 | */ |
207 | struct ContextualTypes |
208 | { |
209 | enum CompileContext { INTERNAL, QML }; |
210 | |
211 | ContextualTypes( |
212 | CompileContext context, |
213 | const QHash<QString, ImportedScope<ConstPtr>> types, |
214 | const QQmlJSScope::ConstPtr &arrayType) |
215 | : m_types(types) |
216 | , m_context(context) |
217 | , m_arrayType(arrayType) |
218 | {} |
219 | |
220 | CompileContext context() const { return m_context; } |
221 | ConstPtr arrayType() const { return m_arrayType; } |
222 | |
223 | bool hasType(const QString &name) const { return m_types.contains(key: name); } |
224 | ImportedScope<ConstPtr> type(const QString &name) const { return m_types[name]; } |
225 | void setType(const QString &name, const ImportedScope<ConstPtr> &type) |
226 | { |
227 | m_types.insert(key: name, value: type); |
228 | } |
229 | void clearType(const QString &name) |
230 | { |
231 | m_types[name].scope = QQmlJSScope::ConstPtr(); |
232 | } |
233 | |
234 | bool isNullType(const QString &name) const |
235 | { |
236 | const auto it = m_types.constFind(key: name); |
237 | return it != m_types.constEnd() && it->scope.isNull(); |
238 | } |
239 | |
240 | void addTypes(ContextualTypes &&types) |
241 | { |
242 | Q_ASSERT(types.m_context == m_context); |
243 | m_types.insert(hash: std::move(types.m_types)); |
244 | } |
245 | |
246 | void addTypes(const ContextualTypes &types) |
247 | { |
248 | Q_ASSERT(types.m_context == m_context); |
249 | m_types.insert(hash: types.m_types); |
250 | } |
251 | |
252 | const QHash<QString, ImportedScope<ConstPtr>> &types() const { return m_types; } |
253 | |
254 | void clearTypes() { m_types.clear(); } |
255 | |
256 | private: |
257 | QHash<QString, ImportedScope<ConstPtr>> m_types; |
258 | CompileContext m_context; |
259 | |
260 | // For resolving enums |
261 | QQmlJSScope::ConstPtr m_intType; |
262 | |
263 | // For resolving sequence types |
264 | QQmlJSScope::ConstPtr m_arrayType; |
265 | }; |
266 | |
267 | struct JavaScriptIdentifier |
268 | { |
269 | enum Kind { |
270 | Parameter, |
271 | FunctionScoped, |
272 | LexicalScoped, |
273 | Injected |
274 | }; |
275 | |
276 | Kind kind = FunctionScoped; |
277 | QQmlJS::SourceLocation location; |
278 | std::optional<QString> typeName; |
279 | bool isConst = false; |
280 | QQmlJSScope::WeakConstPtr scope = {}; |
281 | }; |
282 | |
283 | enum BindingTargetSpecifier { |
284 | SimplePropertyTarget, // e.g. `property int p: 42` |
285 | ListPropertyTarget, // e.g. `property list<Item> pList: [ Text {} ]` |
286 | UnnamedPropertyTarget // default property bindings, where property name is unspecified |
287 | }; |
288 | |
289 | static QQmlJSScope::Ptr create() { return QSharedPointer<QQmlJSScope>(new QQmlJSScope); } |
290 | static QQmlJSScope::Ptr create(const QString &internalName) |
291 | { |
292 | return QSharedPointer<QQmlJSScope>(new QQmlJSScope(internalName)); |
293 | } |
294 | static QQmlJSScope::Ptr clone(const QQmlJSScope::ConstPtr &origin); |
295 | static QQmlJSScope::ConstPtr findCurrentQMLScope(const QQmlJSScope::ConstPtr &scope); |
296 | |
297 | QQmlJSScope::Ptr parentScope() |
298 | { |
299 | return m_parentScope.toStrongRef(); |
300 | } |
301 | |
302 | QQmlJSScope::ConstPtr parentScope() const |
303 | { |
304 | QT_WARNING_PUSH |
305 | #if defined(Q_CC_GNU_ONLY) && Q_CC_GNU < 1400 && Q_CC_GNU >= 1200 |
306 | QT_WARNING_DISABLE_GCC("-Wuse-after-free" ) |
307 | #endif |
308 | return QQmlJSScope::WeakConstPtr(m_parentScope).toStrongRef(); |
309 | QT_WARNING_POP |
310 | } |
311 | |
312 | static void reparent(const QQmlJSScope::Ptr &parentScope, const QQmlJSScope::Ptr &childScope); |
313 | |
314 | void insertJSIdentifier(const QString &name, const JavaScriptIdentifier &identifier); |
315 | |
316 | // inserts property as qml identifier as well as the corresponding |
317 | void insertPropertyIdentifier(const QQmlJSMetaProperty &prop); |
318 | |
319 | bool isIdInCurrentScope(const QString &id) const; |
320 | |
321 | ScopeType scopeType() const { return m_scopeType; } |
322 | void setScopeType(ScopeType type) { m_scopeType = type; } |
323 | |
324 | void addOwnMethod(const QQmlJSMetaMethod &method) { m_methods.insert(key: method.methodName(), value: method); } |
325 | QMultiHash<QString, QQmlJSMetaMethod> ownMethods() const { return m_methods; } |
326 | QList<QQmlJSMetaMethod> ownMethods(const QString &name) const { return m_methods.values(key: name); } |
327 | bool hasOwnMethod(const QString &name) const { return m_methods.contains(key: name); } |
328 | |
329 | bool hasMethod(const QString &name) const; |
330 | QHash<QString, QQmlJSMetaMethod> methods() const; |
331 | QList<QQmlJSMetaMethod> methods(const QString &name) const; |
332 | QList<QQmlJSMetaMethod> methods(const QString &name, QQmlJSMetaMethodType type) const; |
333 | |
334 | void addOwnEnumeration(const QQmlJSMetaEnum &enumeration) { m_enumerations.insert(key: enumeration.name(), value: enumeration); } |
335 | QHash<QString, QQmlJSMetaEnum> ownEnumerations() const { return m_enumerations; } |
336 | QQmlJSMetaEnum ownEnumeration(const QString &name) const { return m_enumerations.value(key: name); } |
337 | bool hasOwnEnumeration(const QString &name) const { return m_enumerations.contains(key: name); } |
338 | |
339 | bool hasEnumeration(const QString &name) const; |
340 | bool hasEnumerationKey(const QString &name) const; |
341 | QQmlJSMetaEnum enumeration(const QString &name) const; |
342 | QHash<QString, QQmlJSMetaEnum> enumerations() const; |
343 | |
344 | void setAnnotations(const QList<QQmlJSAnnotation> &annotation) { m_annotations = std::move(annotation); } |
345 | const QList<QQmlJSAnnotation> &annotations() const { return m_annotations; } |
346 | |
347 | QString filePath() const { return m_filePath; } |
348 | void setFilePath(const QString &file) { m_filePath = file; } |
349 | |
350 | // The name the type uses to refer to itself. Either C++ class name or base name of |
351 | // QML file. isComposite tells us if this is a C++ or a QML name. |
352 | QString internalName() const { return m_internalName; } |
353 | void setInternalName(const QString &internalName) { m_internalName = internalName; } |
354 | QString augmentedInternalName() const |
355 | { |
356 | using namespace Qt::StringLiterals; |
357 | |
358 | switch (m_semantics) { |
359 | case AccessSemantics::Reference: |
360 | return m_internalName + " *"_L1 ; |
361 | case AccessSemantics::Value: |
362 | case AccessSemantics::Sequence: |
363 | break; |
364 | case AccessSemantics::None: |
365 | // If we got a namespace, it might still be a regular type, exposed as namespace. |
366 | // We may need to travel the inheritance chain all the way up to QObject to |
367 | // figure this out, since all other types may be exposed the same way. |
368 | for (QQmlJSScope::ConstPtr base = baseType(); base; base = base->baseType()) { |
369 | switch (base->accessSemantics()) { |
370 | case AccessSemantics::Reference: |
371 | return m_internalName + " *"_L1 ; |
372 | case AccessSemantics::Value: |
373 | case AccessSemantics::Sequence: |
374 | return m_internalName; |
375 | case AccessSemantics::None: |
376 | break; |
377 | } |
378 | } |
379 | break; |
380 | } |
381 | return m_internalName; |
382 | } |
383 | |
384 | // This returns a more user readable version of internalName / baseTypeName |
385 | static QString prettyName(QAnyStringView name); |
386 | |
387 | static bool causesImplicitComponentWrapping(const QQmlJSMetaProperty &property, |
388 | const QQmlJSScope::ConstPtr &assignedType); |
389 | bool isComponentRootElement() const; |
390 | |
391 | void setInterfaceNames(const QStringList& interfaces) { m_interfaceNames = interfaces; } |
392 | QStringList interfaceNames() const { return m_interfaceNames; } |
393 | |
394 | bool hasInterface(const QString &name) const; |
395 | bool hasOwnInterface(const QString &name) const { return m_interfaceNames.contains(str: name); } |
396 | |
397 | void setOwnDeferredNames(const QStringList &names) { m_ownDeferredNames = names; } |
398 | QStringList ownDeferredNames() const { return m_ownDeferredNames; } |
399 | void setOwnImmediateNames(const QStringList &names) { m_ownImmediateNames = names; } |
400 | QStringList ownImmediateNames() const { return m_ownImmediateNames; } |
401 | |
402 | bool isNameDeferred(const QString &name) const; |
403 | |
404 | // If isComposite(), this is the QML/JS name of the prototype. Otherwise it's the |
405 | // relevant base class (in the hierarchy starting from QObject) of a C++ type. |
406 | void setBaseTypeName(const QString &baseTypeName); |
407 | QString baseTypeName() const; |
408 | |
409 | QQmlJSScope::ConstPtr baseType() const { return m_baseType.scope; } |
410 | QTypeRevision baseTypeRevision() const { return m_baseType.revision; } |
411 | |
412 | QString qualifiedName() const { return m_qualifiedName; } |
413 | void setQualifiedName(const QString &qualifiedName) { m_qualifiedName = qualifiedName; }; |
414 | static QString qualifiedNameFrom(const QString &moduleName, const QString &typeName, |
415 | const QTypeRevision &firstRevision, |
416 | const QTypeRevision &lastRevision); |
417 | QString moduleName() const { return m_moduleName; } |
418 | void setModuleName(const QString &moduleName) { m_moduleName = moduleName; } |
419 | |
420 | void clearBaseType() { m_baseType = {}; } |
421 | void setBaseTypeError(const QString &baseTypeError); |
422 | QString baseTypeError() const; |
423 | |
424 | void addOwnProperty(const QQmlJSMetaProperty &prop) { m_properties.insert(key: prop.propertyName(), value: prop); } |
425 | QHash<QString, QQmlJSMetaProperty> ownProperties() const { return m_properties; } |
426 | QQmlJSMetaProperty ownProperty(const QString &name) const { return m_properties.value(key: name); } |
427 | bool hasOwnProperty(const QString &name) const { return m_properties.contains(key: name); } |
428 | |
429 | bool hasProperty(const QString &name) const; |
430 | QQmlJSMetaProperty property(const QString &name) const; |
431 | QHash<QString, QQmlJSMetaProperty> properties() const; |
432 | |
433 | void setPropertyLocallyRequired(const QString &name, bool isRequired); |
434 | bool isPropertyRequired(const QString &name) const; |
435 | bool isPropertyLocallyRequired(const QString &name) const; |
436 | |
437 | void addOwnPropertyBinding( |
438 | const QQmlJSMetaPropertyBinding &binding, |
439 | BindingTargetSpecifier specifier = BindingTargetSpecifier::SimplePropertyTarget) |
440 | { |
441 | Q_ASSERT(binding.sourceLocation().isValid()); |
442 | m_propertyBindings.insert(key: binding.propertyName(), value: binding); |
443 | |
444 | // NB: insert() prepends \a binding to the list of bindings, but we need |
445 | // append, so rotate |
446 | using iter = typename QMultiHash<QString, QQmlJSMetaPropertyBinding>::iterator; |
447 | QPair<iter, iter> r = m_propertyBindings.equal_range(key: binding.propertyName()); |
448 | std::rotate(first: r.first, middle: std::next(x: r.first), last: r.second); |
449 | |
450 | // additionally store bindings in the QmlIR compatible order |
451 | addOwnPropertyBindingInQmlIROrder(binding, specifier); |
452 | Q_ASSERT(m_propertyBindings.size() == m_propertyBindingsArray.size()); |
453 | } |
454 | QMultiHash<QString, QQmlJSMetaPropertyBinding> ownPropertyBindings() const |
455 | { |
456 | return m_propertyBindings; |
457 | } |
458 | QPair<QMultiHash<QString, QQmlJSMetaPropertyBinding>::const_iterator, |
459 | QMultiHash<QString, QQmlJSMetaPropertyBinding>::const_iterator> |
460 | ownPropertyBindings(const QString &name) const |
461 | { |
462 | return m_propertyBindings.equal_range(key: name); |
463 | } |
464 | QList<QQmlJSMetaPropertyBinding> ownPropertyBindingsInQmlIROrder() const; |
465 | bool hasOwnPropertyBindings(const QString &name) const |
466 | { |
467 | return m_propertyBindings.contains(key: name); |
468 | } |
469 | |
470 | bool hasPropertyBindings(const QString &name) const; |
471 | QList<QQmlJSMetaPropertyBinding> propertyBindings(const QString &name) const; |
472 | |
473 | struct AnnotatedScope; // defined later |
474 | static AnnotatedScope ownerOfProperty(const QQmlJSScope::ConstPtr &self, const QString &name); |
475 | |
476 | bool isResolved() const; |
477 | bool isFullyResolved() const; |
478 | |
479 | QString ownDefaultPropertyName() const { return m_defaultPropertyName; } |
480 | void setOwnDefaultPropertyName(const QString &name) { m_defaultPropertyName = name; } |
481 | QString defaultPropertyName() const; |
482 | |
483 | QString ownParentPropertyName() const { return m_parentPropertyName; } |
484 | void setOwnParentPropertyName(const QString &name) { m_parentPropertyName = name; } |
485 | QString parentPropertyName() const; |
486 | |
487 | QString ownAttachedTypeName() const { return m_attachedTypeName; } |
488 | void setOwnAttachedTypeName(const QString &name) { m_attachedTypeName = name; } |
489 | QQmlJSScope::ConstPtr ownAttachedType() const { return m_attachedType; } |
490 | |
491 | QString attachedTypeName() const; |
492 | QQmlJSScope::ConstPtr attachedType() const; |
493 | |
494 | QString extensionTypeName() const { return m_extensionTypeName; } |
495 | void setExtensionTypeName(const QString &name) { m_extensionTypeName = name; } |
496 | enum ExtensionKind { |
497 | NotExtension, |
498 | ExtensionType, |
499 | ExtensionNamespace, |
500 | }; |
501 | struct AnnotatedScope |
502 | { |
503 | QQmlJSScope::ConstPtr scope; |
504 | ExtensionKind extensionSpecifier = NotExtension; |
505 | }; |
506 | AnnotatedScope extensionType() const |
507 | { |
508 | if (!m_extensionType) |
509 | return { .scope: m_extensionType, .extensionSpecifier: NotExtension }; |
510 | return { .scope: m_extensionType, |
511 | .extensionSpecifier: (m_flags & HasExtensionNamespace) ? ExtensionNamespace : ExtensionType }; |
512 | } |
513 | |
514 | QString valueTypeName() const { return m_valueTypeName; } |
515 | void setValueTypeName(const QString &name) { m_valueTypeName = name; } |
516 | QQmlJSScope::ConstPtr valueType() const { return m_valueType; } |
517 | QQmlJSScope::ConstPtr listType() const { return m_listType; } |
518 | QQmlJSScope::Ptr listType() { return m_listType; } |
519 | |
520 | void addOwnRuntimeFunctionIndex(QQmlJSMetaMethod::AbsoluteFunctionIndex index) |
521 | { |
522 | m_runtimeFunctionIndices.emplaceBack(args&: index); |
523 | } |
524 | QQmlJSMetaMethod::AbsoluteFunctionIndex |
525 | ownRuntimeFunctionIndex(QQmlJSMetaMethod::RelativeFunctionIndex index) const |
526 | { |
527 | const int i = static_cast<int>(index); |
528 | Q_ASSERT(i >= 0); |
529 | Q_ASSERT(i < int(m_runtimeFunctionIndices.size())); |
530 | return m_runtimeFunctionIndices[i]; |
531 | } |
532 | |
533 | bool isSingleton() const { return m_flags & Singleton; } |
534 | bool isCreatable() const; |
535 | bool hasCreatableFlag() const { return m_flags & Creatable; } |
536 | /*! |
537 | * \internal |
538 | * |
539 | * Returns true for objects defined from Qml, and false for objects declared from C++. |
540 | */ |
541 | bool isComposite() const { return m_flags & Composite; } |
542 | bool isScript() const { return m_flags & Script; } |
543 | bool hasCustomParser() const { return m_flags & CustomParser; } |
544 | bool isArrayScope() const { return m_flags & Array; } |
545 | bool isInlineComponent() const { return m_flags & InlineComponent; } |
546 | bool isWrappedInImplicitComponent() const { return m_flags & WrappedInImplicitComponent; } |
547 | bool extensionIsNamespace() const { return m_flags & HasExtensionNamespace; } |
548 | void setIsSingleton(bool v) { m_flags.setFlag(flag: Singleton, on: v); } |
549 | void setCreatableFlag(bool v) { m_flags.setFlag(flag: Creatable, on: v); } |
550 | void setIsComposite(bool v) { m_flags.setFlag(flag: Composite, on: v); } |
551 | void setIsScript(bool v) { m_flags.setFlag(flag: Script, on: v); } |
552 | void setHasCustomParser(bool v) |
553 | { |
554 | m_flags.setFlag(flag: CustomParser, on: v);; |
555 | } |
556 | void setIsArrayScope(bool v) { m_flags.setFlag(flag: Array, on: v); } |
557 | void setIsInlineComponent(bool v) { m_flags.setFlag(flag: InlineComponent, on: v); } |
558 | void setIsWrappedInImplicitComponent(bool v) { m_flags.setFlag(flag: WrappedInImplicitComponent, on: v); } |
559 | void setExtensionIsNamespace(bool v) { m_flags.setFlag(flag: HasExtensionNamespace, on: v); } |
560 | |
561 | bool isListProperty() const { return m_flags.testFlag(flag: IsListProperty); } |
562 | void setIsListProperty(bool v) { m_flags.setFlag(flag: IsListProperty, on: v); } |
563 | |
564 | void setAccessSemantics(AccessSemantics semantics) { m_semantics = semantics; } |
565 | AccessSemantics accessSemantics() const { return m_semantics; } |
566 | bool isReferenceType() const { return m_semantics == QQmlJSScope::AccessSemantics::Reference; } |
567 | bool isValueType() const { return m_semantics == QQmlJSScope::AccessSemantics::Value; } |
568 | |
569 | bool isIdInCurrentQmlScopes(const QString &id) const; |
570 | bool isIdInCurrentJSScopes(const QString &id) const; |
571 | bool isIdInjectedFromSignal(const QString &id) const; |
572 | |
573 | std::optional<JavaScriptIdentifier> findJSIdentifier(const QString &id) const; |
574 | std::optional<JavaScriptIdentifier> JSIdentifier(const QString &id) const; |
575 | |
576 | QQmlJS::ConstPtrWrapperIterator childScopesBegin() const { return m_childScopes.constBegin(); } |
577 | QQmlJS::ConstPtrWrapperIterator childScopesEnd() const { return m_childScopes.constEnd(); } |
578 | |
579 | void setInlineComponentName(const QString &inlineComponentName) |
580 | { |
581 | Q_ASSERT(isInlineComponent()); |
582 | m_inlineComponentName = inlineComponentName; |
583 | } |
584 | std::optional<QString> inlineComponentName() const; |
585 | InlineComponentOrDocumentRootName enclosingInlineComponentName() const; |
586 | |
587 | QVector<QQmlJSScope::Ptr> childScopes() |
588 | { |
589 | return m_childScopes; |
590 | } |
591 | |
592 | QVector<QQmlJSScope::ConstPtr> childScopes() const |
593 | { |
594 | QVector<QQmlJSScope::ConstPtr> result; |
595 | result.reserve(asize: m_childScopes.size()); |
596 | for (const auto &child : m_childScopes) |
597 | result.append(t: child); |
598 | return result; |
599 | } |
600 | |
601 | static QTypeRevision resolveTypes( |
602 | const Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes, |
603 | QSet<QString> *usedTypes = nullptr); |
604 | static void resolveNonEnumTypes( |
605 | const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes, |
606 | QSet<QString> *usedTypes = nullptr); |
607 | static void resolveEnums( |
608 | const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes, |
609 | QSet<QString> *usedTypes = nullptr); |
610 | static void resolveList( |
611 | const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &arrayType); |
612 | static void resolveGeneralizedGroup( |
613 | const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &baseType, |
614 | const QQmlJSScope::ContextualTypes &contextualTypes, |
615 | QSet<QString> *usedTypes = nullptr); |
616 | |
617 | void setSourceLocation(const QQmlJS::SourceLocation &sourceLocation) |
618 | { |
619 | m_sourceLocation = sourceLocation; |
620 | } |
621 | |
622 | QQmlJS::SourceLocation sourceLocation() const |
623 | { |
624 | return m_sourceLocation; |
625 | } |
626 | |
627 | static QQmlJSScope::ConstPtr nonCompositeBaseType(const QQmlJSScope::ConstPtr &type) |
628 | { |
629 | for (QQmlJSScope::ConstPtr base = type; base; base = base->baseType()) { |
630 | if (!base->isComposite()) |
631 | return base; |
632 | } |
633 | return {}; |
634 | } |
635 | |
636 | static QTypeRevision nonCompositeBaseRevision(const ImportedScope<QQmlJSScope::ConstPtr> &scope) |
637 | { |
638 | for (auto base = scope; base.scope; |
639 | base = { .scope: base.scope->m_baseType.scope, .revision: base.scope->m_baseType.revision }) { |
640 | if (!base.scope->isComposite()) |
641 | return base.revision; |
642 | } |
643 | return {}; |
644 | } |
645 | |
646 | /*! |
647 | \internal |
648 | Checks whether \a otherScope is the same type as this. |
649 | |
650 | In addition to checking whether the scopes are identical, we also cover duplicate scopes with |
651 | the same internal name. |
652 | */ |
653 | bool isSameType(const QQmlJSScope::ConstPtr &otherScope) const |
654 | { |
655 | return this == otherScope.get() |
656 | || (!this->internalName().isEmpty() |
657 | && this->internalName() == otherScope->internalName()); |
658 | } |
659 | |
660 | bool inherits(const QQmlJSScope::ConstPtr &base) const |
661 | { |
662 | for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().get()) { |
663 | if (scope->isSameType(otherScope: base)) |
664 | return true; |
665 | } |
666 | return false; |
667 | } |
668 | |
669 | /*! |
670 | \internal |
671 | Checks whether \a derived type can be assigned to this type. Returns \c |
672 | true if the type hierarchy of \a derived contains a type equal to this. |
673 | |
674 | \note Assigning \a derived to "QVariant" or "QJSValue" is always possible and |
675 | the function returns \c true in this case. In addition any "QObject" based \a derived type |
676 | can be assigned to a this type if that type is derived from "QQmlComponent". |
677 | */ |
678 | bool canAssign(const QQmlJSScope::ConstPtr &derived) const; |
679 | |
680 | /*! |
681 | \internal |
682 | Checks whether this type or its parents have a custom parser. |
683 | */ |
684 | bool isInCustomParserParent() const; |
685 | |
686 | /*! \internal |
687 | |
688 | Minimal information about a QQmlJSMetaPropertyBinding that allows it to |
689 | be manipulated similarly to QmlIR::Binding. |
690 | */ |
691 | struct QmlIRCompatibilityBindingData |
692 | { |
693 | QmlIRCompatibilityBindingData() = default; |
694 | QmlIRCompatibilityBindingData(const QString &name, quint32 offset) |
695 | : propertyName(name), sourceLocationOffset(offset) |
696 | { |
697 | } |
698 | QString propertyName; // bound property name |
699 | quint32 sourceLocationOffset = 0; // binding's source location offset |
700 | }; |
701 | |
702 | /*! \internal |
703 | * Finds a type in contextualTypes with given name. |
704 | * If a type is found, then its name is inserted into usedTypes (when provided). |
705 | * If contextualTypes has mode INTERNAl, then namespace resolution for enums is |
706 | * done (eg for Qt::Alignment). |
707 | * If contextualTypes has mode QML, then inline component resolution is done |
708 | * ("qmlFileName.IC" is correctly resolved from qmlFileName). |
709 | */ |
710 | static ImportedScope<QQmlJSScope::ConstPtr> findType(const QString &name, |
711 | const ContextualTypes &contextualTypes, |
712 | QSet<QString> *usedTypes = nullptr); |
713 | |
714 | static QQmlSA::Element createQQmlSAElement(const ConstPtr &); |
715 | static QQmlSA::Element createQQmlSAElement(ConstPtr &&); |
716 | static const QQmlJSScope::ConstPtr &scope(const QQmlSA::Element &); |
717 | static constexpr qsizetype sizeofQQmlSAElement() { return QQmlSA::Element::sizeofElement; } |
718 | |
719 | private: |
720 | QQmlJSScope() = default; |
721 | QQmlJSScope(const QQmlJSScope &) = default; |
722 | QQmlJSScope &operator=(const QQmlJSScope &) = default; |
723 | static QTypeRevision resolveType( |
724 | const QQmlJSScope::Ptr &self, const ContextualTypes &contextualTypes, |
725 | QSet<QString> *usedTypes); |
726 | static void updateChildScope( |
727 | const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self, |
728 | const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes); |
729 | |
730 | void addOwnPropertyBindingInQmlIROrder(const QQmlJSMetaPropertyBinding &binding, |
731 | BindingTargetSpecifier specifier); |
732 | |
733 | QHash<QString, JavaScriptIdentifier> m_jsIdentifiers; |
734 | |
735 | QMultiHash<QString, QQmlJSMetaMethod> m_methods; |
736 | QHash<QString, QQmlJSMetaProperty> m_properties; |
737 | QMultiHash<QString, QQmlJSMetaPropertyBinding> m_propertyBindings; |
738 | |
739 | // a special QmlIR compatibility bindings array, ordered the same way as |
740 | // bindings in QmlIR::Object |
741 | QList<QmlIRCompatibilityBindingData> m_propertyBindingsArray; |
742 | |
743 | // same as QmlIR::Object::runtimeFunctionIndices |
744 | QList<QQmlJSMetaMethod::AbsoluteFunctionIndex> m_runtimeFunctionIndices; |
745 | |
746 | QHash<QString, QQmlJSMetaEnum> m_enumerations; |
747 | |
748 | QVector<QQmlJSAnnotation> m_annotations; |
749 | QVector<QQmlJSScope::Ptr> m_childScopes; |
750 | QQmlJSScope::WeakPtr m_parentScope; |
751 | |
752 | QString m_filePath; |
753 | QString m_internalName; |
754 | QString m_baseTypeNameOrError; |
755 | |
756 | // We only need the revision for the base type as inheritance is |
757 | // the only relation between two types where the revisions matter. |
758 | ImportedScope<QQmlJSScope::WeakConstPtr> m_baseType; |
759 | |
760 | ScopeType m_scopeType = ScopeType::QMLScope; |
761 | QStringList m_interfaceNames; |
762 | QStringList m_ownDeferredNames; |
763 | QStringList m_ownImmediateNames; |
764 | |
765 | QString m_defaultPropertyName; |
766 | QString m_parentPropertyName; |
767 | /*! \internal |
768 | * The attached type name. |
769 | * This is an internal name, from a c++ type or a synthetic jsrootgen. |
770 | */ |
771 | QString m_attachedTypeName; |
772 | QStringList m_requiredPropertyNames; |
773 | QQmlJSScope::WeakConstPtr m_attachedType; |
774 | |
775 | /*! \internal |
776 | * The Value type name. |
777 | * This is an internal name, from a c++ type or a synthetic jsrootgen. |
778 | */ |
779 | QString m_valueTypeName; |
780 | QQmlJSScope::WeakConstPtr m_valueType; |
781 | QQmlJSScope::Ptr m_listType; |
782 | |
783 | /*! |
784 | The extension is provided as either a type (QML_{NAMESPACE_}EXTENDED) or as a |
785 | namespace (QML_EXTENDED_NAMESPACE). |
786 | The bool HasExtensionNamespace helps differentiating both cases, as namespaces |
787 | have a more limited lookup capaility. |
788 | This is an internal name, from a c++ type or a synthetic jsrootgen. |
789 | */ |
790 | QString m_extensionTypeName; |
791 | QQmlJSScope::WeakConstPtr m_extensionType; |
792 | |
793 | Flags m_flags = Creatable; // all types are marked as creatable by default. |
794 | AccessSemantics m_semantics = AccessSemantics::Reference; |
795 | |
796 | QQmlJS::SourceLocation m_sourceLocation; |
797 | |
798 | QString m_qualifiedName; |
799 | QString m_moduleName; |
800 | |
801 | std::optional<QString> m_inlineComponentName; |
802 | }; |
803 | Q_DECLARE_TYPEINFO(QQmlJSScope::QmlIRCompatibilityBindingData, Q_RELOCATABLE_TYPE); |
804 | |
805 | template<> |
806 | class Q_QMLCOMPILER_PRIVATE_EXPORT QDeferredFactory<QQmlJSScope> |
807 | { |
808 | public: |
809 | QDeferredFactory() = default; |
810 | |
811 | QDeferredFactory(QQmlJSImporter *importer, const QString &filePath) : |
812 | m_filePath(filePath), m_importer(importer) |
813 | {} |
814 | |
815 | bool isValid() const |
816 | { |
817 | return !m_filePath.isEmpty() && m_importer != nullptr; |
818 | } |
819 | |
820 | QString internalName() const |
821 | { |
822 | return QFileInfo(m_filePath).baseName(); |
823 | } |
824 | |
825 | void setIsSingleton(bool isSingleton) |
826 | { |
827 | m_isSingleton = isSingleton; |
828 | } |
829 | |
830 | void setQualifiedName(const QString &qualifiedName) { m_qualifiedName = qualifiedName; } |
831 | void setModuleName(const QString &moduleName) { m_moduleName = moduleName; } |
832 | |
833 | private: |
834 | friend class QDeferredSharedPointer<QQmlJSScope>; |
835 | friend class QDeferredSharedPointer<const QQmlJSScope>; |
836 | friend class QDeferredWeakPointer<QQmlJSScope>; |
837 | friend class QDeferredWeakPointer<const QQmlJSScope>; |
838 | |
839 | // Should only be called when lazy-loading the type in a deferred pointer. |
840 | void populate(const QSharedPointer<QQmlJSScope> &scope) const; |
841 | |
842 | QString m_filePath; |
843 | QQmlJSImporter *m_importer = nullptr; |
844 | bool m_isSingleton = false; |
845 | QString m_qualifiedName; |
846 | QString m_moduleName; |
847 | }; |
848 | |
849 | using QQmlJSExportedScope = QQmlJSScope::ExportedScope<QQmlJSScope::Ptr>; |
850 | using QQmlJSImportedScope = QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr>; |
851 | |
852 | QT_END_NAMESPACE |
853 | |
854 | #endif // QQMLJSSCOPE_P_H |
855 | |