12#include <QtCore/qqueue.h>
13#include <QtCore/qsharedpointer.h>
15#include <private/qduplicatetracker_p.h>
22
23
24
25
26
27
28
29
30
31
33using namespace Qt::StringLiterals;
35QQmlJSScope::QQmlJSScope(
const QString &internalName) : QQmlJSScope{}
37 m_internalName = internalName;
40void QQmlJSScope::reparent(
const QQmlJSScope::Ptr &parentScope,
const QQmlJSScope::Ptr &childScope)
42 if (
const QQmlJSScope::Ptr parent = childScope->m_parentScope.toStrongRef())
43 parent->m_childScopes.removeOne(childScope);
45 parentScope->m_childScopes.append(childScope);
46 childScope->m_parentScope = parentScope;
49QQmlJSScope::Ptr QQmlJSScope::clone(
const ConstPtr &origin)
52 return QQmlJSScope::Ptr();
53 QQmlJSScope::Ptr cloned = create();
55 if (QQmlJSScope::Ptr parent = cloned->parentScope())
56 parent->m_childScopes.append(cloned);
61
62
63
64QHash<QString, QQmlJSScope::JavaScriptIdentifier> QQmlJSScope::ownJSIdentifiers()
const
66 return m_jsIdentifiers;
69void QQmlJSScope::insertJSIdentifier(
const QString &name,
const JavaScriptIdentifier &identifier)
71 Q_ASSERT(m_scopeType != QQmlSA::ScopeType::QMLScope);
72 if (identifier.kind == JavaScriptIdentifier::LexicalScoped
73 || identifier.kind == JavaScriptIdentifier::Injected
74 || QQmlSA::isFunctionScope(m_scopeType)) {
75 m_jsIdentifiers.insert(name, identifier);
77 auto targetScope = parentScope();
78 while (targetScope->m_scopeType != QQmlSA::ScopeType::JSFunctionScope)
79 targetScope = targetScope->parentScope();
80 targetScope->m_jsIdentifiers.insert(name, identifier);
84void QQmlJSScope::setLineNumber(quint32 lineNumber)
86 m_sourceLocation.startLine = lineNumber;
88 m_sourceLocation.startColumn = 1;
91void QQmlJSScope::insertPropertyIdentifier(
const QQmlJSMetaProperty &property)
93 addOwnProperty(property);
94 QQmlJSMetaMethod method(
95 QQmlSignalNames::propertyNameToChangedSignalName(property.propertyName()), u"void"_s);
96 method.setMethodType(QQmlJSMetaMethodType::Signal);
97 method.setIsImplicitQmlPropertyChangeSignal(
true);
101bool QQmlJSScope::hasMethod(
const QString &name)
const
103 return QQmlJSUtils::searchBaseAndExtensionTypes(
104 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
105 if (mode == QQmlJSScope::ExtensionNamespace)
107 return scope->m_methods.contains(name);
112
113
114
115
116
117
118
119
120QHash<QString, QQmlJSMetaMethod> QQmlJSScope::methods()
const
122 QHash<QString, QQmlJSMetaMethod> results;
123 QQmlJSUtils::searchBaseAndExtensionTypes(
124 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
125 if (mode == QQmlJSScope::ExtensionNamespace)
127 for (
auto it = scope->m_methods.constBegin(); it != scope->m_methods.constEnd();
129 if (!results.contains(it.key()))
130 results.insert(it.key(), it.value());
138QList<QQmlJSMetaMethod> QQmlJSScope::methods(
const QString &name)
const
140 QList<QQmlJSMetaMethod> results;
142 QQmlJSUtils::searchBaseAndExtensionTypes(
143 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
144 if (mode == QQmlJSScope::ExtensionNamespace)
146 results.append(scope->ownMethods(name));
152QList<QQmlJSMetaMethod> QQmlJSScope::methods(
const QString &name, QQmlJSMetaMethodType type)
const
154 QList<QQmlJSMetaMethod> results;
156 QQmlJSUtils::searchBaseAndExtensionTypes(
157 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
158 if (mode == QQmlJSScope::ExtensionNamespace)
160 const auto ownMethods = scope->ownMethods(name);
161 for (
const auto &method : ownMethods) {
162 if (method.methodType() == type)
163 results.append(method);
170bool QQmlJSScope::hasEnumeration(
const QString &name)
const
172 return QQmlJSUtils::searchBaseAndExtensionTypes(
173 this, [&](
const QQmlJSScope *scope) {
return scope->m_enumerations.contains(name); });
176bool QQmlJSScope::hasOwnEnumerationKey(
const QString &name)
const
178 for (
const auto &e : m_enumerations) {
179 if (e.keys().contains(name))
185bool QQmlJSScope::hasEnumerationKey(
const QString &name)
const
187 return QQmlJSUtils::searchBaseAndExtensionTypes(
188 this, [&](
const QQmlJSScope *scope) {
return scope->hasOwnEnumerationKey(name); });
191QQmlJSMetaEnum QQmlJSScope::enumeration(
const QString &name)
const
193 QQmlJSMetaEnum result;
195 QQmlJSUtils::searchBaseAndExtensionTypes(
this, [&](
const QQmlJSScope *scope) {
196 const auto it = scope->m_enumerations.find(name);
197 if (it == scope->m_enumerations.end())
206QHash<QString, QQmlJSMetaEnum> QQmlJSScope::enumerations()
const
208 QHash<QString, QQmlJSMetaEnum> results;
210 QQmlJSUtils::searchBaseAndExtensionTypes(
this, [&](
const QQmlJSScope *scope) {
211 for (
auto it = scope->m_enumerations.constBegin(); it != scope->m_enumerations.constEnd();
213 if (!results.contains(it.key()))
214 results.insert(it.key(), it.value());
222QString QQmlJSScope::augmentedInternalName()
const
224 using namespace Qt::StringLiterals;
225 Q_ASSERT(!m_internalName.isEmpty());
227 switch (m_semantics) {
228 case AccessSemantics::Reference:
229 return m_internalName +
" *"_L1;
230 case AccessSemantics::Value:
231 case AccessSemantics::Sequence:
233 case AccessSemantics::None:
237 for (QQmlJSScope::ConstPtr base = baseType(); base; base = base->baseType()) {
238 switch (base->accessSemantics()) {
239 case AccessSemantics::Reference:
240 return m_internalName +
" *"_L1;
241 case AccessSemantics::Value:
242 case AccessSemantics::Sequence:
243 return m_internalName;
244 case AccessSemantics::None:
250 return m_internalName;
253QString QQmlJSScope::prettyName(QAnyStringView name)
255 const auto internal =
"$internal$."_L1;
256 const QString anonymous =
"$anonymous$."_L1;
258 QString pretty = name.toString();
260 if (pretty.startsWith(internal))
261 pretty = pretty.mid(internal.size());
262 else if (pretty.startsWith(anonymous))
263 pretty = pretty.mid(anonymous.size());
265 if (pretty == u"std::nullptr_t")
268 if (pretty == u"void")
269 return u"undefined"_s;
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291QQmlJSScope::IsComponentRoot QQmlJSScope::componentRootStatus()
const {
292 if (m_flags.testAnyFlags(
293 Flags(WrappedInImplicitComponent | FileRootComponent | InlineComponent))) {
294 return IsComponentRoot::Yes;
298 if (m_flags.testFlag(AssignedToUnknownProperty))
299 return IsComponentRoot::Maybe;
301 auto base = nonCompositeBaseType(parentScope());
303 return IsComponentRoot::No;
304 return base->internalName() == u"QQmlComponent"
305 ? IsComponentRoot::Yes
306 : IsComponentRoot::No;
309std::optional<QQmlJSScope::JavaScriptIdentifier>
310QQmlJSScope::jsIdentifier(
const QString &id)
const
312 for (
const auto *scope =
this; scope; scope = scope->parentScope().data()) {
313 if (QQmlSA::isFunctionScope(scope->m_scopeType)
314 || scope->m_scopeType == QQmlSA::ScopeType::JSLexicalScope) {
315 auto it = scope->m_jsIdentifiers.find(id);
316 if (it != scope->m_jsIdentifiers.end())
321 return std::optional<JavaScriptIdentifier>{};
324std::optional<QQmlJSScope::JavaScriptIdentifier> QQmlJSScope::ownJSIdentifier(
const QString &id)
const
326 auto it = m_jsIdentifiers.find(id);
327 if (it != m_jsIdentifiers.end())
330 return std::optional<JavaScriptIdentifier>{};
336 const int separatorIndex = typeName.lastIndexOf(u'.');
338 if (separatorIndex < 1 || separatorIndex >= typeName.size() - 1)
341 const auto parentIt = contextualTypes.types().constFind(typeName.first(separatorIndex).toString());
342 if (parentIt == contextualTypes.types().constEnd())
345 auto inlineComponentParent = *parentIt;
351 QStringView inlineComponentName = typeName.sliced(separatorIndex + 1);
352 QQueue<QQmlJSScope::ConstPtr> candidatesForInlineComponents;
353 candidatesForInlineComponents.enqueue(inlineComponentParent.scope);
354 while (candidatesForInlineComponents.size()) {
355 QQmlJSScope::ConstPtr current = candidatesForInlineComponents.dequeue();
358 if (current->isInlineComponent() && current->inlineComponentName() == inlineComponentName) {
359 return { current, inlineComponentParent.revision };
364 const auto &childScopes = current->childScopes();
365 for (
const auto &child : childScopes) {
366 if (child->scopeType() == QQmlSA::ScopeType::QMLScope)
367 candidatesForInlineComponents.enqueue(child);
370 if (
const auto base = current->baseType())
371 candidatesForInlineComponents.enqueue(base);
377
378
379
380
381
382
383
384QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
385 const QString &name,
const QQmlJS::ContextualTypes &contextualTypes,
386 QSet<QString> *usedTypes)
388 const auto useType = [&]() {
389 if (usedTypes !=
nullptr)
390 usedTypes->insert(name);
393 auto type = contextualTypes.types().constFind(name);
395 if (type != contextualTypes.types().constEnd()) {
400 const auto findListType = [&](
const QString &prefix,
const QString &postfix)
401 -> ImportedScope<ConstPtr> {
402 if (name.startsWith(prefix) && name.endsWith(postfix)) {
403 const qsizetype prefixLength = prefix.length();
404 const QString &elementName
405 = name.mid(prefixLength, name.length() - prefixLength - postfix.length());
406 const ImportedScope<ConstPtr> element
407 = findType(elementName, contextualTypes, usedTypes);
410 return { element.scope->listType(), element.revision };
417 switch (contextualTypes.context()) {
418 case QQmlJS::ContextualTypes::INTERNAL: {
419 if (
const auto listType = findListType(u"QList<"_s, u">"_s);
420 listType.scope && !listType.scope->isReferenceType()) {
424 if (
const auto listType = findListType(u"QQmlListProperty<"_s, u">"_s);
425 listType.scope && listType.scope->isReferenceType()) {
430 const auto colonColon = name.lastIndexOf(QStringLiteral(
"::"));
431 if (colonColon == -1)
434 const QString outerTypeName = name.left(colonColon);
435 const auto outerType = contextualTypes.types().constFind(outerTypeName);
436 if (outerType == contextualTypes.types().constEnd())
439 for (
const auto &innerType : std::as_const(outerType->scope->m_childScopes)) {
440 if (innerType->m_internalName == name) {
442 return { innerType, outerType->revision };
448 case QQmlJS::ContextualTypes::QML: {
450 const auto inlineComponent = qFindInlineComponents(name, contextualTypes);
451 if (inlineComponent.scope) {
453 return inlineComponent;
456 if (
const auto listType = findListType(u"list<"_s, u">"_s); listType.scope)
465QTypeRevision QQmlJSScope::resolveType(
466 const QQmlJSScope::Ptr &self,
const QQmlJS::ContextualTypes &context,
467 QSet<QString> *usedTypes)
469 if (self->accessSemantics() == AccessSemantics::Sequence
470 && self->internalName().startsWith(u"QQmlListProperty<"_s)) {
471 self->setIsListProperty(
true);
474 const QString baseTypeName = self->baseTypeName();
475 const auto baseType = findType(baseTypeName, context, usedTypes);
476 if (!self->m_baseType.scope && !baseTypeName.isEmpty())
477 self->m_baseType = { baseType.scope, baseType.revision };
479 if (!self->m_attachedType && !self->m_attachedTypeName.isEmpty())
480 self->m_attachedType = findType(self->m_attachedTypeName, context, usedTypes).scope;
482 if (!self->m_elementType && !self->m_elementTypeName.isEmpty())
483 self->m_elementType = findType(self->m_elementTypeName, context, usedTypes).scope;
485 if (!self->m_extensionType) {
486 if (self->m_extensionTypeName.isEmpty()) {
487 if (self->accessSemantics() == AccessSemantics::Sequence) {
489 self->setExtensionTypeName(u"Array"_s);
490 self->setExtensionIsJavaScript(
true);
491 self->m_extensionType = context.arrayType();
494 self->m_extensionType = findType(self->m_extensionTypeName, context, usedTypes).scope;
499 for (
auto it = self->m_properties.begin(), end = self->m_properties.end(); it != end; ++it) {
500 const QString typeName = it->typeName();
501 if (it->type() || typeName.isEmpty())
504 if (
const auto type = findType(typeName, context, usedTypes); type.scope) {
505 it->setType(it->isList() ? type.scope->listType() : type.scope);
509 const auto enumeration = self->m_enumerations.find(typeName);
510 if (enumeration != self->m_enumerations.end()) {
511 it->setType(it->isList()
512 ? enumeration->type()->listType()
513 : QQmlJSScope::ConstPtr(enumeration->type()));
517 const auto resolveParameter = [&](QQmlJSMetaParameter ¶meter) {
518 if (
const QString typeName = parameter.typeName();
519 !parameter.type() && !typeName.isEmpty()) {
520 auto type = findType(typeName, context, usedTypes);
521 if (type.scope && parameter.isList()) {
522 type.scope = type.scope->listType();
523 parameter.setIsList(
false);
524 parameter.setIsPointer(
false);
525 parameter.setTypeName(type.scope ? type.scope->internalName() : QString());
526 }
else if (type.scope && type.scope->isReferenceType()) {
527 parameter.setIsPointer(
true);
529 parameter.setType({ type.scope });
533 for (
auto it = self->m_methods.begin(), end = self->m_methods.end(); it != end; ++it) {
534 auto returnValue = it->returnValue();
535 resolveParameter(returnValue);
536 it->setReturnValue(returnValue);
538 auto parameters = it->parameters();
539 for (
int i = 0, length = parameters.size(); i < length; ++i)
540 resolveParameter(parameters[i]);
541 it->setParameters(parameters);
544 for (
auto it = self->m_jsIdentifiers.begin(); it != self->m_jsIdentifiers.end(); ++it) {
546 it->scope = findType(it->typeName.value(), context, usedTypes).scope;
549 return baseType.revision;
552void QQmlJSScope::updateChildScope(
553 const QQmlJSScope::Ptr &childScope,
const QQmlJSScope::Ptr &self,
554 const QQmlJS::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
556 switch (childScope->scopeType()) {
557 case QQmlSA::ScopeType::GroupedPropertyScope:
558 QQmlJSUtils::searchBaseAndExtensionTypes(
559 self.data(), [&](
const QQmlJSScope *type, QQmlJSScope::ExtensionKind mode) {
560 if (mode == QQmlJSScope::ExtensionNamespace)
562 const auto propertyIt = type->m_properties.find(childScope->internalName());
563 if (propertyIt != type->m_properties.end()) {
564 childScope->m_baseType.scope = QQmlJSScope::ConstPtr(propertyIt->type());
565 if (propertyIt->type())
566 childScope->m_semantics = propertyIt->type()->accessSemantics();
567 childScope->setBaseTypeName(propertyIt->typeName());
573 case QQmlSA::ScopeType::AttachedPropertyScope:
574 if (
const auto attachedBase = findType(
575 childScope->internalName(), contextualTypes, usedTypes).scope) {
576 childScope->m_baseType.scope = attachedBase->attachedType();
577 childScope->setBaseTypeName(attachedBase->attachedTypeName());
585template<
typename Resolver,
typename ChildScopeUpdater>
587 Resolver resolve, ChildScopeUpdater update,
const QQmlJSScope::Ptr &self,
590 const QTypeRevision revision = resolve(self, contextualTypes, usedTypes);
592 const auto childScopes = self->childScopes();
593 for (
auto it = childScopes.begin(), end = childScopes.end(); it != end; ++it) {
594 const auto childScope = *it;
595 update(childScope, self, contextualTypes, usedTypes);
596 resolveTypesInternal(resolve, update, childScope, contextualTypes, usedTypes);
601QTypeRevision QQmlJSScope::resolveTypes(
602 const QQmlJSScope::Ptr &self,
const QQmlJS::ContextualTypes &contextualTypes,
603 QSet<QString> *usedTypes)
605 const auto resolveAll = [](
const QQmlJSScope::Ptr &self,
606 const QQmlJS::ContextualTypes &contextualTypes,
607 QSet<QString> *usedTypes) {
608 resolveEnums(self, contextualTypes, usedTypes);
609 resolveList(self, contextualTypes.arrayType());
610 return resolveType(self, contextualTypes, usedTypes);
612 return resolveTypesInternal(resolveAll, updateChildScope, self, contextualTypes, usedTypes);
615void QQmlJSScope::resolveNonEnumTypes(
616 const QQmlJSScope::Ptr &self,
const QQmlJS::ContextualTypes &contextualTypes,
617 QSet<QString> *usedTypes)
619 resolveTypesInternal(resolveType, updateChildScope, self, contextualTypes, usedTypes);
626 if (underlyingType == u"uint"
627 || underlyingType == u"quint8"
628 || underlyingType == u"ushort"
629 || underlyingType == u"ulonglong") {
633 if (underlyingType == u"int"
634 || underlyingType == u"qint8"
635 || underlyingType == u"short"
636 || underlyingType == u"longlong") {
646
647
648
649
650
651
652
653
654
655
656void QQmlJSScope::resolveEnums(
657 const QQmlJSScope::Ptr &self,
const QQmlJS::ContextualTypes &contextualTypes,
658 QSet<QString> *usedTypes)
661 QHash<QString, QQmlJSMetaEnum> toBeAppended;
662 for (
auto it = self->m_enumerations.begin(), end = self->m_enumerations.end(); it != end; ++it) {
665 QQmlJSScope::Ptr enumScope = QQmlJSScope::create();
666 reparent(self, enumScope);
667 enumScope->m_scopeType = QQmlSA::ScopeType::EnumScope;
669 QString typeName = it->typeName();
670 if (typeName.isEmpty())
671 typeName = QStringLiteral(
"int");
672 else if (it->isFlag())
673 typeName = flagStorage(typeName);
674 enumScope->setBaseTypeName(typeName);
675 const auto type = findType(typeName, contextualTypes, usedTypes);
676 enumScope->m_baseType = { type.scope, type.revision };
678 enumScope->m_semantics = AccessSemantics::Value;
679 enumScope->m_internalName = self->internalName() + QStringLiteral(
"::") + it->name();
680 resolveList(enumScope, contextualTypes.arrayType());
681 if (QString alias = it->alias(); !alias.isEmpty()
682 && self->m_enumerations.constFind(alias) == self->m_enumerations.constEnd()) {
683 auto aliasScope = QQmlJSScope::clone(enumScope);
684 aliasScope->m_internalName = self->internalName() + QStringLiteral(
"::") + alias;
685 QQmlJSMetaEnum cpy(*it);
686 cpy.setType(QQmlJSScope::ConstPtr(aliasScope));
687 toBeAppended.insert(alias, cpy);
689 it->setType(QQmlJSScope::ConstPtr(enumScope));
692 self->m_enumerations.insert(toBeAppended);
695void QQmlJSScope::resolveList(
const QQmlJSScope::Ptr &self,
const QQmlJSScope::ConstPtr &arrayType)
697 if (self->listType() || self->accessSemantics() == AccessSemantics::Sequence)
700 Q_ASSERT(!arrayType.isNull());
701 QQmlJSScope::Ptr listType = QQmlJSScope::create();
702 listType->setAccessSemantics(AccessSemantics::Sequence);
703 listType->setElementTypeName(self->internalName());
705 if (self->isComposite()) {
707 listType->setInternalName(u"QQmlListProperty<>"_s);
708 listType->m_elementType = QQmlJSScope::ConstPtr(self);
709 }
else if (self->isReferenceType()) {
710 listType->setInternalName(u"QQmlListProperty<%2>"_s.arg(self->internalName()));
714 listType->setInternalName(u"QList<%2>"_s.arg(self->internalName()));
715 listType->setFilePath(self->filePath());
718 const QQmlJSImportedScope element = {self, QTypeRevision()};
719 const QQmlJSImportedScope array = {arrayType, QTypeRevision()};
720 QQmlJS::ContextualTypes contextualTypes(
721 QQmlJS::ContextualTypes::INTERNAL,
722 { { self->internalName(), element }, },
723 { { self, self->internalName() }, },
725 QQmlJSScope::resolveTypes(listType, contextualTypes);
727 Q_ASSERT(listType->elementType() == self);
728 self->m_listType = listType;
731void QQmlJSScope::resolveGroup(
732 const Ptr &self,
const ConstPtr &baseType,
733 const QQmlJS::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
738 Q_ASSERT(self->isComposite());
740 self->m_baseType.scope = baseType;
741 self->m_semantics = baseType->accessSemantics();
742 resolveNonEnumTypes(self, contextualTypes, usedTypes);
745QQmlJSScope::ConstPtr QQmlJSScope::findCurrentQMLScope(
const QQmlJSScope::ConstPtr &scope)
747 auto qmlScope = scope;
748 while (qmlScope && qmlScope->m_scopeType != QQmlSA::ScopeType::QMLScope)
749 qmlScope = qmlScope->parentScope();
753bool QQmlJSScope::hasProperty(
const QString &name)
const
755 return QQmlJSUtils::searchBaseAndExtensionTypes(
756 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
757 if (mode == QQmlJSScope::ExtensionNamespace)
759 return scope->m_properties.contains(name);
763QQmlJSMetaProperty QQmlJSScope::property(
const QString &name)
const
765 QQmlJSMetaProperty prop;
766 QQmlJSUtils::searchBaseAndExtensionTypes(
767 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
768 if (mode == QQmlJSScope::ExtensionNamespace)
770 const auto it = scope->m_properties.find(name);
771 if (it == scope->m_properties.end())
780
781
782
783
784
785
786QHash<QString, QQmlJSMetaProperty> QQmlJSScope::properties()
const
788 QHash<QString, QQmlJSMetaProperty> results;
789 QQmlJSUtils::searchBaseAndExtensionTypes(
790 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
791 if (mode == QQmlJSScope::ExtensionNamespace)
793 for (
auto it = scope->m_properties.constBegin();
794 it != scope->m_properties.constEnd(); it++) {
795 if (!results.contains(it.key()))
796 results.insert(it.key(), it.value());
803QQmlJSScope::AnnotatedScope QQmlJSScope::ownerOfProperty(
const QQmlJSScope::ConstPtr &self,
806 QQmlJSScope::AnnotatedScope owner;
807 QQmlJSUtils::searchBaseAndExtensionTypes(
808 self, [&](
const QQmlJSScope::ConstPtr &scope, QQmlJSScope::ExtensionKind mode) {
809 if (mode == QQmlJSScope::ExtensionNamespace)
811 if (scope->hasOwnProperty(name)) {
812 owner = { scope, mode };
820void QQmlJSScope::setPropertyLocallyRequired(
const QString &name,
bool isRequired)
823 m_requiredPropertyNames.removeOne(name);
824 else if (!m_requiredPropertyNames.contains(name))
825 m_requiredPropertyNames.append(name);
828bool QQmlJSScope::isPropertyRequired(
const QString &name)
const
830 bool isRequired =
false;
831 QQmlJSUtils::searchBaseAndExtensionTypes(
832 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
833 if (scope->isPropertyLocallyRequired(name)) {
840 if (mode == QQmlJSScope::ExtensionNamespace)
846 return scope->hasOwnProperty(name);
851bool QQmlJSScope::isPropertyLocallyRequired(
const QString &name)
const
853 return m_requiredPropertyNames.contains(name);
856void QQmlJSScope::addOwnPropertyBinding(
const QQmlJSMetaPropertyBinding &binding, BindingTargetSpecifier specifier)
858 Q_ASSERT(binding.sourceLocation().isValid());
859 m_propertyBindings.insert(binding.propertyName(), binding);
863 using iter =
typename QMultiHash<QString, QQmlJSMetaPropertyBinding>::iterator;
864 std::pair<iter, iter> r = m_propertyBindings.equal_range(binding.propertyName());
865 std::rotate(r.first, std::next(r.first), r.second);
868 addOwnPropertyBindingInQmlIROrder(binding, specifier);
869 Q_ASSERT(m_propertyBindings.size() == m_propertyBindingsArray.size());
872void QQmlJSScope::addOwnPropertyBindingInQmlIROrder(
const QQmlJSMetaPropertyBinding &binding,
873 BindingTargetSpecifier specifier)
882 static_assert(QTypeInfo<QQmlJSScope::QmlIRCompatibilityBindingData>::isRelocatable,
883 "We really want T to be relocatable as it improves QList<T> performance");
886 case BindingTargetSpecifier::SimplePropertyTarget: {
887 m_propertyBindingsArray.emplaceFront(binding.propertyName(),
888 binding.sourceLocation().offset);
891 case BindingTargetSpecifier::ListPropertyTarget: {
892 const auto bindingOnTheSameProperty =
893 [&](
const QQmlJSScope::QmlIRCompatibilityBindingData &x) {
894 return x.propertyName == binding.propertyName();
900 auto pos = std::find_if_not(m_propertyBindingsArray.begin(), m_propertyBindingsArray.end(),
901 bindingOnTheSameProperty);
902 Q_ASSERT(pos == m_propertyBindingsArray.begin()
903 || std::prev(pos)->propertyName == binding.propertyName());
904 m_propertyBindingsArray.emplace(pos, binding.propertyName(),
905 binding.sourceLocation().offset);
908 case BindingTargetSpecifier::UnnamedPropertyTarget: {
910 const auto findInsertionPoint = [
this](
const QQmlJSMetaPropertyBinding &x) {
912 for (
auto it = m_propertyBindingsArray.cbegin(); it != m_propertyBindingsArray.cend();
914 if (!(it->sourceLocationOffset <= x.sourceLocation().offset))
922 const auto insertAfter = [
this](qsizetype pos,
const QQmlJSMetaPropertyBinding &x) {
924 m_propertyBindingsArray.emplaceFront(x.propertyName(), x.sourceLocation().offset);
925 }
else if (pos == m_propertyBindingsArray.size()) {
926 m_propertyBindingsArray.emplaceBack(x.propertyName(), x.sourceLocation().offset);
929 m_propertyBindingsArray.emplace(pos + 1, x.propertyName(),
930 x.sourceLocation().offset);
934 const qsizetype insertionPos = findInsertionPoint(binding);
935 insertAfter(insertionPos, binding);
945QList<QQmlJSMetaPropertyBinding> QQmlJSScope::ownPropertyBindingsInQmlIROrder()
const
947 QList<QQmlJSMetaPropertyBinding> qmlIrOrdered;
948 qmlIrOrdered.reserve(m_propertyBindingsArray.size());
950 for (
const auto &data : m_propertyBindingsArray) {
951 const auto [first, last] = m_propertyBindings.equal_range(data.propertyName);
952 Q_ASSERT(first != last);
953 auto binding = std::find_if(first, last, [&](
const QQmlJSMetaPropertyBinding &x) {
954 return x.sourceLocation().offset == data.sourceLocationOffset;
956 Q_ASSERT(binding != last);
957 qmlIrOrdered.append(*binding);
963bool QQmlJSScope::hasPropertyBindings(
const QString &name)
const
965 return QQmlJSUtils::searchBaseAndExtensionTypes(
966 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
967 if (mode != QQmlJSScope::NotExtension) {
968 Q_ASSERT(!scope->hasOwnPropertyBindings(name));
971 return scope->hasOwnPropertyBindings(name);
975QList<QQmlJSMetaPropertyBinding> QQmlJSScope::propertyBindings(
const QString &name)
const
977 QList<QQmlJSMetaPropertyBinding> bindings;
978 QQmlJSUtils::searchBaseAndExtensionTypes(
979 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
980 if (mode != QQmlJSScope::NotExtension) {
981 Q_ASSERT(!scope->hasOwnPropertyBindings(name));
984 const auto range = scope->ownPropertyBindings(name);
985 for (
auto it = range.first; it != range.second; ++it)
986 bindings.append(*it);
992bool QQmlJSScope::hasInterface(
const QString &name)
const
994 return QQmlJSUtils::searchBaseAndExtensionTypes(
995 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
996 if (mode != QQmlJSScope::NotExtension)
998 return scope->m_interfaceNames.contains(name);
1002bool QQmlJSScope::isNameDeferred(
const QString &name)
const
1004 bool isDeferred =
false;
1006 QQmlJSUtils::searchBaseAndExtensionTypes(
this, [&](
const QQmlJSScope *scope) {
1007 const QStringList immediate = scope->ownImmediateNames();
1008 if (!immediate.isEmpty()) {
1009 isDeferred = !immediate.contains(name);
1012 const QStringList deferred = scope->ownDeferredNames();
1013 if (!deferred.isEmpty()) {
1014 isDeferred = deferred.contains(name);
1023void QQmlJSScope::setBaseTypeName(
const QString &baseTypeName)
1025 m_flags.setFlag(HasBaseTypeError,
false);
1026 m_baseTypeNameOrError = baseTypeName;
1029QString QQmlJSScope::baseTypeName()
const
1031 return m_flags.testFlag(HasBaseTypeError) ? QString() : m_baseTypeNameOrError;
1034void QQmlJSScope::setBaseTypeError(
const QString &baseTypeError)
1036 m_flags.setFlag(HasBaseTypeError);
1037 m_baseTypeNameOrError = baseTypeError;
1041
1042
1043
1044
1045
1046QString QQmlJSScope::moduleName()
const
1048 for (
const QQmlJSScope *it =
this; it; it = it->parentScope().get()) {
1049 const QString name = it->ownModuleName();
1050 if (!name.isEmpty())
1056QString QQmlJSScope::baseTypeError()
const
1058 return m_flags.testFlag(HasBaseTypeError) ? m_baseTypeNameOrError : QString();
1061QString QQmlJSScope::attachedTypeName()
const
1064 QQmlJSUtils::searchBaseAndExtensionTypes(
1065 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
1066 if (mode != QQmlJSScope::NotExtension)
1068 if (scope->ownAttachedType().isNull())
1070 name = scope->ownAttachedTypeName();
1077QQmlJSScope::ConstPtr QQmlJSScope::attachedType()
const
1079 QQmlJSScope::ConstPtr ptr;
1080 QQmlJSUtils::searchBaseAndExtensionTypes(
1081 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
1082 if (mode != QQmlJSScope::NotExtension)
1084 if (scope->ownAttachedType().isNull())
1086 ptr = scope->ownAttachedType();
1093QQmlJSScope::AnnotatedScope QQmlJSScope::extensionType()
const
1095 if (!m_extensionType)
1096 return { m_extensionType, NotExtension };
1097 if (m_flags & ExtensionIsJavaScript)
1098 return { m_extensionType, ExtensionJavaScript };
1099 if (m_flags & ExtensionIsNamespace)
1100 return { m_extensionType, ExtensionNamespace };
1101 return { m_extensionType, ExtensionType };
1104void QQmlJSScope::addOwnRuntimeFunctionIndex(QQmlJSMetaMethod::AbsoluteFunctionIndex index)
1106 m_runtimeFunctionIndices.emplaceBack(index);
1109bool QQmlJSScope::isResolved()
const
1111 const bool nameIsEmpty = (m_scopeType == ScopeType::AttachedPropertyScope
1112 || m_scopeType == ScopeType::GroupedPropertyScope)
1113 ? m_internalName.isEmpty()
1114 : m_baseTypeNameOrError.isEmpty();
1117 if (m_baseType.scope.isNull())
1119 if (isComposite() && !nonCompositeBaseType(baseType()))
1124QString QQmlJSScope::defaultPropertyName()
const
1127 QQmlJSUtils::searchBaseAndExtensionTypes(
this, [&](
const QQmlJSScope *scope) {
1128 name = scope->ownDefaultPropertyName();
1129 return !name.isEmpty();
1134QString QQmlJSScope::parentPropertyName()
const
1137 QQmlJSUtils::searchBaseAndExtensionTypes(
this, [&](
const QQmlJSScope *scope) {
1138 name = scope->ownParentPropertyName();
1139 return !name.isEmpty();
1144bool QQmlJSScope::isFullyResolved()
const
1146 bool baseResolved =
true;
1147 QQmlJSUtils::searchBaseAndExtensionTypes(
this, [&](
const QQmlJSScope *scope) {
1148 if (!scope->isResolved()) {
1149 baseResolved =
false;
1155 return baseResolved;
1158QQmlJSScope::Export::Export(
1159 QString package, QString type, QTypeRevision version, QTypeRevision revision)
1160 : m_package(std::move(package))
1161 , m_type(std::move(type))
1162 , m_version(std::move(version))
1163 , m_revision(std::move(revision))
1167bool QQmlJSScope::Export::isValid()
const
1169 return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty();
1172QDeferredFactory<QQmlJSScope>::QDeferredFactory(QQmlJSImporter *importer,
const QString &filePath,
1173 const TypeReader &typeReader)
1174 : m_filePath(filePath),
1175 m_importer(importer),
1176 m_typeReader(typeReader ? typeReader
1177 : [](QQmlJSImporter *importer,
const QString &filePath,
1178 const QSharedPointer<QQmlJSScope> &scopeToPopulate) {
1179 QQmlJSTypeReader defaultTypeReader(importer, filePath);
1180 defaultTypeReader(scopeToPopulate);
1181 return defaultTypeReader.errors();
1186void QDeferredFactory<QQmlJSScope>::populate(
const QSharedPointer<QQmlJSScope> &scope)
const
1188 scope->setOwnModuleName(m_moduleName);
1189 scope->setFilePath(m_filePath);
1191 QList<QQmlJS::DiagnosticMessage> errors = m_typeReader(m_importer, m_filePath, scope);
1192 m_importer->m_globalWarnings.append(errors);
1194 scope->setInternalName(internalName());
1195 QQmlJSScope::resolveEnums(
1196 scope, m_importer->builtinInternalNames().contextualTypes());
1197 QQmlJSScope::resolveList(
1198 scope, m_importer->builtinInternalNames().contextualTypes().arrayType());
1200 if (m_isSingleton && !scope->isSingleton()) {
1201 m_importer->m_globalWarnings.append(
1203 "Type %1 declared as singleton in qmldir but missing pragma Singleton")
1204 .arg(scope->internalName()),
1205 QtCriticalMsg, QQmlJS::SourceLocation() });
1206 scope->setIsSingleton(
true);
1207 }
else if (!m_isSingleton && scope->isSingleton()) {
1208 m_importer->m_globalWarnings.append(
1209 { QStringLiteral(
"Type %1 not declared as singleton in qmldir "
1210 "but using pragma Singleton")
1211 .arg(scope->internalName()),
1212 QtCriticalMsg, QQmlJS::SourceLocation() });
1213 scope->setIsSingleton(
false);
1218
1219
1220
1221
1222
1223
1224
1225
1226bool QQmlJSScope::canAssign(
const QQmlJSScope::ConstPtr &derived)
const
1232 Q_ASSERT(!isComposite() || nonCompositeBaseType(baseType()));
1233 Q_ASSERT(nonCompositeBaseType(derived));
1237 const bool isBaseComponent = [
this]() {
1238 if (internalName() == u"QQmlComponent")
1240 else if (isComposite())
1242 for (
auto cppBase = nonCompositeBaseType(baseType()); cppBase;
1243 cppBase = cppBase->baseType()) {
1244 if (cppBase->internalName() == u"QQmlAbstractDelegateComponent")
1250 QDuplicateTracker<QQmlJSScope::ConstPtr> seen;
1251 for (
auto scope = derived; !scope.isNull() && !seen.hasSeen(scope);
1252 scope = scope->baseType()) {
1253 if (isSameType(scope))
1255 if (isBaseComponent && scope->internalName() == u"QObject"_s)
1259 if (internalName() == u"QVariant"_s || internalName() == u"QJSValue"_s)
1262 return isListProperty() && elementType()->canAssign(derived);
1266
1267
1268
1269bool QQmlJSScope::isInCustomParserParent()
const
1271 for (
const auto *scope =
this; scope; scope = scope->parentScope().get()) {
1272 if (!scope->baseType().isNull() && scope->baseType()->hasCustomParser())
1280
1281
1282
1283
1284std::optional<QString> QQmlJSScope::inlineComponentName()
const
1286 Q_ASSERT(isInlineComponent() == m_inlineComponentName.has_value());
1287 return m_inlineComponentName;
1291
1292
1293
1294
1295QQmlJSScope::InlineComponentOrDocumentRootName QQmlJSScope::enclosingInlineComponentName()
const
1297 for (
auto *type =
this; type; type = type->parentScope().get()) {
1298 if (type->isInlineComponent())
1299 return *type->inlineComponentName();
1301 return RootDocumentNameType();
1304QList<QQmlJSScope::ConstPtr> QQmlJSScope::childScopes()
const
1306 QList<QQmlJSScope::ConstPtr> result;
1307 result.reserve(m_childScopes.size());
1308 for (
const auto &child : m_childScopes)
1309 result.append(child);
1314
1315
1316
1317
1318
1319
1320bool QQmlJSScope::enforcesScopedEnums()
const
1322 for (
const QQmlJSScope *scope =
this; scope; scope = scope->baseType().get()) {
1323 if (scope->hasEnforcesScopedEnumsFlag())
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344bool QQmlJSScope::isCreatable()
const
1346 auto isCreatableNonRecursive = [](
const QQmlJSScope *scope) {
1347 return scope->hasCreatableFlag() && !scope->isSingleton()
1348 && scope->scopeType() == QQmlSA::ScopeType::QMLScope;
1351 for (
const QQmlJSScope* scope =
this; scope; scope = scope->baseType().get()) {
1352 if (!scope->isComposite()) {
1354 return isCreatableNonRecursive(scope);
1357 if (isCreatableNonRecursive(scope))
1365bool QQmlJSScope::isStructured()
const
1367 for (
const QQmlJSScope *scope =
this; scope; scope = scope->baseType().get()) {
1368 if (!scope->isComposite())
1369 return scope->hasStructuredFlag();
1374QQmlSA::Element QQmlJSScope::createQQmlSAElement(
const ConstPtr &ptr)
1376 QQmlSA::Element element;
1377 *
reinterpret_cast<QQmlJSScope::ConstPtr *>(element.m_data) = ptr;
1381QQmlSA::Element QQmlJSScope::createQQmlSAElement(ConstPtr &&ptr)
1383 QQmlSA::Element element;
1384 *
reinterpret_cast<QQmlJSScope::ConstPtr *>(element.m_data) = std::move(ptr);
1388const QQmlJSScope::ConstPtr &QQmlJSScope::scope(
const QQmlSA::Element &element)
1390 return *
reinterpret_cast<
const QQmlJSScope::ConstPtr *>(element.m_data);
1394QQmlJSScope::nonCompositeBaseRevision(
const ImportedScope<QQmlJSScope::ConstPtr> &scope)
1396 for (
auto base = scope; base.scope;
1397 base = { base.scope->m_baseType.scope, base.scope->m_baseType.revision }) {
1398 if (!base.scope->isComposite())
1399 return base.revision;
1405
1406
1407
1408
1409
1410
1411bool QQmlJSScope::isSameType(
const ConstPtr &otherScope)
const
1413 return this == otherScope.get()
1414 || (!
this->internalName().isEmpty()
1415 &&
this->internalName() == otherScope->internalName());
1418bool QQmlJSScope::inherits(
const ConstPtr &base)
const
1420 for (
const QQmlJSScope *scope =
this; scope; scope = scope->baseType().get()) {
1421 if (scope->isSameType(base))
static QQmlJSScope::ImportedScope< QQmlJSScope::ConstPtr > qFindInlineComponents(QStringView typeName, const QQmlJS::ContextualTypes &contextualTypes)
static QString flagStorage(const QString &underlyingType)
static QTypeRevision resolveTypesInternal(Resolver resolve, ChildScopeUpdater update, const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes, QSet< QString > *usedTypes)