17#include <QtQml/private/qqmljsast_p.h>
18#include <QtQmlCompiler/private/qqmljsutils_p.h>
21#include <QtCore/QFileInfo>
22#include <QtCore/QScopeGuard>
23#include <QtCore/QLoggingCategory>
34
35
36
37#define Q_SCRIPTELEMENT_DISABLE()
39 qDebug() << "Could not construct the JS DOM at" << __FILE__ << ":" << __LINE__
40 << ", skipping JS elements...";
41 disableScriptElements();
44#define Q_SCRIPTELEMENT_EXIT_IF(check)
46 if (m_enableScriptExpressions && (check)) {
47 Q_SCRIPTELEMENT_DISABLE();
58template<
typename K,
typename V>
59V *valueFromMultimap(QMultiMap<K, V> &mmap,
const K &key, index_type idx)
63 auto it = mmap.find(key);
64 auto end = mmap.end();
69 while (it2 != end && it2.key() == key) {
75 for (index_type i = idx + 1; i < nEl; ++i)
87static QString toString(
const UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char(
'.'))
91 for (
const UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) {
92 if (iter != qualifiedId)
101static QString typeToString(AST::Type *t)
104 QString res = toString(t->typeId);
106 if (UiQualifiedId *arg = t->typeArgument)
107 res += u'<' + toString(arg) + u'>';
112SourceLocation combineLocations(SourceLocation s1, SourceLocation s2)
114 return combine(s1, s2);
117SourceLocation combineLocations(Node *n)
119 return combineLocations(n->firstSourceLocation(), n->lastSourceLocation());
123 const SourceLocation &dotToken,
126 SourceLocation s1, s2;
127 left.visitConst([&s1](
auto &&el) { s1 = el->mainRegionLocation(); });
128 right.visitConst([&s2](
auto &&el) { s2 = el->mainRegionLocation(); });
131 result->addLocation(OperatorTokenRegion, dotToken);
133 result->setLeft(left);
134 result->setRight(right);
139
140
141
143fieldMemberExpressionForQualifiedId(
const AST::UiQualifiedId *qualifiedId)
147 for (
auto exp = qualifiedId; exp; exp = exp->next) {
148 const SourceLocation identifierLoc = exp->identifierToken;
150 id->setName(exp->name);
156 bindable = wrapIntoFieldMemberExpression(bindable, exp->dotToken,
157 ScriptElementVariant::fromElement(id));
165 Q_ASSERT_X(idx < nodeStack.size() && idx >= 0,
"currentQmlObjectOrComponentEl",
166 "Stack does not contain enough elements!");
167 int i = nodeStack.size() - idx;
169 DomType k = nodeStack.at(i).item.kind;
170 if (k == DomType::QmlObject || k == DomType::QmlComponent)
173 Q_ASSERT_X(
false,
"currentQmlObjectEl",
"No QmlObject or component in stack");
174 return nodeStack.last();
179 Q_ASSERT_X(i < nodeStack.size() && i >= 0,
"currentNode",
"Stack does not contain element!");
180 return nodeStack[nodeStack.size() - i - 1];
185 Q_ASSERT_X(i < scriptNodeStack.size() && i >= 0,
"currentNode",
186 "Stack does not contain element!");
187 return scriptNodeStack[scriptNodeStack.size() - i - 1];
192 Q_ASSERT_X(i < nodeStack.size() && i >= 0,
"currentNode",
193 "Stack does not contain element!");
194 return nodeStack[nodeStack.size() - i - 1].item;
199 Q_ASSERT_X(!nodeStack.isEmpty(), className,
"popCurrentNode() without any node");
201 Q_ASSERT(nodeStack.last().item.kind == *expectedType);
202 nodeStack.removeLast();
208 Q_ASSERT_X(!scriptNodeStack.isEmpty(), className,
209 "popCurrentScriptNode() without any node");
211 Q_ASSERT(scriptNodeStack.last().kind == *expectedType);
212 scriptNodeStack.removeLast();
216
217
218
219
220
221
222
223
224
225
226
231 auto e = element.base();
234 qCDebug(creatorLog) <<
"Finalizing script expression with path:"
235 << FileLocations::canonicalPathForTesting(ownerFileLocations)
236 .append(pathFromOwner.toString());
237 e->updatePathFromOwner(pathFromOwner);
238 e->createFileLocations(ownerFileLocations);
256 switch (currentNode().kind) {
265 qCWarning(domLog) <<
"unexpected type" << domTypeToString(currentNode().kind);
268 base = currentNodeEl().fileLocations;
272 && (p2.checkHeadName(Fields::children) || p2.checkHeadName(Fields::objects)
273 || p2.checkHeadName(Fields::value) || p2.checkHeadName(Fields::annotations)
274 || p2.checkHeadName(Fields::children)))
276 else if (p
.last().checkHeadName(Fields::value)
280 qCWarning(domLog) <<
"unexpected path to QmlObject in createMap" << p;
284 qCWarning(domLog) <<
"unexpected path to QmlObject in createMap" << p;
290 base = currentNodeEl().fileLocations;
303 base = currentEl<
QmlObject>().fileLocations;
311 qCWarning(domLog) <<
"Unexpected type in createMap:" << domTypeToString(k);
315 return createMap(base, relative, n);
327 QFileInfo fInfo(qmlFile.canonicalFilePath());
328 QString componentName = fInfo.baseName();
330 Path p = qmlFilePtr->addComponent(QmlComponent(componentName), AddOption::KeepExisting,
333 Q_ASSERT_X(newC
.item(), className,
"could not recover component added with addComponent");
337 pushEl(p, *cPtr, program);
339 auto envPtr = qmlFile.environment().ownerAs<DomEnvironment>();
340 const bool loadDependencies =
343 if (!fInfo.canonicalPath().isEmpty()) {
344 Import selfDirImport(QmlUri::fromDirectoryString(fInfo.canonicalPath()));
346 qmlFilePtr->addImport(selfDirImport);
348 if (loadDependencies) {
349 const QString currentFile = envPtr->domCreationOption() == Extended
350 ? QQmlJSUtils::qmlBuildPathFromSourcePath(
351 envPtr->semanticAnalysis().m_mapper.get(),
352 qmlFile.canonicalFilePath())
353 : qmlFile.canonicalFilePath();
355 const QDir implicitImportDir = QFileInfo(currentFile).dir();
356 const QString implicitImportDirPath = implicitImportDir.canonicalPath();
357 envPtr->loadFile(FileToLoad::fromFileSystem(envPtr, implicitImportDirPath),
361 if (implicitImportDir.exists(u"qmldir"_s)) {
362 const QString implicitImportQmldir = implicitImportDirPath + u"/qmldir"_s;
363 envPtr->loadFile(FileToLoad::fromFileSystem(envPtr, implicitImportQmldir),
369 for (Import i : qmlFile.environment().ownerAs<DomEnvironment>()->implicitImports()) {
371 qmlFilePtr->addImport(i);
373 if (loadDependencies)
374 envPtr->loadModuleDependency(i.uri.moduleUri(), i.version, DomItem::Callback());
376 if (m_loadFileLazily && loadDependencies) {
377 envPtr->loadPendingDependencies();
378 envPtr->commitToBase(qmlFile.environment().item());
387 QmlComponent &comp = current<QmlComponent>();
388 for (
const Pragma &p : qmlFilePtr->pragmas()) {
389 if (p.name.compare(u"singleton", Qt::CaseInsensitive) == 0) {
390 comp.setIsSingleton(
true);
391 comp.setIsCreatable(
false);
394 *newC.mutableAs<QmlComponent>() = comp;
396 Q_ASSERT_X(nodeStack.isEmpty(), className,
"ui program did not finish node stack");
401 QStringList valueList;
402 for (
auto t = el->values; t; t = t->next)
403 valueList << t->value.toString();
405 auto fileLocation = createMap(
406 DomType::Pragma, qmlFilePtr->addPragma(Pragma(el->name.toString(), valueList)), el);
409 if (el->colonToken.isValid()) {
413 for (
auto t = el->values; t; t = t->next) {
414 auto subMap = createMap(fileLocation, Path().withField(Fields::values).withIndex(i), t);
424 Version v(Version::Latest, Version::Latest);
425 if (el->version && el->version->version.hasMajorVersion())
426 v.majorVersion = el->version->version.majorVersion();
427 if (el->version && el->version->version.hasMinorVersion())
428 v.minorVersion = el->version->version.minorVersion();
430 auto envPtr = qmlFile.environment().ownerAs<DomEnvironment>();
431 const bool loadDependencies =
434 if (el->importUri !=
nullptr) {
436 Import::fromUriString(toString(el->importUri), v, el->importId.toString());
437 fileLocation = createMap(DomType::Import, qmlFilePtr->addImport(import), el);
439 if (loadDependencies) {
440 envPtr->loadModuleDependency(import.uri.moduleUri(), import.version,
441 DomItem::Callback());
446 Import::fromFileString(el->fileName.toString(), el->importId.toString());
447 fileLocation = createMap(DomType::Import, qmlFilePtr->addImport(import), el);
449 if (loadDependencies) {
450 const QString currentFileDir =
451 QFileInfo(qmlFile.canonicalFilePath()).dir().canonicalPath();
452 envPtr->loadFile(FileToLoad::fromFileSystem(
453 envPtr, import.uri.absoluteLocalPath(currentFileDir)),
458 if (m_loadFileLazily && loadDependencies) {
459 envPtr->loadPendingDependencies();
460 envPtr->commitToBase(qmlFile.environment().item());
463 if (el->importToken.isValid())
466 if (el->asToken.isValid())
469 if (el->importIdToken.isValid())
482 case AST::UiPublicMember::Signal: {
484 m.name = el->name.toString();
485 m.typeName = toString(el->memberType);
486 m.isReadonly = el->isReadonly();
488 m.methodType = MethodInfo::Signal;
489 m.isList = el->typeModifier == QLatin1String(
"list");
492 pushEl(p, *mPtr, el);
494 const auto fileLocations = nodeStack.last().fileLocations;
497 if (el->lparenToken.isValid())
499 if (el->rparenToken.isValid())
503 AST::UiParameterList *args = el->parameters;
506 param.name = args->name.toString();
507 param.typeName = args->type ? args->type->toString() : QString();
508 index_type idx = index_type(mInfo.parameters.size());
509 if (!args->colonToken.isValid())
511 mInfo.parameters.append(param);
513 Path::fromField(Fields::parameters).withIndex(idx));
517 if (args->colonToken.isValid())
525 case AST::UiPublicMember::Property: {
527 p.name = el->name.toString();
528 p.typeName = toString(el->memberType);
529 p.isReadonly = el->isReadonly();
532 p.isList = el->typeModifier == QLatin1String(
"list");
536 if (!el->typeModifier.isEmpty())
537 p.typeName = el->typeModifier.toString() + QChar(u'<') + p.typeName + QChar(u'>');
539 Path pPathFromOwner =
541 if (m_enableScriptExpressions) {
543 qmlObjectType->insertChild(Fields::typeName,
544 fieldMemberExpressionForQualifiedId(el->memberType));
547 pPathFromOwner.withField(Fields::nameIdentifiers), rootMap)
);
550 m_skipBindingIdentifiers = el->binding;
552 pushEl(pPathFromOwner, *pPtr, el);
554 el->propertyToken());
556 el->identifierToken);
560 if (el->typeModifierToken.isValid())
563 qmlFile.addError(std::move(astParseErrors()
564 .warning(tr(
"id is a special attribute, that should not be "
565 "used as property name"))
566 .withPath(currentNodeEl().path)));
577 el->overrideToken());
585 el->requiredToken());
589 el->readonlyToken());
593 SourceLocation loc = combineLocations(el->statement);
594 QStringView code = qmlFilePtr->code();
597 code.mid(loc.offset, loc.length), qmlFilePtr->engine(), el->statement,
598 qmlFilePtr->astComments(), ScriptExpression::ExpressionType::BindingExpression,
603 FileLocations::
Tree bLoc = createMap(DomType::Binding, bPathFromOwner, el->statement);
605 FileLocations::
Tree valueLoc = FileLocations::ensure(bLoc, Path::fromField(Fields::value));
609 nodeStack.append({ std::move(bPathFromOwner), *bPtr, std::move(bLoc) });
621 if (m_enableScriptExpressions
622 && (scriptNodeStack.size() != 1 || scriptNodeStack.last().isList())) {
625 if (m_enableScriptExpressions) {
626 b.scriptExpressionValue()->setScriptElement(finalizeScriptExpression(
627 currentScriptNodeEl().takeVariant(), Path().withField(Fields::scriptElement),
628 FileLocations::ensure(currentNodeEl().fileLocations,
629 Path().withField(Fields::value))));
630 removeCurrentScriptNode({});
635 valueFromMultimap(containingObject.m_bindings, b.name(), currentIndex());
637 removeCurrentNode({});
639 Node::accept(el->parameters,
this);
641 if ((el->binding || el->statement)
642 && nodeStack.last().item.kind == DomType::PropertyDefinition) {
644 if (!pDef.annotations.isEmpty()) {
646 duplicate.setName(QLatin1String(
"duplicate"));
648 auto it = obj.m_bindings.find(pDef.name);
649 if (it != obj.m_bindings.end()) {
650 for (QmlObject ann : pDef.annotations) {
651 ann.addAnnotation(duplicate);
652 it->addAnnotation(currentEl<QmlObject>()
653 .path.withField(Fields::bindings)
655 .withIndex(obj.m_bindings.values(pDef.name).size() - 1),
662 QmlStackElement &sEl = nodeStack.last();
663 switch (sEl.item.kind) {
667 valueFromMultimap(obj.m_propertyDefs, pDef.name, sEl.path.last().headIndex());
669 *pDefPtr =
std::move(pDef);
673 MethodInfo *mPtr = valueFromMultimap(obj.m_methods, m.name, sEl.path.last().headIndex());
675 *mPtr =
std::move(m);
680 removeCurrentNode({});
685 endVisitForLists(list);
690 ++m_nestedFunctionDepth;
691 if (!m_enableScriptExpressions)
699 Q_ASSERT(!scriptNodeStack.isEmpty() || !fExpression->body);
701 if (fExpression->body) {
702 if (currentScriptNodeEl().isList()) {
706 combineLocations(fExpression->lbraceToken, fExpression->rbraceToken));
707 body->setStatements(currentScriptNodeEl().takeList());
708 if (
auto semanticScope = body->statements().semanticScope())
709 body->setSemanticScope(semanticScope);
711 removeCurrentScriptNode({});
714 auto result = currentScriptNodeEl().takeVariant();
715 removeCurrentScriptNode({});
718 Q_UNREACHABLE_RETURN({});
723 combineLocations(fExpression->lbraceToken, fExpression->rbraceToken));
729 --m_nestedFunctionDepth;
730 if (!m_enableScriptExpressions)
734 if (fExpression->identifierToken.isValid())
735 current->addLocation(IdentifierRegion, fExpression->identifierToken);
736 if (fExpression->functionToken.isValid())
737 current->addLocation(FunctionKeywordRegion, fExpression->functionToken);
738 if (fExpression->starToken.isValid())
739 current->addLocation(StarTokenRegion, fExpression->starToken);
740 if (fExpression->lparenToken.isValid())
741 current->addLocation(LeftParenthesisRegion, fExpression->lparenToken);
742 if (fExpression->rparenToken.isValid())
743 current->addLocation(RightParenthesisRegion, fExpression->rparenToken);
744 if (fExpression->lbraceToken.isValid())
745 current->addLocation(LeftBraceRegion, fExpression->lbraceToken);
746 if (fExpression->rbraceToken.isValid())
747 current->addLocation(RightBraceRegion, fExpression->rbraceToken);
748 if (fExpression->typeAnnotation) {
749 current->addLocation(TypeIdentifierRegion,
750 combineLocations(fExpression->typeAnnotation->type));
754 current->insertChild(Fields::body, prepareBodyForFunction(fExpression));
756 if (fExpression->typeAnnotation) {
758 current->insertChild(Fields::returnType, currentScriptNodeEl().takeVariant());
759 scriptNodeStack.removeLast();
761 if (fExpression->formals) {
763 current->insertChild(Fields::parameters, currentScriptNodeEl().takeList());
764 scriptNodeStack.removeLast();
767 if (!fExpression->name.isEmpty())
768 current->insertValue(Fields::name, fExpression->name);
770 pushScriptElement(current);
776 if (m_nestedFunctionDepth > 0) {
777 return visit(
static_cast<FunctionExpression *>(fDef));
779 ++m_nestedFunctionDepth;
780 const QStringView code(qmlFilePtr->code());
782 m.name = fDef->name.toString();
783 if (AST::TypeAnnotation *tAnn = fDef->typeAnnotation) {
784 if (AST::Type *t = tAnn->type)
785 m.typeName = typeToString(t);
788 m.methodType = MethodInfo::Method;
791 SourceLocation bodyLoc = fDef->body ? combineLocations(fDef->body)
792 : combineLocations(fDef->lbraceToken, fDef->rbraceToken);
794 code.mid(bodyLoc.offset, bodyLoc.length), qmlFilePtr->engine(), fDef->body,
795 qmlFilePtr->astComments(), ScriptExpression::ExpressionType::FunctionBody, bodyLoc);
797 if (fDef->typeAnnotation) {
798 SourceLocation typeLoc = combineLocations(fDef->typeAnnotation);
800 code.mid(typeLoc.offset, typeLoc.length), qmlFilePtr->engine(),
801 fDef->typeAnnotation, qmlFilePtr->astComments(),
802 ScriptExpression::ExpressionType::ReturnType, typeLoc);
807 pushEl(mPathFromOwner, *mPtr,
810 if (fDef->identifierToken.isValid())
814 if (fDef->functionToken.isValid())
816 if (fDef->starToken.isValid())
818 if (fDef->lparenToken.length != 0)
820 if (fDef->rparenToken.length != 0)
822 if (fDef->lbraceToken.length != 0)
824 if (fDef->rbraceToken.length != 0)
826 if (fDef->typeAnnotation)
829 AST::FormalParameterList *args = fDef->formals;
832 param.name = args->element->bindingIdentifier.toString();
833 if (AST::TypeAnnotation *tAnn = args->element->typeAnnotation) {
834 if (AST::Type *t = tAnn->type)
835 param.typeName = typeToString(t);
837 if (args->element->initializer) {
838 SourceLocation loc = combineLocations(args->element->initializer);
840 code.mid(loc.offset, loc.length), qmlFilePtr->engine(),
841 args->element->initializer, qmlFilePtr->astComments(),
842 ScriptExpression::ExpressionType::ArgInitializer, loc);
844 if (args->element->type == AST::PatternElement::SpreadElement)
846 SourceLocation parameterLoc = combineLocations(args->element);
848 code.mid(parameterLoc.offset, parameterLoc.length), qmlFilePtr->engine(),
849 args->element, qmlFilePtr->astComments(),
850 ScriptExpression::ExpressionType::ArgumentStructure, parameterLoc);
852 index_type idx = index_type(mInfo.parameters.size());
853 mInfo.parameters.append(param);
855 Path::fromField(Fields::parameters).withIndex(idx));
857 if (args->element->identifierToken.isValid())
859 if (args->element->typeAnnotation)
868 if (AST::cast<VariableStatement *>(el->sourceElement)) {
869 qmlFile.addError(astParseErrors().warning(
870 "JavaScript declarations are not allowed in QML elements"_L1));
878 if (
auto data = variant.data()) {
879 if (
auto genericElement =
880 std::get_if<std::shared_ptr<ScriptElements::GenericScriptElement>>(&*data)) {
889 if (m_nestedFunctionDepth > 1) {
890 endVisit(
static_cast<FunctionExpression *>(fDef));
893 --m_nestedFunctionDepth;
896 FileLocations::ensure(currentNodeEl().fileLocations, Path().withField(Fields::body));
897 const Path bodyPath =
Path().withField(Fields::scriptElement);
899 if (!m_enableScriptExpressions)
903 m.body->setScriptElement(
904 finalizeScriptExpression(prepareBodyForFunction(fDef), bodyPath, bodyTree));
906 if (fDef->typeAnnotation) {
908 Path().withField(Fields::returnType));
909 const Path pathToReturnType =
Path().withField(Fields::scriptElement);
913 finalizeScriptExpression(variant, pathToReturnType, argLoc);
914 m.returnType->setScriptElement(variant);
915 removeCurrentScriptNode({});
919 const auto parameterList = scriptNodeStack.takeLast().takeList();
920 const auto ¶meterQList = parameterList.qList();
921 size_t size = (size_t)parameterQList.size();
922 for (size_t idx = size - 1; idx < size; --idx) {
924 nodeStack.last().fileLocations,
925 Path().withField(Fields::parameters).withIndex(idx).withField(Fields::value));
926 const Path pathToArgument =
Path().withField(Fields::scriptElement);
929 setFormalParameterKind(variant);
930 finalizeScriptExpression(variant, pathToArgument, argLoc);
931 m.parameters[idx].value->setScriptElement(variant);
936 if (m_enableScriptExpressions && !scriptNodeStack.empty()) {
943 if (AST::cast<VariableStatement *>(el->sourceElement))
949 valueFromMultimap(obj.m_methods, m.name, nodeStack.last().path.last().headIndex());
958 scope.setName(toString(el->qualifiedTypeNameId));
962 if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last()) {
964 QList<QmlObject> *vals =
std::get<
Binding>(currentNode().value).arrayValue();
966 int idx = vals->size();
968 sPathFromOwner = currentNodeEl().path.withField(Fields::value).withIndex(idx);
969 sPtr = &((*vals)[idx]);
972 Q_ASSERT_X(
false, className,
973 "expected an array binding with a valid QList<QmlScope> as value");
976 Q_ASSERT_X(
false, className,
"expected an array binding as last node on the stack");
979 DomValue &containingObject = currentQmlObjectOrComponentEl().item;
980 switch (containingObject.kind) {
982 sPathFromOwner =
std::get<QmlComponent>(containingObject.value).addObject(scope, &sPtr);
985 sPathFromOwner =
std::get<
QmlObject>(containingObject.value).addChild(scope, &sPtr);
990 Path pathFromContainingObject = sPathFromOwner.mid(currentNodeEl().path.length());
992 FileLocations::ensure(currentNodeEl().fileLocations, pathFromContainingObject);
994 el->qualifiedTypeNameId->identifierToken);
996 Q_ASSERT_X(sPtr, className,
"could not recover new scope");
998 if (m_enableScriptExpressions) {
999 auto qmlObjectType = makeGenericScriptElement(el->qualifiedTypeNameId,
DomType::ScriptType);
1000 qmlObjectType->insertChild(Fields::typeName,
1001 fieldMemberExpressionForQualifiedId(el->qualifiedTypeNameId));
1004 sPathFromOwner.withField(Fields::nameIdentifiers), rootMap)
);
1006 pushEl(sPathFromOwner, *sPtr, el);
1008 if (el->initializer) {
1010 el->initializer->lbraceToken);
1012 el->initializer->rbraceToken);
1014 loadAnnotations(el);
1021 int idx = currentIndex();
1022 if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last() + 1) {
1025 QList<QmlObject> *vals = b.arrayValue();
1026 Q_ASSERT_X(vals, className,
1027 "expected an array binding with a valid QList<QmlScope> as value");
1030 Q_ASSERT_X(
false, className,
"expected an array binding as last node on the stack");
1033 DomValue &containingObject = currentNodeEl(1).item;
1034 Path p = currentNodeEl().path;
1035 switch (containingObject.kind) {
1037 if (p
[p
.length() - 2
] == Path::fromField(Fields::objects))
1038 std::get<QmlComponent>(containingObject.value).m_objects[idx] = obj;
1043 if (p
[p
.length() - 2
] == Path::fromField(Fields::children))
1044 std::get<
QmlObject>(containingObject.value).m_children[idx] = obj;
1056 const UiQualifiedId *identifiers,
Binding *bindingPtr)
1058 const bool skipBindingIdentifiers =
std::exchange(m_skipBindingIdentifiers,
false);
1059 if (!m_enableScriptExpressions || skipBindingIdentifiers)
1064 bindable, pathFromOwner.withField(Fields::bindingIdentifiers), rootMap)
);
1071 value.setName(toString(el->qualifiedTypeNameId));
1075 if (bPtr->name() == u"id")
1076 qmlFile.addError(std::move(astParseErrors()
1077 .warning(tr(
"id attributes should only be a lower case letter "
1078 "followed by letters, numbers or underscore, "
1079 "assuming they refer to an id property"))
1080 .withPath(bPathFromOwner)));
1081 setBindingIdentifiers(bPathFromOwner, el->qualifiedId, bPtr);
1083 pushEl(bPathFromOwner, *bPtr, el);
1089 loadAnnotations(el);
1091 Q_ASSERT_X(objValue, className,
"could not recover objectValue");
1092 objValue->setName(toString(el->qualifiedTypeNameId));
1094 if (m_enableScriptExpressions) {
1095 auto qmlObjectType = makeGenericScriptElement(el->qualifiedTypeNameId,
DomType::ScriptType);
1096 qmlObjectType->insertChild(Fields::typeName,
1097 fieldMemberExpressionForQualifiedId(el->qualifiedTypeNameId));
1100 bPathFromOwner.withField(Fields::value).withField(Fields::nameIdentifiers), rootMap)
);
1104 pushEl(bPathFromOwner.withField(Fields::value), *objValue, el->initializer);
1105 if (m_enableScriptExpressions && el->initializer) {
1107 el->initializer->lbraceToken);
1109 el->initializer->rbraceToken);
1122 index_type idx = currentNodeEl(1).path.last().headIndex();
1123 Binding *bPtr = valueFromMultimap(containingObj.m_bindings, b.name(), idx);
1132 ++m_nestedFunctionDepth;
1133 QStringView code = qmlFilePtr->code();
1134 SourceLocation loc = combineLocations(el->statement);
1136 code.mid(loc.offset, loc.length), qmlFilePtr->engine(), el->statement,
1137 qmlFilePtr->astComments(), ScriptExpression::ExpressionType::BindingExpression, loc);
1139 Binding *bindingPtr =
nullptr;
1140 Id *idPtr =
nullptr;
1142 if (bindingV.name() == u"id") {
1143 Node *exp = script->ast();
1144 if (ExpressionStatement *eStat = cast<ExpressionStatement *>(script->ast()))
1145 exp = eStat->expression;
1146 if (IdentifierExpression *iExp = cast<IdentifierExpression *>(exp)) {
1147 QmlStackElement &containingObjectEl = currentEl<
QmlObject>();
1149 QString idName = iExp->name.toString();
1150 Id idVal(idName, qmlFile.canonicalPath().withPath(containingObject.pathFromOwner()));
1151 idVal.value = script;
1152 containingObject.setIdStr(idName);
1154 combineLocations(el->qualifiedId));
1158 combineLocations(el->statement));
1159 QmlComponent &comp = current<QmlComponent>();
1161 QRegularExpression idRe(QRegularExpression::anchoredPattern(
1162 QStringLiteral(uR"([[:lower:]][[:lower:][:upper:]0-9_]*)")));
1163 auto m = idRe.matchView(iExp->name);
1164 if (!m.hasMatch()) {
1165 qmlFile.addError(std::move(
1167 .warning(tr(
"id attributes should only be a lower case letter "
1168 "followed by letters, numbers or underscore, not %1")
1170 .withPath(pathFromOwner)));
1175 Q_ASSERT_X(bindingPtr, className,
"binding could not be retrieved");
1176 qmlFile.addError(std::move(
1178 .warning(tr(
"id attributes should only be a lower case letter "
1179 "followed by letters, numbers or underscore, not %1 "
1180 "%2, assuming they refer to a property")
1181 .arg(script->code(), script->astRelocatableDump()))
1182 .withPath(pathFromOwner)));
1187 QmlStackElement &containingObjectEl = currentEl<
QmlObject>();
1189 Path pathFromContainingObject = pathFromOwner.mid(containingObjectEl.path.length());
1190 auto bindingFileLocation =
1193 el->qualifiedId->identifierToken);
1196 setBindingIdentifiers(pathFromOwner, el->qualifiedId, bindingPtr);
1198 Q_ASSERT_X(bindingPtr, className,
"binding could not be retrieved");
1201 pushEl(pathFromOwner, *bindingPtr, el);
1203 pushEl(pathFromOwner, *idPtr, el);
1206 loadAnnotations(el);
1214 if (m_enableScriptExpressions
1215 && (scriptNodeStack.size() != 1 || currentScriptNodeEl().isList()))
1217 if (m_enableScriptExpressions) {
1218 FileLocations::
Tree valueLoc = FileLocations::ensure(currentNodeEl().fileLocations,
1219 Path().withField(Fields::value));
1220 value->setScriptElement(finalizeScriptExpression(currentScriptNodeEl().takeVariant(),
1221 Path().withField(Fields::scriptElement),
1223 removeCurrentScriptNode({});
1229 --m_nestedFunctionDepth;
1230 DomValue &lastEl = currentNode();
1231 index_type idx = currentIndex();
1238 Binding *bPtr = valueFromMultimap(containingObject.m_bindings, b.name(), idx);
1242 Id &id =
std::get<
Id>(lastEl.value);
1244 setScriptExpression(id.value);
1246 QmlComponent &comp = current<QmlComponent>();
1247 Id *idPtr = valueFromMultimap(comp.m_ids, id.name, idx);
1254 if (m_enableScriptExpressions && !scriptNodeStack.empty()) {
1257 removeCurrentNode({});
1262 QList<QmlObject> value;
1265 Path bindingPathFromOwner =
1267 if (bindingV.name() == u"id")
1268 qmlFile.addError(std::move(
1270 .error(tr(
"id attributes should have only simple strings as values"))
1271 .withPath(bindingPathFromOwner)));
1273 setBindingIdentifiers(bindingPathFromOwner, el->qualifiedId, bindingPtr);
1275 pushEl(bindingPathFromOwner, *bindingPtr, el);
1277 loadAnnotations(el);
1279 createMap(currentNodeEl().fileLocations, Path::fromField(Fields::value),
nullptr);
1282 arrayBindingLevels.append(nodeStack.size());
1288 index_type idx = currentIndex();
1290 Binding *bPtr = valueFromMultimap(current<
QmlObject>().m_bindings, b.name(), idx);
1292 arrayBindingLevels.removeLast();
1298 endVisitForLists(list);
1308 endVisitForLists<AST::PatternElementList>(list, [](AST::PatternElementList *current) {
1310 toCollect +=
bool(current->elision);
1311 toCollect +=
bool(current->element);
1318 endVisitForLists(list);
1322
1323
1324
1325
1326
1330 expression->firstSourceLocation(), expression->lastSourceLocation());
1331 id->setName(expression->toString());
1338 if (!m_enableScriptExpressions)
1347 eDecl.setName(el->name.toString());
1349 Path enumPathFromOwner =
1351 pushEl(enumPathFromOwner, *ePtr, el);
1356 loadAnnotations(el);
1362 EnumDecl &e =
std::get<EnumDecl>(currentNode().value);
1364 valueFromMultimap(current<QmlComponent>().m_enumerations, e.name(), currentIndex());
1372 EnumItem it(el->member.toString(), el->value,
1375 EnumDecl &eDecl =
std::get<EnumDecl>(currentNode().value);
1377 const auto map = createMap(DomType::EnumItem, itPathFromDecl,
nullptr);
1378 if (el->commaToken.isValid())
1380 if (el->memberToken.isValid())
1382 if (el->equalToken.isValid())
1384 if (el->valueToken.isValid())
1387 map, MainRegion, combine(combine(el->memberToken, el->commaToken), el->valueToken));
1393 Node::accept(el->next,
this);
1398 QStringList els = current<QmlComponent>().name().split(QLatin1Char(
'.'));
1399 els.append(el->name.toString());
1400 QString cName = els.join(QLatin1Char(
'.'));
1401 QmlComponent *compPtr;
1402 Path p = qmlFilePtr->addComponent(QmlComponent(cName), AddOption::KeepExisting, &compPtr);
1404 if (m_enableScriptExpressions) {
1405 auto inlineComponentType =
1409 typeName->setName(el->name);
1410 inlineComponentType->insertChild(Fields::typeName,
1414 p.withField(Fields::nameIdentifiers), rootMap)
);
1417 pushEl(p, *compPtr, el);
1419 el->componentToken);
1421 loadAnnotations(el);
1427 QmlComponent &component =
std::get<QmlComponent>(currentNode().value);
1428 QStringList nameEls = component.name().split(QChar::fromLatin1(
'.'));
1429 QString key = nameEls.mid(1).join(QChar::fromLatin1(
'.'));
1430 QmlComponent *cPtr = valueFromMultimap(qmlFilePtr->lazyMembers().m_components, key, currentIndex());
1439 pDef.name = el->name.toString();
1442 Path pathFromOwner =
1444 createMap(DomType::PropertyDefinition, pathFromOwner, el);
1451 a.setName(QStringLiteral(u"@") + toString(el->qualifiedTypeNameId));
1453 DomValue &containingElement = currentNode();
1456 switch (containingElement.kind) {
1458 pathFromOwner =
std::get<
QmlObject>(containingElement.value).addAnnotation(a, &aPtr);
1461 pathFromOwner =
std::get<
Binding>(containingElement.value)
1462 .addAnnotation(currentNodeEl().path, a, &aPtr);
1466 std::get<
Id>(containingElement.value).addAnnotation(currentNodeEl().path, a, &aPtr);
1470 .addAnnotation(currentNodeEl().path, a, &aPtr);
1473 pathFromOwner =
std::get<
MethodInfo>(containingElement.value)
1474 .addAnnotation(currentNodeEl().path, a, &aPtr);
1477 qCWarning(domLog) <<
"Unexpected container object for annotation:"
1478 << domTypeToString(containingElement.kind);
1481 pushEl(pathFromOwner, *aPtr, el);
1487 DomValue &containingElement = currentNode(1);
1490 switch (containingElement.kind) {
1491 case DomType::QmlObject:
1492 std::get<QmlObject>(containingElement.value).m_annotations[currentIndex()] = a;
1494 case DomType::Binding:
1495 std::get<Binding>(containingElement.value).m_annotations[currentIndex()] = a;
1498 std::get<Id>(containingElement.value).annotations[currentIndex()] = a;
1500 case DomType::PropertyDefinition:
1501 std::get<PropertyDefinition>(containingElement.value).annotations[currentIndex()] = a;
1503 case DomType::MethodInfo:
1504 std::get<MethodInfo>(containingElement.value).annotations[currentIndex()] = a;
1514 qmlFile.addError(astParseErrors().error(
1515 tr(
"Maximum statement or expression depth exceeded in QmlDomAstCreator")));
1520 endVisitForLists(list);
1525 if (!m_enableScriptExpressions)
1533 if (!m_enableScriptExpressions)
1537 current->addLocation(OperatorTokenRegion, exp->operatorToken);
1539 current->setRight(currentScriptNodeEl().takeVariant());
1540 removeCurrentScriptNode({});
1542 current->setLeft(currentScriptNodeEl().takeVariant());
1543 removeCurrentScriptNode({});
1545 pushScriptElement(current);
1550 if (!m_enableScriptExpressions)
1558 if (!m_enableScriptExpressions)
1563 if (block->statements) {
1565 current->setStatements(currentScriptNodeEl().takeList());
1569 pushScriptElement(current);
1574 if (!m_enableScriptExpressions)
1582 if (!m_enableScriptExpressions)
1586 current->addLocation(FileLocationRegion::ForKeywordRegion, forStatement->forToken);
1587 current->addLocation(FileLocationRegion::LeftParenthesisRegion, forStatement->lparenToken);
1588 current->addLocation(FileLocationRegion::FirstSemicolonTokenRegion,
1589 forStatement->firstSemicolonToken);
1590 current->addLocation(FileLocationRegion::SecondSemicolonRegion,
1591 forStatement->secondSemicolonToken);
1592 current->addLocation(FileLocationRegion::RightParenthesisRegion, forStatement->rparenToken);
1594 if (forStatement->statement) {
1596 current->setBody(currentScriptNodeEl().takeVariant());
1597 removeCurrentScriptNode(
std::nullopt);
1600 if (forStatement->expression) {
1602 current->setExpression(currentScriptNodeEl().takeVariant());
1603 removeCurrentScriptNode(
std::nullopt);
1606 if (forStatement->condition) {
1608 current->setCondition(currentScriptNodeEl().takeVariant());
1609 removeCurrentScriptNode(
std::nullopt);
1612 if (forStatement->declarations) {
1614 auto variableDeclaration = makeGenericScriptElement(forStatement->declarations,
1620 variableDeclaration->insertChild(Fields::declarations,
std::move(list));
1621 removeCurrentScriptNode({});
1625 if (
auto pe = forStatement->declarations->declaration;
1626 pe && pe->declarationKindToken.isValid()) {
1627 current->addLocation(FileLocationRegion::TypeIdentifierRegion,
1628 pe->declarationKindToken);
1632 if (forStatement->initialiser) {
1634 current->setInitializer(currentScriptNodeEl().takeVariant());
1635 removeCurrentScriptNode(
std::nullopt);
1637 pushScriptElement(current);
1642 if (!m_enableScriptExpressions)
1646 current->setName(expression->name);
1647 pushScriptElement(current);
1653 if (!m_enableScriptExpressions)
1657 current->setLiteralValue(expression->value);
1658 pushScriptElement(current);
1664 if (!m_enableScriptExpressions)
1667 pushScriptElement(makeStringLiteral(expression->value, expression));
1673 if (!m_enableScriptExpressions)
1677 current->setLiteralValue(
nullptr);
1678 pushScriptElement(current);
1684 if (!m_enableScriptExpressions)
1688 current->setLiteralValue(
true);
1689 pushScriptElement(current);
1695 if (!m_enableScriptExpressions)
1699 current->setLiteralValue(
false);
1700 pushScriptElement(current);
1706 if (!m_enableScriptExpressions)
1710 current->setName(expression->id);
1711 pushScriptElement(current);
1717 if (!m_enableScriptExpressions)
1720 pushScriptElement(makeStringLiteral(expression->id, expression));
1726 if (!m_enableScriptExpressions)
1735 if (!m_enableScriptExpressions)
1739 current->insertValue(Fields::regExpPattern, literal->pattern);
1740 current->insertValue(Fields::regExpFlags, literal->flags);
1741 pushScriptElement(current);
1748 if (!m_enableScriptExpressions)
1752 if (expression->thisToken.isValid())
1753 current->addLocation(ThisKeywordRegion, expression->thisToken);
1754 pushScriptElement(current);
1760 if (!m_enableScriptExpressions)
1764 if (expression->superToken.isValid())
1765 current->addLocation(SuperKeywordRegion, expression->superToken);
1766 pushScriptElement(current);
1772 if (!m_enableScriptExpressions)
1776 current->setLiteralValue(expression->id);
1777 pushScriptElement(current);
1783 if (!m_enableScriptExpressions)
1792 const std::function<
int(T *)> &scriptElementsPerEntry)
1794 if (!m_enableScriptExpressions)
1797 auto current = makeScriptList(list);
1798 for (
auto it = list; it; it = it->next) {
1799 const int entriesToCollect = scriptElementsPerEntry ? scriptElementsPerEntry(it) : 1;
1800 for (
int i = 0; i < entriesToCollect; ++i) {
1802 auto last = scriptNodeStack.takeLast();
1804 current.append(last.takeList());
1806 current.append(last.takeVariant());
1811 pushScriptElement(current);
1816 endVisitForLists(list);
1821 if (!m_enableScriptExpressions)
1824 auto currentList = makeScriptList(list);
1826 for (
auto it = list; it; it = it->next) {
1830 pushScriptElement(currentList);
1838 if (!m_enableScriptExpressions)
1845
1846
1847
1848
1850 AST::PatternElement *pe,
1853 if (pe->equalToken.isValid())
1854 current->addLocation(FileLocationRegion::EqualTokenRegion, pe->equalToken);
1856 if (pe->identifierToken.isValid() && !pe->bindingIdentifier.isEmpty()) {
1859 identifier->setName(pe->bindingIdentifier);
1860 current->insertChild(Fields::identifier, ScriptElementVariant::fromElement(identifier));
1862 if (pe->initializer) {
1864 current->insertChild(Fields::initializer, scriptNodeStack.last().takeVariant());
1865 scriptNodeStack.removeLast();
1867 if (pe->typeAnnotation) {
1869 current->insertChild(Fields::type, scriptNodeStack.last().takeVariant());
1870 scriptNodeStack.removeLast();
1872 if (pe->bindingTarget) {
1874 current->insertChild(Fields::bindingElement, scriptNodeStack.last().takeVariant());
1875 scriptNodeStack.removeLast();
1881 if (!m_enableScriptExpressions)
1885 endVisitHelper(pe, element);
1887 if (!m_enableScriptExpressions)
1890 pushScriptElement(element);
1895 if (!m_enableScriptExpressions)
1903 if (!m_enableScriptExpressions)
1907 current->addLocation(LeftParenthesisRegion, ifStatement->lparenToken);
1908 current->addLocation(RightParenthesisRegion, ifStatement->rparenToken);
1909 current->addLocation(ElseKeywordRegion, ifStatement->elseToken);
1910 current->addLocation(IfKeywordRegion, ifStatement->ifToken);
1912 if (ifStatement->ko) {
1914 current->setAlternative(scriptNodeStack.last().takeVariant());
1915 scriptNodeStack.removeLast();
1918 if (ifStatement->ok) {
1920 current->setConsequence(scriptNodeStack.last().takeVariant());
1921 scriptNodeStack.removeLast();
1923 if (ifStatement->expression) {
1925 current->setCondition(scriptNodeStack.last().takeVariant());
1926 scriptNodeStack.removeLast();
1929 pushScriptElement(current);
1934 if (!m_enableScriptExpressions)
1942 if (!m_enableScriptExpressions)
1946 current->addLocation(ReturnKeywordRegion, returnStatement->returnToken);
1948 if (returnStatement->expression) {
1950 current->setExpression(currentScriptNodeEl().takeVariant());
1951 removeCurrentScriptNode({});
1954 pushScriptElement(current);
1959 if (!m_enableScriptExpressions)
1967 if (!m_enableScriptExpressions)
1971 current->addLocation(YieldKeywordRegion, yExpression->yieldToken);
1973 if (yExpression->expression) {
1975 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
1976 removeCurrentScriptNode({});
1979 pushScriptElement(current);
1984 if (!m_enableScriptExpressions)
1992 if (!m_enableScriptExpressions)
1997 current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->dotToken);
1999 if (expression->base) {
2001 current->setLeft(currentScriptNodeEl().takeVariant());
2002 removeCurrentScriptNode({});
2005 auto scriptIdentifier =
2007 scriptIdentifier->setName(expression->name);
2010 pushScriptElement(current);
2015 if (!m_enableScriptExpressions)
2023 if (!m_enableScriptExpressions)
2028 current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->lbracketToken);
2030 if (expression->expression) {
2034 current->setRight(currentScriptNodeEl().takeVariant());
2035 removeCurrentScriptNode({});
2038 if (expression->base) {
2040 current->setLeft(currentScriptNodeEl().takeVariant());
2041 removeCurrentScriptNode({});
2044 pushScriptElement(current);
2049 if (!m_enableScriptExpressions)
2057 if (!m_enableScriptExpressions)
2061 current->addLocation(LeftParenthesisRegion, exp->lparenToken);
2062 current->addLocation(RightParenthesisRegion, exp->rparenToken);
2064 if (exp->arguments) {
2066 current->insertChild(Fields::arguments, currentScriptNodeEl().takeList());
2067 removeCurrentScriptNode({});
2070 current->insertChild(Fields::arguments,
2076 current->insertChild(Fields::callee, currentScriptNodeEl().takeVariant());
2077 removeCurrentScriptNode({});
2080 pushScriptElement(current);
2085 if (!m_enableScriptExpressions)
2093 if (!m_enableScriptExpressions)
2098 if (exp->elements) {
2102 current->insertChild(Fields::elements,
std::move(list));
2104 removeCurrentScriptNode({});
2107 current->insertChild(Fields::elements,
2111 pushScriptElement(current);
2116 if (!m_enableScriptExpressions)
2124 if (!m_enableScriptExpressions)
2129 if (exp->properties) {
2131 current->insertChild(Fields::properties, currentScriptNodeEl().takeList());
2132 removeCurrentScriptNode({});
2135 current->insertChild(Fields::properties,
2139 pushScriptElement(current);
2144 if (!m_enableScriptExpressions)
2152 if (!m_enableScriptExpressions)
2158 endVisitHelper(
static_cast<PatternElement *>(exp), current);
2161 if (!m_enableScriptExpressions)
2166 current->insertChild(Fields::name, currentScriptNodeEl().takeVariant());
2167 removeCurrentScriptNode({});
2170 pushScriptElement(current);
2175 if (!m_enableScriptExpressions)
2183 if (!m_enableScriptExpressions)
2187 current->addLocation(FileLocationRegion::TypeIdentifierRegion, statement->declarationKindToken);
2189 if (statement->declarations) {
2195 current->insertChild(Fields::declarations,
std::move(list));
2197 removeCurrentScriptNode({});
2200 pushScriptElement(current);
2205 if (!m_enableScriptExpressions)
2213 if (!m_enableScriptExpressions)
2218 if (exp->typeArgument) {
2219 current->insertChild(Fields::typeArgumentName,
2220 fieldMemberExpressionForQualifiedId(exp->typeArgument));
2221 current->addLocation(FileLocationRegion::IdentifierRegion, combineLocations(exp->typeArgument));
2225 current->insertChild(Fields::typeName, fieldMemberExpressionForQualifiedId(exp->typeId));
2226 current->addLocation(FileLocationRegion::TypeIdentifierRegion, combineLocations(exp->typeId));
2229 pushScriptElement(current);
2234 if (!m_enableScriptExpressions)
2242 if (!m_enableScriptExpressions)
2246 current->addLocation(DefaultKeywordRegion, exp->defaultToken);
2247 current->addLocation(ColonTokenRegion, exp->colonToken);
2249 if (exp->statements) {
2251 current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
2252 removeCurrentScriptNode({});
2255 pushScriptElement(current);
2260 if (!m_enableScriptExpressions)
2268 if (!m_enableScriptExpressions)
2272 current->addLocation(FileLocationRegion::CaseKeywordRegion, exp->caseToken);
2273 current->addLocation(FileLocationRegion::ColonTokenRegion, exp->colonToken);
2275 if (exp->statements) {
2277 current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
2278 removeCurrentScriptNode({});
2281 if (exp->expression) {
2283 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2284 removeCurrentScriptNode({});
2287 pushScriptElement(current);
2292 if (!m_enableScriptExpressions)
2300 if (!m_enableScriptExpressions)
2303 auto current = makeScriptList(list);
2305 for (
auto it = list; it; it = it->next) {
2307 current.append(scriptNodeStack.takeLast().takeVariant());
2311 pushScriptElement(current);
2316 if (!m_enableScriptExpressions)
2324 if (!m_enableScriptExpressions)
2328 current->addLocation(FileLocationRegion::LeftBraceRegion, exp->lbraceToken);
2329 current->addLocation(FileLocationRegion::RightBraceRegion, exp->rbraceToken);
2331 if (exp->moreClauses) {
2333 current->insertChild(Fields::moreCaseClauses, currentScriptNodeEl().takeList());
2334 removeCurrentScriptNode({});
2337 if (exp->defaultClause) {
2339 current->insertChild(Fields::defaultClause, currentScriptNodeEl().takeVariant());
2340 removeCurrentScriptNode({});
2345 current->insertChild(Fields::caseClauses, currentScriptNodeEl().takeList());
2346 removeCurrentScriptNode({});
2348 pushScriptElement(current);
2353 if (!m_enableScriptExpressions)
2361 if (!m_enableScriptExpressions)
2365 current->addLocation(FileLocationRegion::SwitchKeywordRegion, exp->switchToken);
2366 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2367 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2371 current->insertChild(Fields::caseBlock, currentScriptNodeEl().takeVariant());
2372 removeCurrentScriptNode({});
2374 if (exp->expression) {
2376 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2377 removeCurrentScriptNode({});
2380 pushScriptElement(current);
2385 if (!m_enableScriptExpressions)
2393 if (!m_enableScriptExpressions)
2397 current->addLocation(FileLocationRegion::WhileKeywordRegion, exp->whileToken);
2398 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2399 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2401 if (exp->statement) {
2403 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2404 removeCurrentScriptNode({});
2407 if (exp->expression) {
2409 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2410 removeCurrentScriptNode({});
2413 pushScriptElement(current);
2418 if (!m_enableScriptExpressions)
2426 if (!m_enableScriptExpressions)
2430 current->addLocation(FileLocationRegion::DoKeywordRegion, exp->doToken);
2431 current->addLocation(FileLocationRegion::WhileKeywordRegion, exp->whileToken);
2432 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2433 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2435 if (exp->expression) {
2437 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2438 removeCurrentScriptNode({});
2441 if (exp->statement) {
2443 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2444 removeCurrentScriptNode({});
2447 pushScriptElement(current);
2452 if (!m_enableScriptExpressions)
2460 if (!m_enableScriptExpressions)
2464 current->addLocation(FileLocationRegion::ForKeywordRegion, exp->forToken);
2465 current->addLocation(FileLocationRegion::InOfTokenRegion, exp->inOfToken);
2466 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2467 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2469 if (exp->statement) {
2471 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2472 removeCurrentScriptNode({});
2474 if (exp->expression) {
2476 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2477 removeCurrentScriptNode({});
2482 current->insertChild(Fields::bindingElement, currentScriptNodeEl().takeVariant());
2483 removeCurrentScriptNode({});
2485 if (
auto pe = AST::cast<PatternElement *>(exp->lhs);
2486 pe && pe->declarationKindToken.isValid()) {
2487 current->addLocation(FileLocationRegion::TypeIdentifierRegion,
2488 pe->declarationKindToken);
2492 pushScriptElement(current);
2500 if (m_enableScriptExpressions)
2511 if (!m_enableScriptExpressions)
2515 current->insertChild(Fields::templateLiteral, scriptNodeStack.takeLast().takeVariant());
2517 current->insertChild(Fields::callee, scriptNodeStack.takeLast().takeVariant());
2518 pushScriptElement(current);
2522
2523
2524
2525
2526
2527enum TemplatePartPosition : quint8 {
2533Q_DECLARE_FLAGS(TemplatePartPositions, TemplatePartPosition)
2536
2537
2538
2539
2540static void extractDollarBraceSourceLocationInto(
2542 const SourceLocation &toBeSplit, QStringView code,
2543 TemplatePartPositions templatePartLocation)
2545 if (templatePartLocation & AtEnd || !currentExpression)
2548 const auto offset = toBeSplit.offset + toBeSplit.length - 2;
2549 constexpr auto length = quint32(
std::char_traits<
char>::length(
"${"));
2550 const auto [row, column] = SourceLocation::rowAndColumnFrom(code, offset, toBeSplit);
2551 currentExpression->addLocation(FileLocationRegion::DollarLeftBraceTokenRegion,
2552 SourceLocation{ offset, length, row, column });
2557
2558
2559
2560static void extractRightBacktickSourceLocationInto(
2562 const SourceLocation &toBeSplit, QStringView code,
2563 TemplatePartPositions templatePartLocation)
2565 if (!(templatePartLocation & AtEnd))
2568 const auto offset = toBeSplit.offset + toBeSplit.length - 1;
2569 constexpr auto length = quint32(
std::char_traits<
char>::length(
"`"));
2570 const auto [row, column] = SourceLocation::rowAndColumnFrom(code, offset, toBeSplit);
2571 currentTemplate->addLocation(FileLocationRegion::RightBacktickTokenRegion,
2572 SourceLocation{ offset, length, row, column });
2576
2577
2578
2579static void extractLeftBacktickSourceLocationInto(
2581 const SourceLocation &toBeSplit, TemplatePartPositions templatePartLocation)
2583 if (!(templatePartLocation & AtBeginning))
2586 constexpr auto length = quint32(
std::char_traits<
char>::length(
"`"));
2587 const QQmlJS::SourceLocation leftBacktick{ toBeSplit.offset, length, toBeSplit.startLine,
2588 toBeSplit.startColumn };
2589 currentTemplate->addLocation(FileLocationRegion::LeftBacktickTokenRegion, leftBacktick);
2593
2594
2595
2596
2597static SourceLocation extractRightBraceSourceLocation(
const SourceLocation &toBeSplit,
2598 TemplatePartPositions templatePartLocation)
2600 if (templatePartLocation & AtBeginning)
2601 return SourceLocation{};
2604 return SourceLocation{ toBeSplit.offset, 1, toBeSplit.startLine, toBeSplit.startColumn };
2608
2609
2610
2611
2612static SourceLocation extractStringLocation(
const SourceLocation &toBeSplit, QStringView code,
2613 TemplatePartPositions location)
2617 const quint32 length = toBeSplit.length - (location & AtEnd ? 2 : 3);
2618 const quint32 offset = toBeSplit.offset + 1;
2619 const auto [row, column] = SourceLocation::rowAndColumnFrom(code, offset, toBeSplit);
2620 return SourceLocation{ offset, length, row, column };
2625 if (!m_enableScriptExpressions)
2630 auto currentList = makeScriptList(literal);
2633 const auto children = [&literal]() {
2634 std::vector<AST::TemplateLiteral *> result;
2635 for (
auto it = literal; it; it = it->next) {
2636 result.push_back(it);
2641 SourceLocation rightBrace;
2642 for (
auto it = children.crbegin(); it != children.crend(); ++it) {
2644 const QQmlJS::SourceLocation toBeSplit = (*it)->literalToken;
2647 if ((*it)->expression) {
2649 currentExpression = makeGenericScriptElement((*it)->expression,
2652 currentExpression->insertChild(Fields::expression,
2653 scriptNodeStack.takeLast().takeVariant());
2654 if (rightBrace.isValid()) {
2655 currentExpression->addLocation(FileLocationRegion::RightBraceRegion,
2656 std::exchange(rightBrace, SourceLocation{}));
2661 if (!toBeSplit.isValid())
2664 const TemplatePartPositions location = [&it, &children]() {
2665 TemplatePartPositions result;
2666 if (it == children.crbegin())
2668 if (it ==
std::prev(children.crend()))
2669 result |= AtBeginning;
2673 extractRightBacktickSourceLocationInto(currentTemplate, toBeSplit, qmlFilePtr->code(),
2675 extractLeftBacktickSourceLocationInto(currentTemplate, toBeSplit, location);
2677 extractDollarBraceSourceLocationInto(currentExpression, toBeSplit, qmlFilePtr->code(),
2679 rightBrace = extractRightBraceSourceLocation(toBeSplit, location);
2681 if ((*it)->rawValue.isEmpty())
2684 const SourceLocation stringLocation =
2685 extractStringLocation(toBeSplit, qmlFilePtr->code(), location);
2686 auto currentString =
2688 currentString->insertValue(Fields::value, (*it)->rawValue);
2692 currentList.reverse();
2694 currentTemplate->insertChild(Fields::components, currentList);
2695 pushScriptElement(currentTemplate);
2700 return m_enableScriptExpressions;
2705 if (!m_enableScriptExpressions)
2709 current->addLocation(FileLocationRegion::TryKeywordRegion, statement->tryToken);
2711 if (
auto exp = statement->finallyExpression) {
2712 current->addLocation(FileLocationRegion::FinallyKeywordRegion, exp->finallyToken);
2715 current->insertChild(Fields::finallyBlock, currentScriptNodeEl().takeVariant());
2716 removeCurrentScriptNode({});
2719 if (
auto exp = statement->catchExpression) {
2720 current->addLocation(FileLocationRegion::CatchKeywordRegion, exp->catchToken);
2721 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2722 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2725 current->insertChild(Fields::catchBlock, currentScriptNodeEl().takeVariant());
2726 removeCurrentScriptNode({});
2728 current->insertChild(Fields::catchParameter, currentScriptNodeEl().takeVariant());
2729 removeCurrentScriptNode({});
2732 if (statement->statement) {
2734 current->insertChild(Fields::block, currentScriptNodeEl().takeVariant());
2735 removeCurrentScriptNode({});
2738 pushScriptElement(current);
2744 return m_enableScriptExpressions;
2755 return m_enableScriptExpressions;
2765 return m_enableScriptExpressions;
2770 if (!m_enableScriptExpressions)
2774 current->addLocation(FileLocationRegion::ThrowKeywordRegion, statement->throwToken);
2776 if (statement->expression) {
2778 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2779 removeCurrentScriptNode({});
2782 pushScriptElement(current);
2787 return m_enableScriptExpressions;
2792 if (!m_enableScriptExpressions)
2796 current->addLocation(FileLocationRegion::ColonTokenRegion, statement->colonToken);
2799 label->setName(statement->label);
2803 if (statement->statement) {
2805 current->insertChild(Fields::statement, currentScriptNodeEl().takeVariant());
2806 removeCurrentScriptNode({});
2809 pushScriptElement(current);
2814 return m_enableScriptExpressions;
2819 if (!m_enableScriptExpressions)
2823 current->addLocation(FileLocationRegion::BreakKeywordRegion, statement->breakToken);
2825 if (!statement->label.isEmpty()) {
2828 label->setName(statement->label);
2832 pushScriptElement(current);
2837 return m_enableScriptExpressions;
2842 if (!m_enableScriptExpressions)
2846 current->addLocation(OperatorTokenRegion, commaExpression->commaToken);
2848 if (commaExpression->right) {
2850 current->setRight(currentScriptNodeEl().takeVariant());
2851 removeCurrentScriptNode({});
2854 if (commaExpression->left) {
2856 current->setLeft(currentScriptNodeEl().takeVariant());
2857 removeCurrentScriptNode({});
2860 pushScriptElement(current);
2865 return m_enableScriptExpressions;
2870 if (!m_enableScriptExpressions)
2874 current->addLocation(FileLocationRegion::QuestionMarkTokenRegion, expression->questionToken);
2875 current->addLocation(FileLocationRegion::ColonTokenRegion, expression->colonToken);
2877 if (expression->ko) {
2879 current->insertChild(Fields::alternative, currentScriptNodeEl().takeVariant());
2880 removeCurrentScriptNode({});
2883 if (expression->ok) {
2885 current->insertChild(Fields::consequence, currentScriptNodeEl().takeVariant());
2886 removeCurrentScriptNode({});
2889 if (expression->expression) {
2891 current->insertChild(Fields::condition, currentScriptNodeEl().takeVariant());
2892 removeCurrentScriptNode({});
2895 pushScriptElement(current);
2900 return m_enableScriptExpressions;
2905 if (!m_enableScriptExpressions)
2909 current->addLocation(FileLocationRegion::ContinueKeywordRegion, statement->continueToken);
2911 if (!statement->label.isEmpty()) {
2914 label->setName(statement->label);
2918 pushScriptElement(current);
2922
2923
2924
2925
2927QQmlDomAstCreatorBase::makeUnaryExpression(AST::Node *expression, QQmlJS::SourceLocation operatorToken,
2928 bool hasExpression, UnaryExpressionKind kind)
2930 const DomType type = [&kind]() {
2940 auto current = makeGenericScriptElement(expression, type);
2941 current->addLocation(FileLocationRegion::OperatorTokenRegion, operatorToken);
2943 if (hasExpression) {
2948 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2949 removeCurrentScriptNode({});
2957 return m_enableScriptExpressions;
2962 if (!m_enableScriptExpressions)
2966 makeUnaryExpression(statement, statement->minusToken, statement->expression, Prefix);
2970 pushScriptElement(current);
2975 return m_enableScriptExpressions;
2980 if (!m_enableScriptExpressions)
2984 makeUnaryExpression(statement, statement->plusToken, statement->expression, Prefix);
2988 pushScriptElement(current);
2993 return m_enableScriptExpressions;
2998 if (!m_enableScriptExpressions)
3002 makeUnaryExpression(statement, statement->tildeToken, statement->expression, Prefix);
3006 pushScriptElement(current);
3011 return m_enableScriptExpressions;
3016 if (!m_enableScriptExpressions)
3020 makeUnaryExpression(statement, statement->notToken, statement->expression, Prefix);
3024 pushScriptElement(current);
3029 return m_enableScriptExpressions;
3034 if (!m_enableScriptExpressions)
3038 makeUnaryExpression(statement, statement->typeofToken, statement->expression, Prefix);
3042 pushScriptElement(current);
3047 return m_enableScriptExpressions;
3052 if (!m_enableScriptExpressions)
3056 makeUnaryExpression(statement, statement->deleteToken, statement->expression, Prefix);
3060 pushScriptElement(current);
3065 return m_enableScriptExpressions;
3070 if (!m_enableScriptExpressions)
3074 makeUnaryExpression(statement, statement->voidToken, statement->expression, Prefix);
3078 pushScriptElement(current);
3083 return m_enableScriptExpressions;
3088 if (!m_enableScriptExpressions)
3092 makeUnaryExpression(statement, statement->decrementToken, statement->base, Postfix);
3096 pushScriptElement(current);
3101 return m_enableScriptExpressions;
3106 if (!m_enableScriptExpressions)
3110 makeUnaryExpression(statement, statement->incrementToken, statement->base, Postfix);
3114 pushScriptElement(current);
3119 return m_enableScriptExpressions;
3124 if (!m_enableScriptExpressions)
3127 auto current = makeUnaryExpression(statement, statement->incrementToken, statement->expression,
3132 pushScriptElement(current);
3137 return m_enableScriptExpressions;
3142 if (!m_enableScriptExpressions)
3146 current->addLocation(FileLocationRegion::SemicolonTokenRegion, statement->semicolonToken);
3147 pushScriptElement(current);
3152 return m_enableScriptExpressions;
3157 if (!m_enableScriptExpressions)
3161 current->addLocation(FileLocationRegion::LeftParenthesisRegion, expression->lparenToken);
3162 current->addLocation(FileLocationRegion::RightParenthesisRegion, expression->rparenToken);
3164 if (expression->expression) {
3166 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
3167 removeCurrentScriptNode({});
3170 pushScriptElement(current);
3175 return m_enableScriptExpressions;
3180 if (!m_enableScriptExpressions)
3184 current->addLocation(FileLocationRegion::NewKeywordRegion, expression->newToken);
3186 if (expression->expression) {
3188 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
3189 removeCurrentScriptNode({});
3192 pushScriptElement(current);
3197 return m_enableScriptExpressions;
3202 if (!m_enableScriptExpressions)
3206 current->addLocation(FileLocationRegion::NewKeywordRegion, expression->newToken);
3207 current->addLocation(FileLocationRegion::LeftParenthesisRegion, expression->lparenToken);
3208 current->addLocation(FileLocationRegion::RightParenthesisRegion, expression->rparenToken);
3210 if (expression->arguments) {
3212 current->insertChild(Fields::arguments, scriptNodeStack.takeLast().takeList());
3214 if (expression->base) {
3216 current->insertChild(Fields::base, scriptNodeStack.takeLast().takeVariant());
3219 pushScriptElement(current);
3224 if (!m_enableScriptExpressions)
3229 if (ast->statement) {
3231 current->insertChild(Fields::statement, scriptNodeStack.takeLast().takeVariant());
3233 if (ast->expression) {
3235 current->insertChild(Fields::expression, scriptNodeStack.takeLast().takeVariant());
3238 pushScriptElement(current);
3243 return m_enableScriptExpressions;
3248 if (!m_enableScriptExpressions)
3251 auto current = makeUnaryExpression(statement, statement->decrementToken, statement->expression,
3256 pushScriptElement(current);
3259static const DomEnvironment *environmentFrom(
MutableDomItem &qmlFile)
3261 auto top = qmlFile
.top();
3265 auto domEnvironment = top.as<DomEnvironment>();
3266 if (!domEnvironment) {
3269 return domEnvironment;
3274 if (
auto env = environmentFrom(qmlFile))
3275 return env->qmldirFiles();
3282 QQmlJSLogger *logger,
3283 QQmlJSImporter *importer)
3296 bool QQmlDomAstCreatorWithQQmlJSScope::visit(name *node)
3298 return visitT(node);
3300 void QQmlDomAstCreatorWithQQmlJSScope::endVisit(name *node)
3304QQmlJSASTClassListToVisit
3309 const QQmlJSScope::ConstPtr scope = m_scopeCreator.m_currentScope;
3310 if (!m_domCreator.scriptNodeStack.isEmpty()) {
3311 auto topOfStack = m_domCreator.currentScriptNodeEl();
3312 switch (topOfStack.kind) {
3315 if (scope->scopeType() == QQmlJSScope::ScopeType::QMLScope)
3316 m_domCreator.currentScriptNodeEl().setSemanticScope(scope);
3319 case DomType::ScriptBlockStatement:
3320 case DomType::ScriptForStatement:
3321 case DomType::ScriptForEachStatement:
3322 case DomType::ScriptDoWhileStatement:
3323 case DomType::ScriptWhileStatement:
3325 m_domCreator.currentScriptNodeEl().setSemanticScope(scope);
3330 auto element = m_domCreator.currentScriptNodeEl().value;
3332 if (!scriptElementVariant || !scriptElementVariant->data())
3334 scriptElementVariant->visit([](
auto &&e) {
3335 using U = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
3339 if constexpr (std::is_same_v<U,
3340 ScriptElement::PointerType<
3341 ScriptElements::GenericScriptElement>>) {
3342 if (
auto bodyPtr = e->elementChild(Fields::body)) {
3343 const auto bodyScope = bodyPtr.base()->semanticScope();
3344 e->setSemanticScope(bodyScope);
3355 }
else if (!m_domCreator.nodeStack.isEmpty()) {
3357 [&scope](
auto &&e) {
3358 using U = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
3360 if constexpr (std::is_same_v<U, QmlObject>) {
3361 e.setSemanticScope(scope);
3362 }
else if constexpr (std::is_same_v<U, QmlComponent>) {
3363 e.setSemanticScope(scope);
3364 }
else if constexpr (std::is_same_v<U, MethodInfo>) {
3366 if (
auto scriptElement = e.body->scriptElement()) {
3367 scriptElement.base()->setSemanticScope(scope);
3370 e.setSemanticScope(scope);
3373 m_domCreator.currentNodeEl().item.value);
3379 const QQmlJSScope::ConstPtr scope = m_scopeCreator.m_currentScope;
3383 if (m_domCreator.nodeStack.size() > 1
3384 && m_domCreator.nodeStack.last().item.kind == DomType::Binding) {
3386 [&scope](
auto &&e) {
3387 using U = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
3388 if constexpr (std::is_same_v<U, PropertyDefinition>) {
3394 const bool usePropertyDefinitionScopeInsteadOfTheBindingScope =
3395 QQmlSA::isFunctionScope(scope->scopeType())
3396 && scope->parentScope()
3397 && scope->parentScope()->scopeType() == QQmlSA::ScopeType::QMLScope;
3398 e.setSemanticScope(usePropertyDefinitionScopeInsteadOfTheBindingScope
3399 ? scope->parentScope()
3403 m_domCreator.currentNodeEl(1).item.value);
3405 if (m_domCreator.nodeStack.size() > 0) {
3407 [&scope](
auto &&e) {
3408 using U = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
3409 if constexpr (std::is_same_v<U, PropertyDefinition>) {
3410 e.setSemanticScope(scope);
3411 Q_ASSERT(e.semanticScope());
3412 }
else if constexpr (std::is_same_v<U, MethodInfo>) {
3413 if (e.methodType == MethodInfo::Signal) {
3414 e.setSemanticScope(scope);
3418 m_domCreator.currentNodeEl().item.value);
3427 bool QQmlDomAstCreator::visit(AST::name *ast)
3429 return QQmlDomAstCreatorBase::visit(ast) && visitWithCustomListIteration(ast, this);
3437#undef Q_SCRIPTELEMENT_DISABLE
3438#undef Q_SCRIPTELEMENT_EXIT_IF
Binding & operator=(const Binding &)
void setBindingIdentifiers(const ScriptElementVariant &bindingIdentifiers)
QmlObject * objectValue()
std::shared_ptr< ScriptExpression > scriptExpressionValue()
Path addValue(const EnumItem &value)
Represents a set of tags grouping a set of related error messages.
TypeAnnotationStyle typeAnnotationStyle
Path operator[](int i) const
Path mid(int offset, int length) const
void setNameIdentifiers(const ScriptElementVariant &name)
QQmlDomAstCreatorBase(const MutableDomItem &qmlFile)
void endVisit(AST::UiProgram *) override
bool stackHasScriptList() const
void throwRecursionDepthError() override
void endVisitHelper(AST::PatternElement *pe, const std::shared_ptr< ScriptElements::GenericScriptElement > &element)
bool visit(AST::UiProgram *program) override
bool stackHasScriptVariant() const
virtual QQmlJSASTClassListToVisit void throwRecursionDepthError() override
QQmlDomAstCreatorWithQQmlJSScope(const QQmlJSScope::Ptr ¤t, MutableDomItem &qmlFile, QQmlJSLogger *logger, QQmlJSImporter *importer)
void setNameIdentifiers(const ScriptElementVariant &name)
Path addId(const Id &id, AddOption option=AddOption::Overwrite, Id **idPtr=nullptr)
void setNameIdentifiers(const ScriptElementVariant &name)
void updatePathFromOwner(const Path &newPath) override
Path addPrototypePath(const Path &prototypePath)
QList< std::pair< SourceLocation, DomItem > > Attributes
Use this to contain any script element.
void replaceKindForGenericChildren(DomType oldType, DomType newType)
Provides entities to maintain mappings between elements and their location in a file.
void addRegion(const Tree &fLoc, FileLocationRegion region, SourceLocation loc)
Tree ensure(const Tree &base, const Path &basePath)
std::shared_ptr< Node > Tree
@ ScriptVariableDeclarationEntry
@ ScriptContinueStatement
@ ScriptLabelledStatement
@ ScriptTemplateExpressionPart
@ ScriptParenthesizedExpression
@ ScriptNewMemberExpression
@ ScriptConditionalExpression
@ ScriptIdentifierExpression
@ ScriptTryCatchStatement
@ ScriptFunctionExpression
@ ScriptVariableDeclaration
@ ScriptTemplateStringPart
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
#define Q_SCRIPTELEMENT_EXIT_IF(check)
#define Q_SCRIPTELEMENT_DISABLE()
#define NewErrorGroup(name)