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
36QT_BEGIN_NAMESPACE
37
38class QQmlJSImporter;
39
40namespace QQmlJS {
41
42class ConstPtrWrapperIterator
43{
44public:
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
90private:
91 QList<Ptr>::const_iterator m_iterator;
92 ConstPtr m_pointer;
93};
94
95} // namespace QQmlJS
96
97class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSScope
98{
99 friend QQmlSA::Element;
100
101public:
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 {
304QT_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();
309QT_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
719private:
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};
803Q_DECLARE_TYPEINFO(QQmlJSScope::QmlIRCompatibilityBindingData, Q_RELOCATABLE_TYPE);
804
805template<>
806class Q_QMLCOMPILER_PRIVATE_EXPORT QDeferredFactory<QQmlJSScope>
807{
808public:
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
833private:
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
849using QQmlJSExportedScope = QQmlJSScope::ExportedScope<QQmlJSScope::Ptr>;
850using QQmlJSImportedScope = QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr>;
851
852QT_END_NAMESPACE
853
854#endif // QQMLJSSCOPE_P_H
855

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