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;
50
51
52
53
54
55
56
57
58
59
60
61const QQmlJSScope::Ptr &QQmlJSScope::resetForReparse(
const Ptr &scope)
63 auto *factory = scope.factory();
65 const QString moduleName = scope->moduleName();
66 const bool isSingleton = scope->isSingleton();
67 const QString filePath = scope->filePath();
68 *scope = QQmlJSScope{ scope->internalName() };
69 scope->setOwnModuleName(moduleName);
70 scope->setIsSingleton(isSingleton);
71 scope->setFilePath(filePath);
76 const QString moduleName = factory->moduleName();
77 const QString internalName = factory->internalName();
78 const bool isSingleton = factory->isSingleton();
79 const QString filePath = factory->filePath();
80 *scope.factory() = QQmlJSScope::ConstPtr::Factory{ };
81 scope->setFilePath(filePath);
82 scope->setOwnModuleName(moduleName);
83 scope->setInternalName(internalName);
84 scope->setIsSingleton(isSingleton);
89
90
91
92QHash<QString, QQmlJSScope::JavaScriptIdentifier> QQmlJSScope::ownJSIdentifiers()
const
94 return m_jsIdentifiers;
97void QQmlJSScope::insertJSIdentifier(
const QString &name,
const JavaScriptIdentifier &identifier)
99 Q_ASSERT(m_scopeType != QQmlSA::ScopeType::QMLScope);
100 if (identifier.kind == JavaScriptIdentifier::LexicalScoped
101 || identifier.kind == JavaScriptIdentifier::Injected
102 || QQmlSA::isFunctionScope(m_scopeType)) {
103 m_jsIdentifiers.insert(name, identifier);
105 auto targetScope = parentScope();
106 while (targetScope->m_scopeType != QQmlSA::ScopeType::JSFunctionScope)
107 targetScope = targetScope->parentScope();
108 targetScope->m_jsIdentifiers.insert(name, identifier);
112void QQmlJSScope::setLineNumber(quint32 lineNumber)
114 m_sourceLocation.startLine = lineNumber;
116 m_sourceLocation.startColumn = 1;
119void QQmlJSScope::setLineNumberInResolvedFile(quint32 lineNumber)
121 m_lineNumberInResolvedFile = lineNumber;
124bool QQmlJSScope::hasMethod(
const QString &name)
const
126 return QQmlJSUtils::searchBaseAndExtensionTypes(
127 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
128 if (mode == QQmlJSScope::ExtensionNamespace)
130 return scope->m_methods.contains(name);
135
136
137
138
139
140
141
142
143QHash<QString, QQmlJSMetaMethod> QQmlJSScope::methods()
const
145 QHash<QString, QQmlJSMetaMethod> results;
146 QQmlJSUtils::searchBaseAndExtensionTypes(
147 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
148 if (mode == QQmlJSScope::ExtensionNamespace)
150 for (
auto it = scope->m_methods.constBegin(); it != scope->m_methods.constEnd();
152 if (!results.contains(it.key()))
153 results.insert(it.key(), it.value());
161QList<QQmlJSMetaMethod> QQmlJSScope::methods(
const QString &name)
const
163 QList<QQmlJSMetaMethod> results;
165 QQmlJSUtils::searchBaseAndExtensionTypes(
166 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
167 if (mode == QQmlJSScope::ExtensionNamespace)
169 results.append(scope->ownMethods(name));
175QList<QQmlJSMetaMethod> QQmlJSScope::methods(
const QString &name, QQmlJSMetaMethodType type)
const
177 QList<QQmlJSMetaMethod> results;
179 QQmlJSUtils::searchBaseAndExtensionTypes(
180 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
181 if (mode == QQmlJSScope::ExtensionNamespace)
183 const auto ownMethods = scope->ownMethods(name);
184 for (
const auto &method : ownMethods) {
185 if (method.methodType() == type)
186 results.append(method);
193bool QQmlJSScope::hasEnumeration(
const QString &name)
const
195 return QQmlJSUtils::searchBaseAndExtensionTypes(
196 this, [&](
const QQmlJSScope *scope) {
return scope->m_enumerations.contains(name); });
199bool QQmlJSScope::hasOwnEnumerationKey(
const QString &name)
const
201 for (
const auto &e : m_enumerations) {
202 if (e.keys().contains(name))
208bool QQmlJSScope::hasEnumerationKey(
const QString &name)
const
210 return QQmlJSUtils::searchBaseAndExtensionTypes(
211 this, [&](
const QQmlJSScope *scope) {
return scope->hasOwnEnumerationKey(name); });
214QQmlJSMetaEnum QQmlJSScope::enumeration(
const QString &name)
const
216 QQmlJSMetaEnum result;
218 QQmlJSUtils::searchBaseAndExtensionTypes(
this, [&](
const QQmlJSScope *scope) {
219 const auto it = scope->m_enumerations.find(name);
220 if (it == scope->m_enumerations.end())
229QHash<QString, QQmlJSMetaEnum> QQmlJSScope::enumerations()
const
231 QHash<QString, QQmlJSMetaEnum> results;
233 QQmlJSUtils::searchBaseAndExtensionTypes(
this, [&](
const QQmlJSScope *scope) {
234 for (
auto it = scope->m_enumerations.constBegin(); it != scope->m_enumerations.constEnd();
236 if (!results.contains(it.key()))
237 results.insert(it.key(), it.value());
245QString QQmlJSScope::augmentedInternalName()
const
247 using namespace Qt::StringLiterals;
248 Q_ASSERT(!m_internalName.isEmpty());
250 switch (m_semantics) {
251 case AccessSemantics::Reference:
252 return m_internalName +
" *"_L1;
253 case AccessSemantics::Value:
254 case AccessSemantics::Sequence:
256 case AccessSemantics::None:
260 for (QQmlJSScope::ConstPtr base = baseType(); base; base = base->baseType()) {
261 switch (base->accessSemantics()) {
262 case AccessSemantics::Reference:
263 return m_internalName +
" *"_L1;
264 case AccessSemantics::Value:
265 case AccessSemantics::Sequence:
266 return m_internalName;
267 case AccessSemantics::None:
273 return m_internalName;
276QString QQmlJSScope::prettyName(QAnyStringView name)
278 const auto internal =
"$internal$."_L1;
279 const QString anonymous =
"$anonymous$."_L1;
281 QString pretty = name.toString();
283 if (pretty.startsWith(internal))
284 pretty = pretty.mid(internal.size());
285 else if (pretty.startsWith(anonymous))
286 pretty = pretty.mid(anonymous.size());
288 if (pretty == u"std::nullptr_t")
291 if (pretty == u"void")
292 return u"undefined"_s;
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314QQmlJSScope::IsComponentRoot QQmlJSScope::componentRootStatus()
const {
315 if (m_flags.testAnyFlags(
316 Flags(WrappedInImplicitComponent | FileRootComponent | InlineComponent))) {
317 return IsComponentRoot::Yes;
321 if (m_flags.testFlag(AssignedToUnknownProperty))
322 return IsComponentRoot::Maybe;
324 auto base = nonCompositeBaseType(parentScope());
326 return IsComponentRoot::No;
327 return base->internalName() == u"QQmlComponent"
328 ? IsComponentRoot::Yes
329 : IsComponentRoot::No;
332std::optional<QQmlJSScope::JavaScriptIdentifier>
333QQmlJSScope::jsIdentifier(
const QString &id)
const
335 for (
const auto *scope =
this; scope; scope = scope->parentScope().data()) {
336 if (QQmlSA::isFunctionScope(scope->m_scopeType)
337 || scope->m_scopeType == QQmlSA::ScopeType::JSLexicalScope) {
338 auto it = scope->m_jsIdentifiers.find(id);
339 if (it != scope->m_jsIdentifiers.end())
344 return std::optional<JavaScriptIdentifier>{};
347std::optional<QQmlJSScope::JavaScriptIdentifier> QQmlJSScope::ownJSIdentifier(
const QString &id)
const
349 auto it = m_jsIdentifiers.find(id);
350 if (it != m_jsIdentifiers.end())
353 return std::optional<JavaScriptIdentifier>{};
359 const int separatorIndex = typeName.lastIndexOf(u'.');
361 if (separatorIndex < 1 || separatorIndex >= typeName.size() - 1)
364 const auto parentIt = contextualTypes.types().constFind(typeName.first(separatorIndex).toString());
365 if (parentIt == contextualTypes.types().constEnd())
368 auto inlineComponentParent = *parentIt;
374 QStringView inlineComponentName = typeName.sliced(separatorIndex + 1);
375 QQueue<QQmlJSScope::ConstPtr> candidatesForInlineComponents;
376 candidatesForInlineComponents.enqueue(inlineComponentParent.scope);
377 while (candidatesForInlineComponents.size()) {
378 QQmlJSScope::ConstPtr current = candidatesForInlineComponents.dequeue();
381 if (current->isInlineComponent() && current->inlineComponentName() == inlineComponentName) {
382 return { current, inlineComponentParent.revision };
387 const auto &childScopes = current->childScopes();
388 for (
const auto &child : childScopes) {
389 if (child->scopeType() == QQmlSA::ScopeType::QMLScope)
390 candidatesForInlineComponents.enqueue(child);
393 if (
const auto base = current->baseType())
394 candidatesForInlineComponents.enqueue(base);
400
401
402
403
404
405
406
407QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
408 const QString &name,
const QQmlJS::ContextualTypes &contextualTypes,
409 QSet<QString> *usedTypes)
411 const auto useType = [&]() {
412 if (usedTypes !=
nullptr)
413 usedTypes->insert(name);
416 auto type = contextualTypes.types().constFind(name);
417 const QString currentSelector = contextualTypes.currentFileSelector();
419 if (type != contextualTypes.types().constEnd()) {
421 if (currentSelector.isEmpty()) {
426 const QString typeSelector = QQmlJSUtils::fileSelectorFor(type->scope);
427 if (typeSelector.isEmpty() || typeSelector == currentSelector) {
431 if (
auto matching = contextualTypes.fileSelectedTypeFor(name, currentSelector)) {
435 }
else if (!currentSelector.isEmpty()) {
437 if (
auto matching = contextualTypes.fileSelectedTypeFor(name, currentSelector)) {
443 const auto findListType = [&](
const QString &prefix,
const QString &postfix)
444 -> ImportedScope<ConstPtr> {
445 if (name.startsWith(prefix) && name.endsWith(postfix)) {
446 const qsizetype prefixLength = prefix.length();
447 const QString &elementName
448 = name.mid(prefixLength, name.length() - prefixLength - postfix.length());
449 const ImportedScope<ConstPtr> element
450 = findType(elementName, contextualTypes, usedTypes);
453 return { element.scope->listType(), element.revision };
460 switch (contextualTypes.context()) {
461 case QQmlJS::ContextualTypes::INTERNAL: {
462 if (
const auto listType = findListType(u"QList<"_s, u">"_s);
463 listType.scope && !listType.scope->isReferenceType()) {
467 if (
const auto listType = findListType(u"QQmlListProperty<"_s, u">"_s);
468 listType.scope && listType.scope->isReferenceType()) {
473 const auto colonColon = name.lastIndexOf(QStringLiteral(
"::"));
474 if (colonColon == -1)
477 const QString outerTypeName = name.left(colonColon);
478 const auto outerType = contextualTypes.types().constFind(outerTypeName);
479 if (outerType == contextualTypes.types().constEnd())
482 for (
const auto &innerType : std::as_const(outerType->scope->m_childScopes)) {
483 if (innerType->m_internalName == name) {
485 return { innerType, outerType->revision };
491 case QQmlJS::ContextualTypes::QML: {
493 const auto inlineComponent = qFindInlineComponents(name, contextualTypes);
494 if (inlineComponent.scope) {
496 return inlineComponent;
499 if (
const auto listType = findListType(u"list<"_s, u">"_s); listType.scope)
508QTypeRevision QQmlJSScope::resolveType(
509 const QQmlJSScope::Ptr &self,
const QQmlJS::ContextualTypes &context,
510 QSet<QString> *usedTypes)
512 if (self->accessSemantics() == AccessSemantics::Sequence
513 && self->internalName().startsWith(u"QQmlListProperty<"_s)) {
514 self->setIsListProperty(
true);
517 const QString baseTypeName = self->baseTypeName();
518 const auto baseType = findType(baseTypeName, context, usedTypes);
519 if (!self->m_baseType.scope && !baseTypeName.isEmpty())
520 self->m_baseType = { baseType.scope, baseType.revision };
522 if (!self->m_attachedType && !self->m_attachedTypeName.isEmpty())
523 self->m_attachedType = findType(self->m_attachedTypeName, context, usedTypes).scope;
525 if (!self->m_elementType && !self->m_elementTypeName.isEmpty())
526 self->m_elementType = findType(self->m_elementTypeName, context, usedTypes).scope;
528 if (!self->m_extensionType) {
529 if (self->m_extensionTypeName.isEmpty()) {
530 if (self->accessSemantics() == AccessSemantics::Sequence) {
532 self->setExtensionTypeName(u"Array"_s);
533 self->setExtensionIsJavaScript(
true);
534 self->m_extensionType = context.arrayType();
537 self->m_extensionType = findType(self->m_extensionTypeName, context, usedTypes).scope;
542 for (
auto it = self->m_properties.begin(), end = self->m_properties.end(); it != end; ++it) {
543 const QString typeName = it->typeName();
544 if (it->type() || typeName.isEmpty())
547 if (
const auto type = findType(typeName, context, usedTypes); type.scope) {
548 it->setType(it->isList() ? type.scope->listType() : type.scope);
552 const auto enumeration = self->m_enumerations.find(typeName);
553 if (enumeration != self->m_enumerations.end()) {
554 it->setType(it->isList()
555 ? enumeration->type()->listType()
556 : QQmlJSScope::ConstPtr(enumeration->type()));
560 const auto resolveParameter = [&](QQmlJSMetaParameter ¶meter) {
561 if (
const QString typeName = parameter.typeName();
562 !parameter.type() && !typeName.isEmpty()) {
563 auto type = findType(typeName, context, usedTypes);
564 if (type.scope && parameter.isList()) {
565 type.scope = type.scope->listType();
566 parameter.setIsList(
false);
567 parameter.setIsPointer(
false);
568 parameter.setTypeName(type.scope ? type.scope->internalName() : QString());
569 }
else if (type.scope && type.scope->isReferenceType()) {
570 parameter.setIsPointer(
true);
572 parameter.setType({ type.scope });
576 for (
auto it = self->m_methods.begin(), end = self->m_methods.end(); it != end; ++it) {
577 auto returnValue = it->returnValue();
578 resolveParameter(returnValue);
579 it->setReturnValue(returnValue);
581 auto parameters = it->parameters();
582 for (
int i = 0, length = parameters.size(); i < length; ++i)
583 resolveParameter(parameters[i]);
584 it->setParameters(parameters);
587 for (
auto it = self->m_jsIdentifiers.begin(); it != self->m_jsIdentifiers.end(); ++it) {
589 it->scope = findType(it->typeName.value(), context, usedTypes).scope;
592 return baseType.revision;
595void QQmlJSScope::updateChildScope(
596 const QQmlJSScope::Ptr &childScope,
const QQmlJSScope::Ptr &self,
597 const QQmlJS::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
599 switch (childScope->scopeType()) {
600 case QQmlSA::ScopeType::GroupedPropertyScope:
601 QQmlJSUtils::searchBaseAndExtensionTypes(
602 self.data(), [&](
const QQmlJSScope *type, QQmlJSScope::ExtensionKind mode) {
603 if (mode == QQmlJSScope::ExtensionNamespace)
605 const auto propertyIt = type->m_properties.find(childScope->internalName());
606 if (propertyIt != type->m_properties.end()) {
607 childScope->m_baseType.scope = QQmlJSScope::ConstPtr(propertyIt->type());
608 if (propertyIt->type())
609 childScope->m_semantics = propertyIt->type()->accessSemantics();
610 childScope->setBaseTypeName(propertyIt->typeName());
616 case QQmlSA::ScopeType::AttachedPropertyScope:
617 if (
const auto attachedBase = findType(
618 childScope->internalName(), contextualTypes, usedTypes).scope) {
619 childScope->m_baseType.scope = attachedBase->attachedType();
620 childScope->setBaseTypeName(attachedBase->attachedTypeName());
628template<
typename Resolver,
typename ChildScopeUpdater>
630 Resolver resolve, ChildScopeUpdater update,
const QQmlJSScope::Ptr &self,
633 const QTypeRevision revision = resolve(self, contextualTypes, usedTypes);
635 const auto childScopes = self->childScopes();
636 for (
auto it = childScopes.begin(), end = childScopes.end(); it != end; ++it) {
637 const auto childScope = *it;
638 update(childScope, self, contextualTypes, usedTypes);
639 resolveTypesInternal(resolve, update, childScope, contextualTypes, usedTypes);
644QTypeRevision QQmlJSScope::resolveTypes(
645 const QQmlJSScope::Ptr &self,
const QQmlJS::ContextualTypes &contextualTypes,
646 QSet<QString> *usedTypes)
648 const auto resolveAll = [](
const QQmlJSScope::Ptr &self,
649 const QQmlJS::ContextualTypes &contextualTypes,
650 QSet<QString> *usedTypes) {
651 resolveEnums(self, contextualTypes, usedTypes);
652 resolveList(self, contextualTypes.arrayType());
653 return resolveType(self, contextualTypes, usedTypes);
655 return resolveTypesInternal(resolveAll, updateChildScope, self, contextualTypes, usedTypes);
658void QQmlJSScope::resolveNonEnumTypes(
659 const QQmlJSScope::Ptr &self,
const QQmlJS::ContextualTypes &contextualTypes,
660 QSet<QString> *usedTypes)
662 resolveTypesInternal(resolveType, updateChildScope, self, contextualTypes, usedTypes);
669 if (underlyingType == u"uint"
670 || underlyingType == u"quint8"
671 || underlyingType == u"ushort"
672 || underlyingType == u"ulonglong") {
676 if (underlyingType == u"int"
677 || underlyingType == u"qint8"
678 || underlyingType == u"short"
679 || underlyingType == u"longlong") {
689
690
691
692
693
694
695
696
697
698
699void QQmlJSScope::resolveEnums(
700 const QQmlJSScope::Ptr &self,
const QQmlJS::ContextualTypes &contextualTypes,
701 QSet<QString> *usedTypes)
704 QHash<QString, QQmlJSMetaEnum> toBeAppended;
705 for (
auto it = self->m_enumerations.begin(), end = self->m_enumerations.end(); it != end; ++it) {
708 QQmlJSScope::Ptr enumScope = QQmlJSScope::create();
709 reparent(self, enumScope);
710 enumScope->m_scopeType = QQmlSA::ScopeType::EnumScope;
712 QString typeName = it->typeName();
713 if (typeName.isEmpty())
714 typeName = QStringLiteral(
"int");
715 else if (it->isFlag())
716 typeName = flagStorage(typeName);
717 enumScope->setBaseTypeName(typeName);
718 const auto type = findType(typeName, contextualTypes, usedTypes);
719 enumScope->m_baseType = { type.scope, type.revision };
721 enumScope->m_semantics = AccessSemantics::Value;
722 enumScope->m_internalName = self->internalName() + QStringLiteral(
"::") + it->name();
723 resolveList(enumScope, contextualTypes.arrayType());
724 if (QString alias = it->alias(); !alias.isEmpty()
725 && self->m_enumerations.constFind(alias) == self->m_enumerations.constEnd()) {
726 auto aliasScope = QQmlJSScope::create();
727 *aliasScope = *enumScope;
728 reparent(self, aliasScope);
729 aliasScope->m_internalName = self->internalName() + QStringLiteral(
"::") + alias;
730 QQmlJSMetaEnum cpy(*it);
731 cpy.setType(QQmlJSScope::ConstPtr(aliasScope));
732 toBeAppended.insert(alias, cpy);
734 it->setType(QQmlJSScope::ConstPtr(enumScope));
737 self->m_enumerations.insert(toBeAppended);
740void QQmlJSScope::resolveList(
const QQmlJSScope::Ptr &self,
const QQmlJSScope::ConstPtr &arrayType)
742 if (self->listType() || self->accessSemantics() == AccessSemantics::Sequence)
745 Q_ASSERT(!arrayType.isNull());
746 QQmlJSScope::Ptr listType = QQmlJSScope::create();
747 listType->setAccessSemantics(AccessSemantics::Sequence);
748 listType->setElementTypeName(self->internalName());
750 if (self->isComposite()) {
752 listType->setInternalName(u"QQmlListProperty<>"_s);
753 listType->m_elementType = QQmlJSScope::ConstPtr(self);
754 }
else if (self->isReferenceType()) {
755 listType->setInternalName(u"QQmlListProperty<%2>"_s.arg(self->internalName()));
759 listType->setInternalName(u"QList<%2>"_s.arg(self->internalName()));
760 listType->setFilePath(self->filePath());
763 const QQmlJS::ContextualType element = { self, QTypeRevision(),
764 quint8(QQmlJS::PrecedenceValues::Default) };
765 const QQmlJSImportedScope array = {arrayType, QTypeRevision()};
766 QQmlJS::ContextualTypes contextualTypes(
767 QQmlJS::ContextualTypes::INTERNAL,
768 { { self->internalName(), element }, },
769 { { self, self->internalName() }, },
771 QQmlJSScope::resolveTypes(listType, contextualTypes);
773 Q_ASSERT(listType->elementType() == self);
774 self->m_listType = listType;
777void QQmlJSScope::resolveGroup(
778 const Ptr &self,
const ConstPtr &baseType,
779 const QQmlJS::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
784 Q_ASSERT(self->isComposite());
786 self->m_baseType.scope = baseType;
787 self->m_semantics = baseType->accessSemantics();
788 resolveNonEnumTypes(self, contextualTypes, usedTypes);
791QQmlJSScope::ConstPtr QQmlJSScope::findCurrentQMLScope(
const QQmlJSScope::ConstPtr &scope)
793 auto qmlScope = scope;
794 while (qmlScope && qmlScope->m_scopeType != QQmlSA::ScopeType::QMLScope)
795 qmlScope = qmlScope->parentScope();
799bool QQmlJSScope::hasProperty(
const QString &name)
const
801 return QQmlJSUtils::searchBaseAndExtensionTypes(
802 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
803 if (mode == QQmlJSScope::ExtensionNamespace)
805 return scope->m_properties.contains(name);
809QQmlJSMetaProperty QQmlJSScope::property(
const QString &name)
const
811 QQmlJSMetaProperty prop;
812 QQmlJSUtils::searchBaseAndExtensionTypes(
813 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
814 if (mode == QQmlJSScope::ExtensionNamespace)
816 const auto it = scope->m_properties.find(name);
817 if (it == scope->m_properties.end())
826
827
828
829
830
831
832QHash<QString, QQmlJSMetaProperty> QQmlJSScope::properties()
const
834 QHash<QString, QQmlJSMetaProperty> results;
835 QQmlJSUtils::searchBaseAndExtensionTypes(
836 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
837 if (mode == QQmlJSScope::ExtensionNamespace)
839 for (
auto it = scope->m_properties.constBegin();
840 it != scope->m_properties.constEnd(); it++) {
841 if (!results.contains(it.key()))
842 results.insert(it.key(), it.value());
849template <
typename Predicate>
852 QQmlJSScope::AnnotatedScope owner;
854 self, [&](
const QQmlJSScope::ConstPtr &scope, QQmlJSScope::ExtensionKind mode) {
855 if (mode == QQmlJSScope::ExtensionNamespace)
858 owner = { scope, mode };
866QQmlJSScope::AnnotatedScope QQmlJSScope::ownerOfProperty(
const QQmlJSScope::ConstPtr &self,
869 return searchOwner(self, [&name](
const QQmlJSScope::ConstPtr &scope) {
870 return scope->hasOwnProperty(name);
874QQmlJSScope::AnnotatedScope QQmlJSScope::ownerOfMethod(
const QQmlJSScope::ConstPtr &self,
877 return searchOwner(self, [&name](
const QQmlJSScope::ConstPtr &scope) {
878 return scope->hasOwnMethod(name);
882QQmlJSScope::AnnotatedScope QQmlJSScope::ownerOfEnum(
const QQmlJSScope::ConstPtr &self,
885 return searchOwner(self, [&name](
const QQmlJSScope::ConstPtr &scope) {
886 return scope->hasOwnEnumeration(name);
890void QQmlJSScope::setPropertyLocallyRequired(
const QString &name,
bool isRequired)
893 m_requiredPropertyNames.removeOne(name);
894 else if (!m_requiredPropertyNames.contains(name))
895 m_requiredPropertyNames.append(name);
898bool QQmlJSScope::isPropertyRequired(
const QString &name)
const
900 bool isRequired =
false;
901 QQmlJSUtils::searchBaseAndExtensionTypes(
902 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
903 if (scope->isPropertyLocallyRequired(name)) {
910 if (mode == QQmlJSScope::ExtensionNamespace)
916 return scope->hasOwnProperty(name);
921bool QQmlJSScope::isPropertyLocallyRequired(
const QString &name)
const
923 return m_requiredPropertyNames.contains(name);
926void QQmlJSScope::addOwnPropertyBinding(
const QQmlJSMetaPropertyBinding &binding, BindingTargetSpecifier specifier)
928 Q_ASSERT(binding.sourceLocation().isValid());
929 m_propertyBindings.insert(binding.propertyName(), binding);
933 using iter =
typename QMultiHash<QString, QQmlJSMetaPropertyBinding>::iterator;
934 std::pair<iter, iter> r = m_propertyBindings.equal_range(binding.propertyName());
935 std::rotate(r.first, std::next(r.first), r.second);
938 addOwnPropertyBindingInQmlIROrder(binding, specifier);
939 Q_ASSERT(m_propertyBindings.size() == m_propertyBindingsArray.size());
942void QQmlJSScope::addOwnPropertyBindingInQmlIROrder(
const QQmlJSMetaPropertyBinding &binding,
943 BindingTargetSpecifier specifier)
952 static_assert(QTypeInfo<QQmlJSScope::QmlIRCompatibilityBindingData>::isRelocatable,
953 "We really want T to be relocatable as it improves QList<T> performance");
956 case BindingTargetSpecifier::SimplePropertyTarget: {
957 m_propertyBindingsArray.emplaceFront(binding.propertyName(),
958 binding.sourceLocation().offset);
961 case BindingTargetSpecifier::ListPropertyTarget: {
962 const auto bindingOnTheSameProperty =
963 [&](
const QQmlJSScope::QmlIRCompatibilityBindingData &x) {
964 return x.propertyName == binding.propertyName();
970 auto pos = std::find_if_not(m_propertyBindingsArray.begin(), m_propertyBindingsArray.end(),
971 bindingOnTheSameProperty);
972 Q_ASSERT(pos == m_propertyBindingsArray.begin()
973 || std::prev(pos)->propertyName == binding.propertyName());
974 m_propertyBindingsArray.emplace(pos, binding.propertyName(),
975 binding.sourceLocation().offset);
978 case BindingTargetSpecifier::UnnamedPropertyTarget: {
981 m_propertyBindingsArray.emplaceBack(
982 binding.propertyName(), binding.sourceLocation().offset);
992QList<QQmlJSMetaPropertyBinding> QQmlJSScope::ownPropertyBindingsInQmlIROrder()
const
994 QList<QQmlJSMetaPropertyBinding> qmlIrOrdered;
995 qmlIrOrdered.reserve(m_propertyBindingsArray.size());
997 for (
const auto &data : m_propertyBindingsArray) {
998 const auto [first, last] = m_propertyBindings.equal_range(data.propertyName);
999 Q_ASSERT(first != last);
1000 auto binding = std::find_if(first, last, [&](
const QQmlJSMetaPropertyBinding &x) {
1001 return x.sourceLocation().offset == data.sourceLocationOffset;
1003 Q_ASSERT(binding != last);
1004 qmlIrOrdered.append(*binding);
1007 return qmlIrOrdered;
1010bool QQmlJSScope::hasPropertyBindings(
const QString &name)
const
1012 return QQmlJSUtils::searchBaseAndExtensionTypes(
1013 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
1014 if (mode != QQmlJSScope::NotExtension) {
1015 Q_ASSERT(!scope->hasOwnPropertyBindings(name));
1018 return scope->hasOwnPropertyBindings(name);
1022QList<QQmlJSMetaPropertyBinding> QQmlJSScope::propertyBindings(
const QString &name)
const
1024 QList<QQmlJSMetaPropertyBinding> bindings;
1025 QQmlJSUtils::searchBaseAndExtensionTypes(
1026 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
1027 if (mode != QQmlJSScope::NotExtension) {
1028 Q_ASSERT(!scope->hasOwnPropertyBindings(name));
1031 const auto range = scope->ownPropertyBindings(name);
1032 for (
auto it = range.first; it != range.second; ++it)
1033 bindings.append(*it);
1039bool QQmlJSScope::hasInterface(
const QString &name)
const
1041 return QQmlJSUtils::searchBaseAndExtensionTypes(
1042 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
1043 if (mode != QQmlJSScope::NotExtension)
1045 return scope->m_interfaceNames.contains(name);
1049bool QQmlJSScope::isNameDeferred(
const QString &name)
const
1051 bool isDeferred =
false;
1053 QQmlJSUtils::searchBaseAndExtensionTypes(
this, [&](
const QQmlJSScope *scope) {
1054 const QStringList immediate = scope->ownImmediateNames();
1055 if (!immediate.isEmpty()) {
1056 isDeferred = !immediate.contains(name);
1059 const QStringList deferred = scope->ownDeferredNames();
1060 if (!deferred.isEmpty()) {
1061 isDeferred = deferred.contains(name);
1070void QQmlJSScope::setBaseTypeName(
const QString &baseTypeName)
1072 m_flags.setFlag(HasBaseTypeError,
false);
1073 m_baseTypeNameOrError = baseTypeName;
1076QString QQmlJSScope::baseTypeName()
const
1078 return m_flags.testFlag(HasBaseTypeError) ? QString() : m_baseTypeNameOrError;
1081void QQmlJSScope::setBaseTypeError(
const QString &baseTypeError)
1083 m_flags.setFlag(HasBaseTypeError);
1084 m_baseTypeNameOrError = baseTypeError;
1088
1089
1090
1091
1092
1093QString QQmlJSScope::moduleName()
const
1095 for (
const QQmlJSScope *it =
this; it; it = it->parentScope().get()) {
1096 const QString name = it->ownModuleName();
1097 if (!name.isEmpty())
1103QString QQmlJSScope::baseTypeError()
const
1105 return m_flags.testFlag(HasBaseTypeError) ? m_baseTypeNameOrError : QString();
1108QString QQmlJSScope::attachedTypeName()
const
1111 QQmlJSUtils::searchBaseAndExtensionTypes(
1112 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
1113 if (mode != QQmlJSScope::NotExtension)
1115 if (scope->ownAttachedType().isNull())
1117 name = scope->ownAttachedTypeName();
1124QQmlJSScope::ConstPtr QQmlJSScope::attachedType()
const
1126 QQmlJSScope::ConstPtr ptr;
1127 QQmlJSUtils::searchBaseAndExtensionTypes(
1128 this, [&](
const QQmlJSScope *scope, QQmlJSScope::ExtensionKind mode) {
1129 if (mode != QQmlJSScope::NotExtension)
1131 if (scope->ownAttachedType().isNull())
1133 ptr = scope->ownAttachedType();
1140QQmlJSScope::AnnotatedScope QQmlJSScope::extensionType()
const
1142 if (!m_extensionType)
1143 return { m_extensionType, NotExtension };
1144 if (m_flags & ExtensionIsJavaScript)
1145 return { m_extensionType, ExtensionJavaScript };
1146 if (m_flags & ExtensionIsNamespace)
1147 return { m_extensionType, ExtensionNamespace };
1148 return { m_extensionType, ExtensionType };
1151void QQmlJSScope::addOwnRuntimeFunctionIndex(QQmlJSMetaMethod::AbsoluteFunctionIndex index)
1153 m_runtimeFunctionIndices.emplaceBack(index);
1156bool QQmlJSScope::isResolved()
const
1158 const bool nameIsEmpty = (m_scopeType == ScopeType::AttachedPropertyScope
1159 || m_scopeType == ScopeType::GroupedPropertyScope)
1160 ? m_internalName.isEmpty()
1161 : m_baseTypeNameOrError.isEmpty();
1164 if (m_baseType.scope.isNull())
1166 if (isComposite() && !nonCompositeBaseType(baseType()))
1171QString QQmlJSScope::defaultPropertyName()
const
1174 QQmlJSUtils::searchBaseAndExtensionTypes(
this, [&](
const QQmlJSScope *scope) {
1175 name = scope->ownDefaultPropertyName();
1176 return !name.isEmpty();
1181QString QQmlJSScope::parentPropertyName()
const
1184 QQmlJSUtils::searchBaseAndExtensionTypes(
this, [&](
const QQmlJSScope *scope) {
1185 name = scope->ownParentPropertyName();
1186 return !name.isEmpty();
1191bool QQmlJSScope::isFullyResolved()
const
1193 bool baseResolved =
true;
1194 QQmlJSUtils::searchBaseAndExtensionTypes(
this, [&](
const QQmlJSScope *scope) {
1195 if (!scope->isResolved()) {
1196 baseResolved =
false;
1202 return baseResolved;
1205QQmlJSScope::Export::Export(
1206 QString package, QString type, QTypeRevision version, QTypeRevision revision)
1207 : m_package(std::move(package))
1208 , m_type(std::move(type))
1209 , m_version(std::move(version))
1210 , m_revision(std::move(revision))
1214bool QQmlJSScope::Export::isValid()
const
1216 return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty();
1219QDeferredFactory<QQmlJSScope>::QDeferredFactory(QQmlJSImporter *importer,
1220 const QQmlJS::TypeReader &typeReader,
1221 const QString &filePath,
const QString &moduleName,
1223 : m_importer(importer),
1224 m_typeReader(typeReader ? typeReader : QQmlJS::TypeReader{ QQmlJS::defaultTypeReader }),
1225 m_filePath(filePath),
1226 m_moduleName(moduleName),
1227 m_isSingleton(isSingleton)
1231void QDeferredFactory<QQmlJSScope>::populate(
const QSharedPointer<QQmlJSScope> &scope)
const
1233 scope->setOwnModuleName(m_moduleName);
1234 scope->setIsSingleton(m_isSingleton);
1235 scope->setInternalName(internalName());
1237 m_typeReader(m_importer, m_filePath, scope);
1241
1242
1243
1244
1245
1246
1247
1248
1249bool QQmlJSScope::canAssign(
const QQmlJSScope::ConstPtr &derived)
const
1255 Q_ASSERT(!isComposite() || nonCompositeBaseType(baseType()));
1256 Q_ASSERT(nonCompositeBaseType(derived));
1260 const bool isBaseComponent = [
this]() {
1261 if (internalName() == u"QQmlComponent")
1263 else if (isComposite())
1265 for (
auto cppBase = nonCompositeBaseType(baseType()); cppBase;
1266 cppBase = cppBase->baseType()) {
1267 if (cppBase->internalName() == u"QQmlAbstractDelegateComponent")
1273 QDuplicateTracker<QQmlJSScope::ConstPtr> seen;
1274 for (
auto scope = derived; !scope.isNull() && !seen.hasSeen(scope);
1275 scope = scope->baseType()) {
1276 if (isSameType(scope))
1278 if (isBaseComponent && scope->internalName() == u"QObject"_s)
1282 if (internalName() == u"QVariant"_s || internalName() == u"QJSValue"_s)
1285 return isListProperty() && elementType()->canAssign(derived);
1289
1290
1291
1292bool QQmlJSScope::isInCustomParserParent()
const
1294 for (
const auto *scope =
this; scope; scope = scope->parentScope().get()) {
1295 if (!scope->baseType().isNull() && scope->baseType()->hasCustomParser())
1303
1304
1305
1306
1307std::optional<QString> QQmlJSScope::inlineComponentName()
const
1309 Q_ASSERT(isInlineComponent() == m_inlineComponentName.has_value());
1310 return m_inlineComponentName;
1314
1315
1316
1317
1318QQmlJSScope::InlineComponentOrDocumentRootName QQmlJSScope::enclosingInlineComponentName()
const
1320 for (
auto *type =
this; type; type = type->parentScope().get()) {
1321 if (type->isInlineComponent())
1322 return *type->inlineComponentName();
1324 return RootDocumentNameType();
1327QList<QQmlJSScope::ConstPtr> QQmlJSScope::childScopes()
const
1329 QList<QQmlJSScope::ConstPtr> result;
1330 result.reserve(m_childScopes.size());
1331 for (
const auto &child : m_childScopes)
1332 result.append(child);
1337
1338
1339
1340
1341
1342
1343bool QQmlJSScope::enforcesScopedEnums()
const
1345 for (
const QQmlJSScope *scope =
this; scope; scope = scope->baseType().get()) {
1346 if (scope->hasEnforcesScopedEnumsFlag())
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367bool QQmlJSScope::isCreatable()
const
1369 auto isCreatableNonRecursive = [](
const QQmlJSScope *scope) {
1370 return scope->hasCreatableFlag() && !scope->isSingleton()
1371 && scope->scopeType() == QQmlSA::ScopeType::QMLScope;
1374 for (
const QQmlJSScope* scope =
this; scope; scope = scope->baseType().get()) {
1375 if (!scope->isComposite()) {
1377 return isCreatableNonRecursive(scope);
1380 if (isCreatableNonRecursive(scope))
1388bool QQmlJSScope::isStructured()
const
1390 for (
const QQmlJSScope *scope =
this; scope; scope = scope->baseType().get()) {
1391 if (!scope->isComposite())
1392 return scope->hasStructuredFlag();
1397QQmlSA::Element QQmlJSScope::createQQmlSAElement(
const ConstPtr &ptr)
1399 QQmlSA::Element element;
1400 *
reinterpret_cast<QQmlJSScope::ConstPtr *>(element.m_data) = ptr;
1404QQmlSA::Element QQmlJSScope::createQQmlSAElement(ConstPtr &&ptr)
1406 QQmlSA::Element element;
1407 *
reinterpret_cast<QQmlJSScope::ConstPtr *>(element.m_data) = std::move(ptr);
1411const QQmlJSScope::ConstPtr &QQmlJSScope::scope(
const QQmlSA::Element &element)
1413 return *
reinterpret_cast<
const QQmlJSScope::ConstPtr *>(element.m_data);
1417QQmlJSScope::nonCompositeBaseRevision(
const ImportedScope<QQmlJSScope::ConstPtr> &scope)
1419 for (
auto base = scope; base.scope;
1420 base = { base.scope->m_baseType.scope, base.scope->m_baseType.revision }) {
1421 if (!base.scope->isComposite())
1422 return base.revision;
1428
1429
1430
1431
1432
1433
1434bool QQmlJSScope::isSameType(
const ConstPtr &otherScope)
const
1436 return this == otherScope.get()
1437 || (!
this->internalName().isEmpty()
1438 &&
this->internalName() == otherScope->internalName());
1441bool QQmlJSScope::inherits(
const ConstPtr &base)
const
1443 for (
const QQmlJSScope *scope =
this; scope; scope = scope->baseType().get()) {
1444 if (scope->isSameType(base))
static QQmlJSScope::ImportedScope< QQmlJSScope::ConstPtr > qFindInlineComponents(QStringView typeName, const QQmlJS::ContextualTypes &contextualTypes)
QQmlJSScope::AnnotatedScope searchOwner(const QQmlJSScope::ConstPtr &self, Predicate &&p)
static QString flagStorage(const QString &underlyingType)
static QTypeRevision resolveTypesInternal(Resolver resolve, ChildScopeUpdater update, const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes, QSet< QString > *usedTypes)