Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmljsscope.cpp
Go to the documentation of this file.
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#include "qqmljsscope_p.h"
6#include "qqmljsimporter_p.h"
7#include "qqmljsutils_p.h"
8#include "qqmlsa.h"
9#include "qqmlsa_p.h"
10
11#include <QtCore/qqueue.h>
12#include <QtCore/qsharedpointer.h>
13
14#include <private/qduplicatetracker_p.h>
15
16#include <algorithm>
17#include <type_traits>
18
20
36using namespace Qt::StringLiterals;
37
39{
40 m_internalName = internalName;
41}
42
43void QQmlJSScope::reparent(const QQmlJSScope::Ptr &parentScope, const QQmlJSScope::Ptr &childScope)
44{
45 if (const QQmlJSScope::Ptr parent = childScope->m_parentScope.toStrongRef())
46 parent->m_childScopes.removeOne(childScope);
47 if (parentScope)
48 parentScope->m_childScopes.append(childScope);
49 childScope->m_parentScope = parentScope;
50}
51
53{
54 if (origin.isNull())
55 return QQmlJSScope::Ptr();
56 QQmlJSScope::Ptr cloned = create();
57 *cloned = *origin;
58 if (QQmlJSScope::Ptr parent = cloned->parentScope())
59 parent->m_childScopes.append(cloned);
60 return cloned;
61}
62
64{
68 || m_scopeType == QQmlSA::ScopeType::JSFunctionScope) {
69 m_jsIdentifiers.insert(name, identifier);
70 } else {
71 auto targetScope = parentScope();
72 while (targetScope->m_scopeType != QQmlSA::ScopeType::JSFunctionScope)
73 targetScope = targetScope->parentScope();
74 targetScope->m_jsIdentifiers.insert(name, identifier);
75 }
76}
77
79{
81 QQmlJSMetaMethod method(property.propertyName() + u"Changed"_s, u"void"_s);
82 method.setMethodType(QQmlJSMetaMethodType::Signal);
83 method.setIsImplicitQmlPropertyChangeSignal(true);
85}
86
88{
90}
91
93{
97 return false;
98 return scope->m_methods.contains(name);
99 });
100}
101
112{
117 return false;
118 for (auto it = scope->m_methods.constBegin(); it != scope->m_methods.constEnd();
119 it++) {
120 if (!results.contains(it.key()))
121 results.insert(it.key(), it.value());
122 }
123 return false;
124 });
125
126 return results;
127}
128
130{
132
136 return false;
138 return false;
139 });
140 return results;
141}
142
144{
146
150 return false;
151 const auto ownMethods = scope->ownMethods(name);
152 for (const auto &method : ownMethods) {
153 if (method.methodType() == type)
155 }
156 return false;
157 });
158 return results;
159}
160
162{
164 this, [&](const QQmlJSScope *scope) { return scope->m_enumerations.contains(name); });
165}
166
168{
170 for (const auto &e : scope->m_enumerations) {
171 if (e.keys().contains(name))
172 return true;
173 }
174 return false;
175 });
176}
177
179{
181
183 const auto it = scope->m_enumerations.find(name);
184 if (it == scope->m_enumerations.end())
185 return false;
186 result = *it;
187 return true;
188 });
189
190 return result;
191}
192
194{
196
198 for (auto it = scope->m_enumerations.constBegin(); it != scope->m_enumerations.constEnd();
199 it++) {
200 if (!results.contains(it.key()))
201 results.insert(it.key(), it.value());
202 }
203 return false;
204 });
205
206 return results;
207}
208
210{
211 const auto internal = "$internal$."_L1;
212 const QString anonymous = "$anonymous$."_L1;
213
214 QString pretty = name.toString();
215
216 if (pretty.startsWith(internal))
217 pretty = pretty.mid(internal.size());
218 else if (pretty.startsWith(anonymous))
219 pretty = pretty.mid(anonymous.size());
220
221 if (pretty == u"std::nullptr_t")
222 return u"null"_s;
223
224 if (pretty == u"void")
225 return u"undefined"_s;
226
227 return pretty;
228}
229
235 const QQmlJSScope::ConstPtr &assignedType)
236{
237 // See QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents()
238 // for the logic in qqmltypecompiler
239
240 // Note: unlike findAndRegisterImplicitComponents() we do not check whether
241 // the property type is *derived* from QQmlComponent at some point because
242 // this is actually meaningless (and in the case of QQmlComponent::create()
243 // gets rejected in QQmlPropertyValidator): if the type is not a
244 // QQmlComponent, we have a type mismatch because of assigning a Component
245 // object to a non-Component property
246 const bool propertyVerdict = property.type()->internalName() == u"QQmlComponent";
247
248 const bool assignedTypeVerdict = [&assignedType]() {
249 // Note: nonCompositeBaseType covers the case when assignedType itself
250 // is non-composite
251 auto cppBase = nonCompositeBaseType(assignedType);
252 Q_ASSERT(cppBase); // any QML type has (or must have) a C++ base type
253
254 // See isUsableComponent() in qqmltypecompiler.cpp: along with checking
255 // whether a type has a QQmlComponent static meta object (which we
256 // substitute here with checking the first non-composite base for being
257 // a QQmlComponent), it also excludes QQmlAbstractDelegateComponent
258 // subclasses from implicit wrapping
259 if (cppBase->internalName() == u"QQmlComponent")
260 return false;
261 for (; cppBase; cppBase = cppBase->baseType()) {
262 if (cppBase->internalName() == u"QQmlAbstractDelegateComponent")
263 return false;
264 }
265 return true;
266 }();
267
268 return propertyVerdict && assignedTypeVerdict;
269}
270
282 if (m_flags.testFlag(WrappedInImplicitComponent))
283 return true;
284
285 auto base = nonCompositeBaseType(parentScope()); // handles null parentScope()
286 if (!base)
287 return false;
288 return base->internalName() == u"QQmlComponent";
289}
290
292{
293 if (m_scopeType == QQmlSA::ScopeType::QMLScope)
294 return m_properties.contains(id) || m_methods.contains(id) || m_enumerations.contains(id);
295
296 const auto qmlScope = findCurrentQMLScope(parentScope());
297 return qmlScope->m_properties.contains(id)
298 || qmlScope->m_methods.contains(id)
299 || qmlScope->m_enumerations.contains(id);
300}
301
303{
304 if (m_scopeType != QQmlSA::ScopeType::QMLScope && m_jsIdentifiers.contains(id))
305 return true;
306
307 for (auto jsScope = parentScope(); jsScope; jsScope = jsScope->parentScope()) {
308 if (jsScope->m_scopeType != QQmlSA::ScopeType::QMLScope
309 && jsScope->m_jsIdentifiers.contains(id))
310 return true;
311 }
312
313 return false;
314}
315
317{
318 const auto found = findJSIdentifier(id);
319 return found.has_value() && found->kind == JavaScriptIdentifier::Injected;
320}
321
322std::optional<QQmlJSScope::JavaScriptIdentifier>
324{
325 for (const auto *scope = this; scope; scope = scope->parentScope().data()) {
326 if (scope->m_scopeType == QQmlSA::ScopeType::JSFunctionScope
327 || scope->m_scopeType == QQmlSA::ScopeType::JSLexicalScope) {
328 auto it = scope->m_jsIdentifiers.find(id);
329 if (it != scope->m_jsIdentifiers.end())
330 return *it;
331 }
332 }
333
334 return std::optional<JavaScriptIdentifier>{};
335}
336
337std::optional<QQmlJSScope::JavaScriptIdentifier> QQmlJSScope::JSIdentifier(const QString &id) const
338{
339 auto it = m_jsIdentifiers.find(id);
340 if (it != m_jsIdentifiers.end())
341 return *it;
342
343 return std::optional<JavaScriptIdentifier>{};
344}
345
348{
349 const int separatorIndex = typeName.lastIndexOf(u'.');
350 // do not crash in typeName.sliced() when it starts or ends with an '.'.
351 if (separatorIndex < 1 || separatorIndex >= typeName.size() - 1)
352 return {};
353
354 const auto parentIt = contextualTypes.types().constFind(typeName.first(separatorIndex).toString());
355 if (parentIt == contextualTypes.types().constEnd())
356 return {};
357
358 auto inlineComponentParent = *parentIt;
359
360 // find the inline components using BFS, as inline components defined in childrens are also
361 // accessible from other qml documents. Same for inline components defined in a base class of
362 // the parent. Use BFS over DFS as the inline components are probably not deeply-nested.
363
364 QStringView inlineComponentName = typeName.sliced(separatorIndex + 1);
365 QQueue<QQmlJSScope::ConstPtr> candidatesForInlineComponents;
366 candidatesForInlineComponents.enqueue(inlineComponentParent.scope);
367 while (candidatesForInlineComponents.size()) {
368 QQmlJSScope::ConstPtr current = candidatesForInlineComponents.dequeue();
369 if (!current) // if some type was not resolved, ignore it instead of crashing
370 continue;
371 if (current->isInlineComponent() && current->inlineComponentName() == inlineComponentName) {
372 return { current, inlineComponentParent.revision };
373 }
374 // check alternatively the inline components at layer 1 in current and basetype, then at
375 // layer 2, etc...
376 candidatesForInlineComponents.append(current->childScopes());
377 if (const auto base = current->baseType())
378 candidatesForInlineComponents.enqueue(base);
379 }
380 return {};
381}
382
384 const QString &name, const QQmlJSScope::ContextualTypes &contextualTypes,
385 QSet<QString> *usedTypes)
386{
387 const auto useType = [&]() {
388 if (usedTypes != nullptr)
389 usedTypes->insert(name);
390 };
391
392 auto type = contextualTypes.types().constFind(name);
393
394 if (type != contextualTypes.types().constEnd()) {
395 useType();
396 return *type;
397 }
398
399 const auto findListType = [&](const QString &prefix, const QString &postfix)
401 if (name.startsWith(prefix) && name.endsWith(postfix)) {
402 const qsizetype prefixLength = prefix.length();
403 const QString &elementName
404 = name.mid(prefixLength, name.length() - prefixLength - postfix.length());
405 const ImportedScope<ConstPtr> element
406 = findType(elementName, contextualTypes, usedTypes);
407 if (element.scope) {
408 useType();
409 return { element.scope->listType(), element.revision };
410 }
411 }
412
413 return {};
414 };
415
416 switch (contextualTypes.context()) {
418 if (const auto listType = findListType(u"QList<"_s, u">"_s);
419 listType.scope && !listType.scope->isReferenceType()) {
420 return listType;
421 }
422
423 if (const auto listType = findListType(u"QQmlListProperty<"_s, u">"_s);
424 listType.scope && listType.scope->isReferenceType()) {
425 return listType;
426 }
427
428 // look for c++ namescoped enums!
429 const auto colonColon = name.lastIndexOf(QStringLiteral("::"));
430 if (colonColon == -1)
431 break;
432
433 const QString outerTypeName = name.left(colonColon);
434 const auto outerType = contextualTypes.types().constFind(outerTypeName);
435 if (outerType == contextualTypes.types().constEnd())
436 break;
437
438 for (const auto &innerType : std::as_const(outerType->scope->m_childScopes)) {
439 if (innerType->m_internalName == name) {
440 useType();
441 return { innerType, outerType->revision };
442 }
443 }
444
445 break;
446 }
448 // look after inline components
449 const auto inlineComponent = qFindInlineComponents(name, contextualTypes);
450 if (inlineComponent.scope) {
451 useType();
452 return inlineComponent;
453 }
454
455 if (const auto listType = findListType(u"list<"_s, u">"_s); listType.scope)
456 return listType;
457
458 break;
459 }
460 }
461 return {};
462}
463
464QTypeRevision QQmlJSScope::resolveType(
466 QSet<QString> *usedTypes)
467{
468 if (self->accessSemantics() == AccessSemantics::Sequence
469 && self->internalName().startsWith(u"QQmlListProperty<"_s)) {
470 self->setIsListProperty(true);
471 }
472
473 const QString baseTypeName = self->baseTypeName();
474 const auto baseType = findType(baseTypeName, context, usedTypes);
475 if (!self->m_baseType.scope && !baseTypeName.isEmpty())
476 self->m_baseType = { baseType.scope, baseType.revision };
477
478 if (!self->m_attachedType && !self->m_attachedTypeName.isEmpty())
479 self->m_attachedType = findType(self->m_attachedTypeName, context, usedTypes).scope;
480
481 if (!self->m_valueType && !self->m_valueTypeName.isEmpty())
482 self->m_valueType = findType(self->m_valueTypeName, context, usedTypes).scope;
483
484 if (!self->m_extensionType) {
485 if (self->m_extensionTypeName.isEmpty()) {
486 if (self->accessSemantics() == AccessSemantics::Sequence) {
487 // All sequence types are implicitly extended by JS Array.
488 self->setExtensionTypeName(u"Array"_s);
489 self->m_extensionType = context.arrayType();
490 }
491 } else {
492 self->m_extensionType = findType(self->m_extensionTypeName, context, usedTypes).scope;
493 }
494 }
495
496
497 for (auto it = self->m_properties.begin(), end = self->m_properties.end(); it != end; ++it) {
498 const QString typeName = it->typeName();
499 if (it->type() || typeName.isEmpty())
500 continue;
501
502 if (const auto type = findType(typeName, context, usedTypes); type.scope) {
503 it->setType(it->isList() ? type.scope->listType() : type.scope);
504 continue;
505 }
506
507 const auto enumeration = self->m_enumerations.find(typeName);
508 if (enumeration != self->m_enumerations.end()) {
509 it->setType(it->isList()
512 }
513 }
514
515 for (auto it = self->m_methods.begin(), end = self->m_methods.end(); it != end; ++it) {
516 const QString returnTypeName = it->returnTypeName();
517 if (!it->returnType() && !returnTypeName.isEmpty()) {
518 const auto returnType = findType(returnTypeName, context, usedTypes);
519 it->setReturnType(returnType.scope);
520 }
521
522 auto parameters = it->parameters();
523 for (int i = 0, length = parameters.size(); i < length; ++i) {
524 auto &parameter = parameters[i];
525 if (const QString typeName = parameter.typeName();
526 !parameter.type() && !typeName.isEmpty()) {
527 auto type = findType(typeName, context, usedTypes);
528 if (type.scope && parameter.isList()) {
529 type.scope = type.scope->listType();
530 parameter.setIsList(false);
531 parameter.setIsPointer(false);
532 parameter.setTypeName(type.scope ? type.scope->internalName() : QString());
533 } else if (type.scope && type.scope->isReferenceType()) {
534 parameter.setIsPointer(true);
535 }
536 parameter.setType({ type.scope });
537 }
538 }
539
540 it->setParameters(parameters);
541 }
542
543 for (auto it = self->m_jsIdentifiers.begin(); it != self->m_jsIdentifiers.end(); ++it) {
544 if (it->typeName)
545 it->scope = findType(it->typeName.value(), context, usedTypes).scope;
546 }
547
548 return baseType.revision;
549}
550
551void QQmlJSScope::updateChildScope(
552 const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self,
553 const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
554{
555 switch (childScope->scopeType()) {
559 if (mode == QQmlJSScope::ExtensionNamespace)
560 return false;
561 const auto propertyIt = type->m_properties.find(childScope->internalName());
562 if (propertyIt != type->m_properties.end()) {
563 childScope->m_baseType.scope = QQmlJSScope::ConstPtr(propertyIt->type());
564 if (propertyIt->type())
565 childScope->m_semantics = propertyIt->type()->accessSemantics();
566 childScope->setBaseTypeName(propertyIt->typeName());
567 return true;
568 }
569 return false;
570 });
571 break;
573 if (const auto attachedBase = findType(
574 childScope->internalName(), contextualTypes, usedTypes).scope) {
575 childScope->m_baseType.scope = attachedBase->attachedType();
576 childScope->setBaseTypeName(attachedBase->attachedTypeName());
577 }
578 break;
579 default:
580 break;
581 }
582}
583
584template<typename Resolver, typename ChildScopeUpdater>
586 Resolver resolve, ChildScopeUpdater update, const QQmlJSScope::Ptr &self,
587 const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
588{
589 const QTypeRevision revision = resolve(self, contextualTypes, usedTypes);
590 // NB: constness ensures no detach
591 const auto childScopes = self->childScopes();
592 for (auto it = childScopes.begin(), end = childScopes.end(); it != end; ++it) {
593 const auto childScope = *it;
594 update(childScope, self, contextualTypes, usedTypes);
595 resolveTypesInternal(resolve, update, childScope, contextualTypes, usedTypes); // recursion
596 }
597 return revision;
598}
599
601 const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
602 QSet<QString> *usedTypes)
603{
604 const auto resolveAll = [](const QQmlJSScope::Ptr &self,
605 const QQmlJSScope::ContextualTypes &contextualTypes,
606 QSet<QString> *usedTypes) {
607 resolveEnums(self, contextualTypes, usedTypes);
608 resolveList(self, contextualTypes.arrayType());
609 return resolveType(self, contextualTypes, usedTypes);
610 };
611 return resolveTypesInternal(resolveAll, updateChildScope, self, contextualTypes, usedTypes);
612}
613
615 const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
616 QSet<QString> *usedTypes)
617{
618 resolveTypesInternal(resolveType, updateChildScope, self, contextualTypes, usedTypes);
619}
620
621static QString flagStorage(const QString &underlyingType)
622{
623 // All numeric types are builtins. Therefore we can exhaustively check the internal names.
624
625 if (underlyingType == u"uint"
626 || underlyingType == u"quint8"
627 || underlyingType == u"ushort"
628 || underlyingType == u"ulonglong") {
629 return u"uint"_s;
630 }
631
632 if (underlyingType == u"int"
633 || underlyingType == u"qint8"
634 || underlyingType == u"short"
635 || underlyingType == u"longlong") {
636 return u"int"_s;
637 }
638
639 // Will fail to resolve and produce an error on usage.
640 // It's harmless if you never use the enum.
641 return QString();
642}
643
656 const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
657 QSet<QString> *usedTypes)
658{
659 // temporary hash to avoid messing up m_enumerations while iterators are active on it
661 for (auto it = self->m_enumerations.begin(), end = self->m_enumerations.end(); it != end; ++it) {
662 if (it->type())
663 continue;
665 reparent(self, enumScope);
666 enumScope->m_scopeType = QQmlSA::ScopeType::EnumScope;
667
668 QString typeName = it->typeName();
669 if (typeName.isEmpty())
670 typeName = QStringLiteral("int");
671 else if (it->isFlag())
673 enumScope->setBaseTypeName(typeName);
674 const auto type = findType(typeName, contextualTypes, usedTypes);
675 enumScope->m_baseType = { type.scope, type.revision };
676
677 enumScope->m_semantics = AccessSemantics::Value;
678 enumScope->m_internalName = self->internalName() + QStringLiteral("::") + it->name();
679 if (QString alias = it->alias(); !alias.isEmpty()
680 && self->m_enumerations.constFind(alias) == self->m_enumerations.constEnd()) {
681 auto aliasScope = QQmlJSScope::clone(enumScope);
682 aliasScope->m_internalName = self->internalName() + QStringLiteral("::") + alias;
683 QQmlJSMetaEnum cpy(*it);
684 cpy.setType(QQmlJSScope::ConstPtr(aliasScope));
685 toBeAppended.insert(alias, cpy);
686 }
687 it->setType(QQmlJSScope::ConstPtr(enumScope));
688 }
689 // no more iterators active on m_enumerations, so it can be changed safely now
690 self->m_enumerations.insert(toBeAppended);
691}
692
694{
695 if (self->listType() || self->accessSemantics() == AccessSemantics::Sequence)
696 return;
697
698 Q_ASSERT(!arrayType.isNull());
700 listType->setAccessSemantics(AccessSemantics::Sequence);
701 listType->setValueTypeName(self->internalName());
702
703 if (self->isComposite()) {
704 // There is no internalName for this thing. Just set the value type right away
705 listType->setInternalName(u"QQmlListProperty<>"_s);
706 listType->m_valueType = QQmlJSScope::ConstPtr(self);
707 } else if (self->isReferenceType()) {
708 listType->setInternalName(u"QQmlListProperty<%2>"_s.arg(self->internalName()));
709 // Do not set a filePath on the list type, so that we have to generalize it
710 // even in direct mode.
711 } else {
712 listType->setInternalName(u"QList<%2>"_s.arg(self->internalName()));
713 listType->setFilePath(self->filePath());
714 }
715
716 const QQmlJSImportedScope element = {self, QTypeRevision()};
717 const QQmlJSImportedScope array = {arrayType, QTypeRevision()};
718 QQmlJSScope::ContextualTypes contextualTypes(
719 QQmlJSScope::ContextualTypes::INTERNAL, { { self->internalName(), element }, },
720 arrayType);
721 QQmlJSScope::resolveTypes(listType, contextualTypes);
722
723 Q_ASSERT(listType->valueType() == self);
724 self->m_listType = listType;
725}
726
728 const Ptr &self, const ConstPtr &baseType,
729 const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
730{
732 // Generalized group properties are always composite,
733 // which means we expect contextualTypes to be QML names.
734 Q_ASSERT(self->isComposite());
735
736 self->m_baseType.scope = baseType;
737 self->m_semantics = baseType->accessSemantics();
738 resolveNonEnumTypes(self, contextualTypes, usedTypes);
739}
740
742{
743 auto qmlScope = scope;
744 while (qmlScope && qmlScope->m_scopeType != QQmlSA::ScopeType::QMLScope)
745 qmlScope = qmlScope->parentScope();
746 return qmlScope;
747}
748
750{
754 return false;
755 return scope->m_properties.contains(name);
756 });
757}
758
760{
765 return false;
766 const auto it = scope->m_properties.find(name);
767 if (it == scope->m_properties.end())
768 return false;
769 prop = *it;
770 return true;
771 });
772 return prop;
773}
774
783{
788 return false;
789 for (auto it = scope->m_properties.constBegin();
790 it != scope->m_properties.constEnd(); it++) {
791 if (!results.contains(it.key()))
792 results.insert(it.key(), it.value());
793 }
794 return false;
795 });
796 return results;
797}
798
800 const QString &name)
801{
806 return false;
807 if (scope->hasOwnProperty(name)) {
808 owner = { scope, mode };
809 return true;
810 }
811 return false;
812 });
813 return owner;
814}
815
817{
818 if (!isRequired)
819 m_requiredPropertyNames.removeOne(name);
820 else if (!m_requiredPropertyNames.contains(name))
821 m_requiredPropertyNames.append(name);
822}
823
825{
826 bool isRequired = false;
830 isRequired = true;
831 return true;
832 }
833
834 // the hasOwnProperty() below only makes sense if our scope is
835 // not an extension namespace
837 return false;
838
839 // If it has a property of that name, and that is not required, then none of the
840 // base types matter. You cannot make a derived type's property required with
841 // a "required" specification in a base type.
842 return scope->hasOwnProperty(name);
843 });
844 return isRequired;
845}
846
848{
849 return m_requiredPropertyNames.contains(name);
850}
851
853 "We really want T to be relocatable as it improves QList<T> performance");
854
855void QQmlJSScope::addOwnPropertyBindingInQmlIROrder(const QQmlJSMetaPropertyBinding &binding,
856 BindingTargetSpecifier specifier)
857{
858 // the order:
859 // * ordinary bindings are prepended to the binding array
860 // * list bindings are properly ordered within each other, so basically
861 // prepended "in bulk"
862 // * bindings to default properties (which are not explicitly mentioned in
863 // binding expression) are inserted by source location's offset
864
865 switch (specifier) {
867 m_propertyBindingsArray.emplaceFront(binding.propertyName(),
868 binding.sourceLocation().offset);
869 break;
870 }
872 const auto bindingOnTheSameProperty =
874 return x.propertyName == binding.propertyName();
875 };
876 // fake "prepend in bulk" by appending a list binding to the sequence of
877 // bindings to the same property. there's an implicit QML language
878 // guarantee that such sequence does not contain arbitrary in-between
879 // bindings that do not belong to the same list property
880 auto pos = std::find_if_not(m_propertyBindingsArray.begin(), m_propertyBindingsArray.end(),
881 bindingOnTheSameProperty);
882 Q_ASSERT(pos == m_propertyBindingsArray.begin()
883 || std::prev(pos)->propertyName == binding.propertyName());
884 m_propertyBindingsArray.emplace(pos, binding.propertyName(),
885 binding.sourceLocation().offset);
886 break;
887 }
889 // see QmlIR::PoolList<>::findSortedInsertionPoint()
890 const auto findInsertionPoint = [this](const QQmlJSMetaPropertyBinding &x) {
891 qsizetype pos = -1;
892 for (auto it = m_propertyBindingsArray.cbegin(); it != m_propertyBindingsArray.cend();
893 ++it) {
894 if (!(it->sourceLocationOffset <= x.sourceLocation().offset))
895 break;
896 ++pos;
897 }
898 return pos;
899 };
900
901 // see QmlIR::PoolList<>::insertAfter()
902 const auto insertAfter = [this](qsizetype pos, const QQmlJSMetaPropertyBinding &x) {
903 if (pos == -1) {
904 m_propertyBindingsArray.emplaceFront(x.propertyName(), x.sourceLocation().offset);
905 } else if (pos == m_propertyBindingsArray.size()) {
906 m_propertyBindingsArray.emplaceBack(x.propertyName(), x.sourceLocation().offset);
907 } else {
908 // since we insert *after*, use (pos + 1) as insertion point
909 m_propertyBindingsArray.emplace(pos + 1, x.propertyName(),
910 x.sourceLocation().offset);
911 }
912 };
913
914 const qsizetype insertionPos = findInsertionPoint(binding);
915 insertAfter(insertionPos, binding);
916 break;
917 }
918 default: {
919 Q_UNREACHABLE();
920 break;
921 }
922 }
923}
924
926{
928 qmlIrOrdered.reserve(m_propertyBindingsArray.size());
929
930 for (const auto &data : m_propertyBindingsArray) {
931 const auto [first, last] = m_propertyBindings.equal_range(data.propertyName);
932 Q_ASSERT(first != last);
933 auto binding = std::find_if(first, last, [&](const QQmlJSMetaPropertyBinding &x) {
934 return x.sourceLocation().offset == data.sourceLocationOffset;
935 });
936 Q_ASSERT(binding != last);
937 qmlIrOrdered.append(*binding);
938 }
939
940 return qmlIrOrdered;
941}
942
944{
949 return false;
950 }
952 });
953}
954
956{
962 return false;
963 }
964 const auto range = scope->ownPropertyBindings(name);
965 for (auto it = range.first; it != range.second; ++it)
966 bindings.append(*it);
967 return false;
968 });
969 return bindings;
970}
971
973{
977 return false;
978 return scope->m_interfaceNames.contains(name);
979 });
980}
981
983{
984 bool isDeferred = false;
985
987 const QStringList immediate = scope->ownImmediateNames();
988 if (!immediate.isEmpty()) {
989 isDeferred = !immediate.contains(name);
990 return true;
991 }
992 const QStringList deferred = scope->ownDeferredNames();
993 if (!deferred.isEmpty()) {
994 isDeferred = deferred.contains(name);
995 return true;
996 }
997 return false;
998 });
999
1000 return isDeferred;
1001}
1002
1004 const QTypeRevision &firstRevision,
1005 const QTypeRevision &lastRevision)
1006{
1008 u"%1/%2 %3.%4"_s.arg(moduleName, typeName)
1009 .arg(firstRevision.hasMajorVersion() ? firstRevision.majorVersion() : 0)
1010 .arg(firstRevision.hasMinorVersion() ? firstRevision.minorVersion() : 0);
1011 if (firstRevision != lastRevision) {
1012 qualifiedName += u"-%1.%2"_s
1013 .arg(lastRevision.hasMajorVersion() ? lastRevision.majorVersion() : 0)
1014 .arg(lastRevision.hasMinorVersion() ? lastRevision.minorVersion() : 0);
1015 }
1016 return qualifiedName;
1017}
1018
1019void QQmlJSScope::setBaseTypeName(const QString &baseTypeName)
1020{
1021 m_flags.setFlag(HasBaseTypeError, false);
1022 m_baseTypeNameOrError = baseTypeName;
1023}
1024
1026{
1027 return m_flags.testFlag(HasBaseTypeError) ? QString() : m_baseTypeNameOrError;
1028}
1029
1030void QQmlJSScope::setBaseTypeError(const QString &baseTypeError)
1031{
1032 m_flags.setFlag(HasBaseTypeError);
1033 m_baseTypeNameOrError = baseTypeError;
1034}
1035
1037{
1038 return m_flags.testFlag(HasBaseTypeError) ? m_baseTypeNameOrError : QString();
1039}
1040
1042{
1043 QString name;
1047 return false;
1048 if (scope->ownAttachedType().isNull())
1049 return false;
1051 return true;
1052 });
1053
1054 return name;
1055}
1056
1058{
1063 return false;
1064 if (scope->ownAttachedType().isNull())
1065 return false;
1067 return true;
1068 });
1069
1070 return ptr;
1071}
1072
1074{
1075 const bool nameIsEmpty = (m_scopeType == ScopeType::AttachedPropertyScope
1076 || m_scopeType == ScopeType::GroupedPropertyScope)
1077 ? m_internalName.isEmpty()
1078 : m_baseTypeNameOrError.isEmpty();
1079 if (nameIsEmpty)
1080 return true;
1081 if (m_baseType.scope.isNull())
1082 return false;
1084 return false;
1085 return true;
1086}
1087
1089{
1090 QString name;
1093 return !name.isEmpty();
1094 });
1095 return name;
1096}
1097
1099{
1100 QString name;
1103 return !name.isEmpty();
1104 });
1105 return name;
1106}
1107
1109{
1110 bool baseResolved = true;
1112 if (!scope->isResolved()) {
1113 baseResolved = false;
1114 return true;
1115 }
1116 return false;
1117 });
1118
1119 return baseResolved;
1120}
1121
1123 bool isDependency) :
1124 m_prefix(std::move(prefix)),
1125 m_name(std::move(name)),
1126 m_version(version),
1127 m_isFile(isFile),
1128 m_isDependency(isDependency)
1129{
1130}
1131
1133{
1134 return !m_name.isEmpty();
1135}
1136
1138 QString package, QString type, QTypeRevision version, QTypeRevision revision)
1139 : m_package(std::move(package))
1140 , m_type(std::move(type))
1141 , m_version(std::move(version))
1142 , m_revision(std::move(revision))
1143{
1144}
1145
1147{
1148 return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty();
1149}
1150
1152{
1153 scope->setQualifiedName(m_qualifiedName);
1154 scope->setModuleName(m_moduleName);
1155 QQmlJSTypeReader typeReader(m_importer, m_filePath);
1156 typeReader(scope);
1157 m_importer->m_globalWarnings.append(typeReader.errors());
1159 QQmlJSScope::resolveEnums(scope, m_importer->builtinInternalNames());
1160 QQmlJSScope::resolveList(scope, m_importer->builtinInternalNames().arrayType());
1161
1162 if (m_isSingleton && !scope->isSingleton()) {
1163 m_importer->m_globalWarnings.append(
1165 "Type %1 declared as singleton in qmldir but missing pragma Singleton")
1166 .arg(scope->internalName()),
1168 scope->setIsSingleton(true);
1169 } else if (!m_isSingleton && scope->isSingleton()) {
1170 m_importer->m_globalWarnings.append(
1171 { QStringLiteral("Type %1 not declared as singleton in qmldir "
1172 "but using pragma Singleton")
1173 .arg(scope->internalName()),
1175 scope->setIsSingleton(false);
1176 }
1177}
1178
1180{
1181 if (!derived)
1182 return false;
1183
1184 // expect this and derived types to have non-composite bases
1187
1188 // the logic with isBaseComponent (as well as the way we set this flag)
1189 // feels wrong - QTBUG-101940
1190 const bool isBaseComponent = [this]() {
1191 if (internalName() == u"QQmlComponent")
1192 return true;
1193 else if (isComposite())
1194 return false;
1195 for (auto cppBase = nonCompositeBaseType(baseType()); cppBase;
1196 cppBase = cppBase->baseType()) {
1197 if (cppBase->internalName() == u"QQmlAbstractDelegateComponent")
1198 return true;
1199 }
1200 return false;
1201 }();
1202
1204 for (auto scope = derived; !scope.isNull() && !seen.hasSeen(scope);
1205 scope = scope->baseType()) {
1206 if (isSameType(scope))
1207 return true;
1208 if (isBaseComponent && scope->internalName() == u"QObject"_s)
1209 return true;
1210 }
1211
1212 if (internalName() == u"QVariant"_s || internalName() == u"QJSValue"_s)
1213 return true;
1214
1215 return isListProperty() && valueType()->canAssign(derived);
1216}
1217
1219{
1220 for (const auto *scope = this; scope; scope = scope->parentScope().get()) {
1222 return true;
1223 }
1224
1225 return false;
1226}
1227
1233std::optional<QString> QQmlJSScope::inlineComponentName() const
1234{
1235 Q_ASSERT(isInlineComponent() == m_inlineComponentName.has_value());
1236 return m_inlineComponentName;
1237}
1238
1245{
1246 for (auto *type = this; type; type = type->parentScope().get()) {
1247 if (type->isInlineComponent())
1248 return *type->inlineComponentName();
1249 }
1250 return RootDocumentNameType();
1251}
1252
1269{
1270 auto isCreatableNonRecursive = [](const QQmlJSScope *scope) {
1271 return scope->hasCreatableFlag() && !scope->isSingleton()
1273 };
1274
1275 for (const QQmlJSScope* scope = this; scope; scope = scope->baseType().get()) {
1276 if (!scope->isComposite()) {
1277 // just check the first nonComposite (c++) base for isCreatableNonRecursive() and then stop
1278 return isCreatableNonRecursive(scope);
1279 } else {
1280 // check all composite (qml) bases for isCreatableNonRecursive().
1281 if (isCreatableNonRecursive(scope))
1282 return true;
1283 }
1284 }
1285 // no uncreatable bases found
1286 return false;
1287}
1288
1290{
1291 for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().get()) {
1292 if (!scope->isComposite())
1293 return scope->hasStructuredFlag();
1294 }
1295 return false;
1296}
1297
1299{
1300 QQmlSA::Element element;
1301 *reinterpret_cast<QQmlJSScope::ConstPtr *>(element.m_data) = ptr;
1302 return element;
1303}
1304
1306{
1307 QQmlSA::Element element;
1308 *reinterpret_cast<QQmlJSScope::ConstPtr *>(element.m_data) = std::move(ptr);
1309 return element;
1310}
1311
1313{
1314 return *reinterpret_cast<const QQmlJSScope::ConstPtr *>(element.m_data);
1315}
1316
\inmodule QtCore
QSharedPointer< T > toStrongRef() const
bool hasSeen(const T &s)
\inmodule QtCore
Definition qhash.h:818
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1209
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1258
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1205
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:991
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1206
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:471
void reserve(qsizetype size)
Definition qlist.h:746
void append(parameter_type t)
Definition qlist.h:441
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1829
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1833
QPair< iterator, iterator > equal_range(const Key &key)
Definition qhash.h:2128
bool contains(const Key &key) const noexcept
Definition qhash.h:1567
void setType(const QSharedPointer< const QQmlJSScope > &type)
QSharedPointer< const QQmlJSScope > type() const
const QQmlJS::SourceLocation & sourceLocation() const
Tracks the types for the QmlCompiler.
QHash< QString, QQmlJSMetaProperty > properties() const
Returns all properties visible from this scope including those of base types and extensions.
QString attachedTypeName() const
QList< QQmlJSMetaPropertyBinding > propertyBindings(const QString &name) const
static void resolveGeneralizedGroup(const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &baseType, const QQmlJSScope::ContextualTypes &contextualTypes, QSet< QString > *usedTypes=nullptr)
bool isComposite() const
bool isStructured() const
bool hasOwnPropertyBindings(const QString &name) const
void insertJSIdentifier(const QString &name, const JavaScriptIdentifier &identifier)
QDeferredSharedPointer< QQmlJSScope > Ptr
bool isNameDeferred(const QString &name) const
QHash< QString, QQmlJSMetaMethod > methods() const
Returns all methods visible from this scope including those of base types and extensions.
InlineComponentOrDocumentRootName enclosingInlineComponentName() const
QString defaultPropertyName() const
bool isInCustomParserParent() const
bool hasPropertyBindings(const QString &name) const
static QQmlJSScope::Ptr create()
bool isSameType(const QQmlJSScope::ConstPtr &otherScope) const
void setAccessSemantics(AccessSemantics semantics)
void setModuleName(const QString &moduleName)
std::monostate RootDocumentNameType
static AnnotatedScope ownerOfProperty(const QQmlJSScope::ConstPtr &self, const QString &name)
bool isComponentRootElement() const
bool isResolved() const
bool isSingleton() const
bool isIdInjectedFromSignal(const QString &id) const
QQmlJSScope::Ptr parentScope()
ScopeType scopeType() const
bool hasStructuredFlag() const
void setInternalName(const QString &internalName)
QString baseTypeName() const
QString internalName() const
bool hasCreatableFlag() const
static void resolveEnums(const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes, QSet< QString > *usedTypes=nullptr)
static bool causesImplicitComponentWrapping(const QQmlJSMetaProperty &property, const QQmlJSScope::ConstPtr &assignedType)
Returns if assigning assignedType to property would require an implicit component wrapping.
void setIsSingleton(bool v)
bool isReferenceType() const
static QQmlJSScope::ConstPtr nonCompositeBaseType(const QQmlJSScope::ConstPtr &type)
void addOwnProperty(const QQmlJSMetaProperty &prop)
QString parentPropertyName() const
static void resolveList(const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &arrayType)
QHash< QString, QQmlJSMetaEnum > enumerations() const
@ WrappedInImplicitComponent
bool isIdInCurrentScope(const QString &id) const
QString moduleName() const
bool isInlineComponent() const
void insertPropertyIdentifier(const QQmlJSMetaProperty &prop)
AccessSemantics accessSemantics() const
static QQmlSA::Element createQQmlSAElement(const ConstPtr &)
bool hasEnumeration(const QString &name) const
static QTypeRevision resolveTypes(const Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes, QSet< QString > *usedTypes=nullptr)
QVector< QQmlJSScope::Ptr > childScopes()
bool hasEnumerationKey(const QString &name) const
static QString qualifiedNameFrom(const QString &moduleName, const QString &typeName, const QTypeRevision &firstRevision, const QTypeRevision &lastRevision)
void setBaseTypeName(const QString &baseTypeName)
QString ownDefaultPropertyName() const
bool hasCustomParser() const
QString qualifiedName() const
bool isListProperty() const
QStringList ownDeferredNames() const
bool isFullyResolved() const
void setQualifiedName(const QString &qualifiedName)
bool hasInterface(const QString &name) const
QQmlJSMetaEnum enumeration(const QString &name) const
QList< QQmlJSMetaPropertyBinding > ownPropertyBindingsInQmlIROrder() const
bool isCreatable() const
QQmlJSScope(const QString &internalName)
bool hasMethod(const QString &name) const
QQmlJSScope::ConstPtr listType() const
static const QQmlJSScope::ConstPtr & scope(const QQmlSA::Element &)
bool isPropertyRequired(const QString &name) const
QStringList ownImmediateNames() const
void setValueTypeName(const QString &name)
QQmlJSScope::ConstPtr attachedType() const
static QQmlJSScope::Ptr clone(const QQmlJSScope::ConstPtr &origin)
QDeferredSharedPointer< const QQmlJSScope > ConstPtr
std::optional< JavaScriptIdentifier > findJSIdentifier(const QString &id) const
std::variant< InlineComponentNameType, RootDocumentNameType > InlineComponentOrDocumentRootName
A Hashable type to differentiate document roots from different inline components.
QQmlJSMetaProperty property(const QString &name) const
std::optional< JavaScriptIdentifier > JSIdentifier(const QString &id) const
static QString prettyName(QAnyStringView name)
bool hasOwnProperty(const QString &name) const
static ImportedScope< QQmlJSScope::ConstPtr > findType(const QString &name, const ContextualTypes &contextualTypes, QSet< QString > *usedTypes=nullptr)
bool canAssign(const QQmlJSScope::ConstPtr &derived) const
bool isIdInCurrentQmlScopes(const QString &id) const
QQmlJSScope::ConstPtr baseType() const
void addOwnMethod(const QQmlJSMetaMethod &method)
bool isPropertyLocallyRequired(const QString &name) const
QString ownParentPropertyName() const
std::optional< QString > inlineComponentName() const
bool hasProperty(const QString &name) const
QQmlJSScope::ConstPtr ownAttachedType() const
static void reparent(const QQmlJSScope::Ptr &parentScope, const QQmlJSScope::Ptr &childScope)
static QQmlJSScope::ConstPtr findCurrentQMLScope(const QQmlJSScope::ConstPtr &scope)
QMultiHash< QString, QQmlJSMetaPropertyBinding > ownPropertyBindings() const
QString baseTypeError() const
bool isIdInCurrentJSScopes(const QString &id) const
void setFilePath(const QString &file)
QMultiHash< QString, QQmlJSMetaMethod > ownMethods() const
QQmlJSScope::ConstPtr valueType() const
static void resolveNonEnumTypes(const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes, QSet< QString > *usedTypes=nullptr)
void setPropertyLocallyRequired(const QString &name, bool isRequired)
void setBaseTypeError(const QString &baseTypeError)
QString ownAttachedTypeName() const
\inmodule QtQmlCompiler
Definition qqmlsa.h:197
\inmodule QtCore
Definition qqueue.h:14
void enqueue(const T &t)
Adds value t to the tail of the queue.
Definition qqueue.h:18
T dequeue()
Removes the head item in the queue and returns it.
Definition qqueue.h:19
Definition qset.h:18
iterator begin()
Definition qset.h:136
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first character in the string.
Definition qstring.h:1197
const_iterator constEnd() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing just after the last character in...
Definition qstring.h:1211
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
iterator end()
Returns an \l{STL-style iterators}{STL-style iterator} pointing just after the last character in the ...
Definition qstring.h:1205
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QString & insert(qsizetype i, QChar c)
Definition qstring.cpp:3110
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1095
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
qsizetype length() const
Returns the number of characters in this string.
Definition qstring.h:187
\inmodule QtCore
constexpr bool hasMinorVersion() const
Returns true if the minor version is known, otherwise false.
constexpr bool hasMajorVersion() const
Returns true if the major version is known, otherwise false.
constexpr quint8 minorVersion() const
Returns the minor version encoded in the revision.
constexpr quint8 majorVersion() const
Returns the major version encoded in the revision.
double e
QSet< QString >::iterator it
MethodType
Definition qqmlsa.h:55
Combined button and popup list for selecting options.
QString self
Definition language.cpp:57
static void * context
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
static QDBusError::ErrorType get(const char *name)
@ QtCriticalMsg
Definition qlogging.h:32
static ControlElement< T > * ptr(QWidget *widget)
const char * typeName
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLsizei range
GLenum type
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLuint name
GLint first
GLenum array
GLuint64EXT * result
[6]
static QString internalName(const QQmlJSScope::ConstPtr &scope)
static QTypeRevision resolveTypesInternal(Resolver resolve, ChildScopeUpdater update, const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes, QSet< QString > *usedTypes)
static QQmlJSScope::ImportedScope< QQmlJSScope::ConstPtr > qFindInlineComponents(QStringView typeName, const QQmlJSScope::ContextualTypes &contextualTypes)
static QString flagStorage(const QString &underlyingType)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int(*) void arg)
#define QStringLiteral(str)
ptrdiff_t qsizetype
Definition qtypes.h:70
const char property[13]
Definition qwizard.cpp:101
if(qFloatDistance(a, b)<(1<< 7))
[0]
QExplicitlySharedDataPointer< Derived > derived(base)
bool contains(const AT &t) const noexcept
Definition qlist.h:44
const QHash< QString, ImportedScope< ConstPtr > > & types() const
CompileContext context() const
static bool searchBaseAndExtensionTypes(QQmlJSScopePtr type, const Action &check)
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent