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;
790 SourceLocation bodyLoc = fDef->body ? combineLocations(fDef->body)
791 : combineLocations(fDef->lbraceToken, fDef->rbraceToken);
793 code.mid(bodyLoc.offset, bodyLoc.length), qmlFilePtr->engine(), fDef->body,
794 qmlFilePtr->astComments(), ScriptExpression::ExpressionType::FunctionBody, bodyLoc);
796 if (fDef->typeAnnotation) {
797 SourceLocation typeLoc = combineLocations(fDef->typeAnnotation);
799 code.mid(typeLoc.offset, typeLoc.length), qmlFilePtr->engine(),
800 fDef->typeAnnotation, qmlFilePtr->astComments(),
801 ScriptExpression::ExpressionType::ReturnType, typeLoc);
806 pushEl(mPathFromOwner, *mPtr,
809 if (fDef->identifierToken.isValid())
813 if (fDef->functionToken.isValid())
815 if (fDef->starToken.isValid())
817 if (fDef->lparenToken.length != 0)
819 if (fDef->rparenToken.length != 0)
821 if (fDef->lbraceToken.length != 0)
823 if (fDef->rbraceToken.length != 0)
825 if (fDef->typeAnnotation)
828 AST::FormalParameterList *args = fDef->formals;
831 param.name = args->element->bindingIdentifier.toString();
832 if (AST::TypeAnnotation *tAnn = args->element->typeAnnotation) {
833 if (AST::Type *t = tAnn->type)
834 param.typeName = typeToString(t);
836 if (args->element->initializer) {
837 SourceLocation loc = combineLocations(args->element->initializer);
839 code.mid(loc.offset, loc.length), qmlFilePtr->engine(),
840 args->element->initializer, qmlFilePtr->astComments(),
841 ScriptExpression::ExpressionType::ArgInitializer, loc);
843 if (args->element->type == AST::PatternElement::SpreadElement)
845 SourceLocation parameterLoc = combineLocations(args->element);
847 code.mid(parameterLoc.offset, parameterLoc.length), qmlFilePtr->engine(),
848 args->element, qmlFilePtr->astComments(),
849 ScriptExpression::ExpressionType::ArgumentStructure, parameterLoc);
851 index_type idx = index_type(mInfo.parameters.size());
852 mInfo.parameters.append(param);
854 Path::fromField(Fields::parameters).withIndex(idx));
856 if (args->element->identifierToken.isValid())
858 if (args->element->typeAnnotation)
867 if (AST::cast<VariableStatement *>(el->sourceElement)) {
868 qmlFile.addError(astParseErrors().warning(
869 "JavaScript declarations are not allowed in QML elements"_L1));
877 if (
auto data = variant.data()) {
878 if (
auto genericElement =
879 std::get_if<std::shared_ptr<ScriptElements::GenericScriptElement>>(&*data)) {
888 if (m_nestedFunctionDepth > 1) {
889 endVisit(
static_cast<FunctionExpression *>(fDef));
892 --m_nestedFunctionDepth;
895 FileLocations::ensure(currentNodeEl().fileLocations, Path().withField(Fields::body));
896 const Path bodyPath =
Path().withField(Fields::scriptElement);
898 if (!m_enableScriptExpressions)
902 m.body->setScriptElement(
903 finalizeScriptExpression(prepareBodyForFunction(fDef), bodyPath, bodyTree));
905 if (fDef->typeAnnotation) {
907 Path().withField(Fields::returnType));
908 const Path pathToReturnType =
Path().withField(Fields::scriptElement);
912 finalizeScriptExpression(variant, pathToReturnType, argLoc);
913 m.returnType->setScriptElement(variant);
914 removeCurrentScriptNode({});
918 const auto parameterList = scriptNodeStack.takeLast().takeList();
919 const auto ¶meterQList = parameterList.qList();
920 size_t size = (size_t)parameterQList.size();
921 for (size_t idx = size - 1; idx < size; --idx) {
923 nodeStack.last().fileLocations,
924 Path().withField(Fields::parameters).withIndex(idx).withField(Fields::value));
925 const Path pathToArgument =
Path().withField(Fields::scriptElement);
928 setFormalParameterKind(variant);
929 finalizeScriptExpression(variant, pathToArgument, argLoc);
930 m.parameters[idx].value->setScriptElement(variant);
935 if (m_enableScriptExpressions && !scriptNodeStack.empty()) {
942 if (AST::cast<VariableStatement *>(el->sourceElement))
948 valueFromMultimap(obj.m_methods, m.name, nodeStack.last().path.last().headIndex());
957 scope.setName(toString(el->qualifiedTypeNameId));
961 if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last()) {
963 QList<QmlObject> *vals =
std::get<
Binding>(currentNode().value).arrayValue();
965 int idx = vals->size();
967 sPathFromOwner = currentNodeEl().path.withField(Fields::value).withIndex(idx);
968 sPtr = &((*vals)[idx]);
971 Q_ASSERT_X(
false, className,
972 "expected an array binding with a valid QList<QmlScope> as value");
975 Q_ASSERT_X(
false, className,
"expected an array binding as last node on the stack");
978 DomValue &containingObject = currentQmlObjectOrComponentEl().item;
979 switch (containingObject.kind) {
981 sPathFromOwner =
std::get<QmlComponent>(containingObject.value).addObject(scope, &sPtr);
984 sPathFromOwner =
std::get<
QmlObject>(containingObject.value).addChild(scope, &sPtr);
989 Path pathFromContainingObject = sPathFromOwner.mid(currentNodeEl().path.length());
991 FileLocations::ensure(currentNodeEl().fileLocations, pathFromContainingObject);
993 el->qualifiedTypeNameId->identifierToken);
995 Q_ASSERT_X(sPtr, className,
"could not recover new scope");
997 if (m_enableScriptExpressions) {
998 auto qmlObjectType = makeGenericScriptElement(el->qualifiedTypeNameId,
DomType::ScriptType);
999 qmlObjectType->insertChild(Fields::typeName,
1000 fieldMemberExpressionForQualifiedId(el->qualifiedTypeNameId));
1003 sPathFromOwner.withField(Fields::nameIdentifiers), rootMap)
);
1005 pushEl(sPathFromOwner, *sPtr, el);
1007 if (el->initializer) {
1009 el->initializer->lbraceToken);
1011 el->initializer->rbraceToken);
1013 loadAnnotations(el);
1020 int idx = currentIndex();
1021 if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last() + 1) {
1024 QList<QmlObject> *vals = b.arrayValue();
1025 Q_ASSERT_X(vals, className,
1026 "expected an array binding with a valid QList<QmlScope> as value");
1029 Q_ASSERT_X(
false, className,
"expected an array binding as last node on the stack");
1032 DomValue &containingObject = currentNodeEl(1).item;
1033 Path p = currentNodeEl().path;
1034 switch (containingObject.kind) {
1036 if (p
[p
.length() - 2
] == Path::fromField(Fields::objects))
1037 std::get<QmlComponent>(containingObject.value).m_objects[idx] = obj;
1042 if (p
[p
.length() - 2
] == Path::fromField(Fields::children))
1043 std::get<
QmlObject>(containingObject.value).m_children[idx] = obj;
1055 const UiQualifiedId *identifiers,
Binding *bindingPtr)
1057 const bool skipBindingIdentifiers =
std::exchange(m_skipBindingIdentifiers,
false);
1058 if (!m_enableScriptExpressions || skipBindingIdentifiers)
1063 bindable, pathFromOwner.withField(Fields::bindingIdentifiers), rootMap)
);
1070 value.setName(toString(el->qualifiedTypeNameId));
1074 if (bPtr->name() == u"id")
1075 qmlFile.addError(std::move(astParseErrors()
1076 .warning(tr(
"id attributes should only be a lower case letter "
1077 "followed by letters, numbers or underscore, "
1078 "assuming they refer to an id property"))
1079 .withPath(bPathFromOwner)));
1080 setBindingIdentifiers(bPathFromOwner, el->qualifiedId, bPtr);
1082 pushEl(bPathFromOwner, *bPtr, el);
1088 loadAnnotations(el);
1090 Q_ASSERT_X(objValue, className,
"could not recover objectValue");
1091 objValue->setName(toString(el->qualifiedTypeNameId));
1093 if (m_enableScriptExpressions) {
1094 auto qmlObjectType = makeGenericScriptElement(el->qualifiedTypeNameId,
DomType::ScriptType);
1095 qmlObjectType->insertChild(Fields::typeName,
1096 fieldMemberExpressionForQualifiedId(el->qualifiedTypeNameId));
1099 bPathFromOwner.withField(Fields::value).withField(Fields::nameIdentifiers), rootMap)
);
1103 pushEl(bPathFromOwner.withField(Fields::value), *objValue, el->initializer);
1104 if (m_enableScriptExpressions && el->initializer) {
1106 el->initializer->lbraceToken);
1108 el->initializer->rbraceToken);
1121 index_type idx = currentNodeEl(1).path.last().headIndex();
1122 Binding *bPtr = valueFromMultimap(containingObj.m_bindings, b.name(), idx);
1131 ++m_nestedFunctionDepth;
1132 QStringView code = qmlFilePtr->code();
1133 SourceLocation loc = combineLocations(el->statement);
1135 code.mid(loc.offset, loc.length), qmlFilePtr->engine(), el->statement,
1136 qmlFilePtr->astComments(), ScriptExpression::ExpressionType::BindingExpression, loc);
1138 Binding *bindingPtr =
nullptr;
1139 Id *idPtr =
nullptr;
1141 if (bindingV.name() == u"id") {
1142 Node *exp = script->ast();
1143 if (ExpressionStatement *eStat = cast<ExpressionStatement *>(script->ast()))
1144 exp = eStat->expression;
1145 if (IdentifierExpression *iExp = cast<IdentifierExpression *>(exp)) {
1146 QmlStackElement &containingObjectEl = currentEl<
QmlObject>();
1148 QString idName = iExp->name.toString();
1149 Id idVal(idName, qmlFile.canonicalPath().withPath(containingObject.pathFromOwner()));
1150 idVal.value = script;
1151 containingObject.setIdStr(idName);
1153 combineLocations(el->qualifiedId));
1157 combineLocations(el->statement));
1158 QmlComponent &comp = current<QmlComponent>();
1160 QRegularExpression idRe(QRegularExpression::anchoredPattern(
1161 QStringLiteral(uR"([[:lower:]][[:lower:][:upper:]0-9_]*)")));
1162 auto m = idRe.matchView(iExp->name);
1163 if (!m.hasMatch()) {
1164 qmlFile.addError(std::move(
1166 .warning(tr(
"id attributes should only be a lower case letter "
1167 "followed by letters, numbers or underscore, not %1")
1169 .withPath(pathFromOwner)));
1174 Q_ASSERT_X(bindingPtr, className,
"binding could not be retrieved");
1175 qmlFile.addError(std::move(
1177 .warning(tr(
"id attributes should only be a lower case letter "
1178 "followed by letters, numbers or underscore, not %1 "
1179 "%2, assuming they refer to a property")
1180 .arg(script->code(), script->astRelocatableDump()))
1181 .withPath(pathFromOwner)));
1186 QmlStackElement &containingObjectEl = currentEl<
QmlObject>();
1188 Path pathFromContainingObject = pathFromOwner.mid(containingObjectEl.path.length());
1189 auto bindingFileLocation =
1192 el->qualifiedId->identifierToken);
1195 setBindingIdentifiers(pathFromOwner, el->qualifiedId, bindingPtr);
1197 Q_ASSERT_X(bindingPtr, className,
"binding could not be retrieved");
1200 pushEl(pathFromOwner, *bindingPtr, el);
1202 pushEl(pathFromOwner, *idPtr, el);
1205 loadAnnotations(el);
1213 if (m_enableScriptExpressions
1214 && (scriptNodeStack.size() != 1 || currentScriptNodeEl().isList()))
1216 if (m_enableScriptExpressions) {
1217 FileLocations::
Tree valueLoc = FileLocations::ensure(currentNodeEl().fileLocations,
1218 Path().withField(Fields::value));
1219 value->setScriptElement(finalizeScriptExpression(currentScriptNodeEl().takeVariant(),
1220 Path().withField(Fields::scriptElement),
1222 removeCurrentScriptNode({});
1228 --m_nestedFunctionDepth;
1229 DomValue &lastEl = currentNode();
1230 index_type idx = currentIndex();
1237 Binding *bPtr = valueFromMultimap(containingObject.m_bindings, b.name(), idx);
1241 Id &id =
std::get<
Id>(lastEl.value);
1243 setScriptExpression(id.value);
1245 QmlComponent &comp = current<QmlComponent>();
1246 Id *idPtr = valueFromMultimap(comp.m_ids, id.name, idx);
1253 if (m_enableScriptExpressions && !scriptNodeStack.empty()) {
1256 removeCurrentNode({});
1261 QList<QmlObject> value;
1264 Path bindingPathFromOwner =
1266 if (bindingV.name() == u"id")
1267 qmlFile.addError(std::move(
1269 .error(tr(
"id attributes should have only simple strings as values"))
1270 .withPath(bindingPathFromOwner)));
1272 setBindingIdentifiers(bindingPathFromOwner, el->qualifiedId, bindingPtr);
1274 pushEl(bindingPathFromOwner, *bindingPtr, el);
1276 loadAnnotations(el);
1278 createMap(currentNodeEl().fileLocations, Path::fromField(Fields::value),
nullptr);
1281 arrayBindingLevels.append(nodeStack.size());
1287 index_type idx = currentIndex();
1289 Binding *bPtr = valueFromMultimap(current<
QmlObject>().m_bindings, b.name(), idx);
1291 arrayBindingLevels.removeLast();
1297 endVisitForLists(list);
1307 endVisitForLists<AST::PatternElementList>(list, [](AST::PatternElementList *current) {
1309 toCollect +=
bool(current->elision);
1310 toCollect +=
bool(current->element);
1317 endVisitForLists(list);
1321
1322
1323
1324
1325
1329 expression->firstSourceLocation(), expression->lastSourceLocation());
1330 id->setName(expression->toString());
1337 if (!m_enableScriptExpressions)
1346 eDecl.setName(el->name.toString());
1348 Path enumPathFromOwner =
1350 pushEl(enumPathFromOwner, *ePtr, el);
1355 loadAnnotations(el);
1361 EnumDecl &e =
std::get<EnumDecl>(currentNode().value);
1363 valueFromMultimap(current<QmlComponent>().m_enumerations, e.name(), currentIndex());
1371 EnumItem it(el->member.toString(), el->value,
1374 EnumDecl &eDecl =
std::get<EnumDecl>(currentNode().value);
1376 const auto map = createMap(DomType::EnumItem, itPathFromDecl,
nullptr);
1377 if (el->commaToken.isValid())
1379 if (el->memberToken.isValid())
1381 if (el->equalToken.isValid())
1383 if (el->valueToken.isValid())
1386 map, MainRegion, combine(combine(el->memberToken, el->commaToken), el->valueToken));
1392 Node::accept(el->next,
this);
1397 QStringList els = current<QmlComponent>().name().split(QLatin1Char(
'.'));
1398 els.append(el->name.toString());
1399 QString cName = els.join(QLatin1Char(
'.'));
1400 QmlComponent *compPtr;
1401 Path p = qmlFilePtr->addComponent(QmlComponent(cName), AddOption::KeepExisting, &compPtr);
1403 if (m_enableScriptExpressions) {
1404 auto inlineComponentType =
1408 typeName->setName(el->name);
1409 inlineComponentType->insertChild(Fields::typeName,
1413 p.withField(Fields::nameIdentifiers), rootMap)
);
1416 pushEl(p, *compPtr, el);
1418 el->componentToken);
1420 loadAnnotations(el);
1426 QmlComponent &component =
std::get<QmlComponent>(currentNode().value);
1427 QStringList nameEls = component.name().split(QChar::fromLatin1(
'.'));
1428 QString key = nameEls.mid(1).join(QChar::fromLatin1(
'.'));
1429 QmlComponent *cPtr = valueFromMultimap(qmlFilePtr->lazyMembers().m_components, key, currentIndex());
1438 pDef.name = el->name.toString();
1441 Path pathFromOwner =
1443 createMap(DomType::PropertyDefinition, pathFromOwner, el);
1450 a.setName(QStringLiteral(u"@") + toString(el->qualifiedTypeNameId));
1452 DomValue &containingElement = currentNode();
1455 switch (containingElement.kind) {
1457 pathFromOwner =
std::get<
QmlObject>(containingElement.value).addAnnotation(a, &aPtr);
1460 pathFromOwner =
std::get<
Binding>(containingElement.value)
1461 .addAnnotation(currentNodeEl().path, a, &aPtr);
1465 std::get<
Id>(containingElement.value).addAnnotation(currentNodeEl().path, a, &aPtr);
1469 .addAnnotation(currentNodeEl().path, a, &aPtr);
1472 pathFromOwner =
std::get<
MethodInfo>(containingElement.value)
1473 .addAnnotation(currentNodeEl().path, a, &aPtr);
1476 qCWarning(domLog) <<
"Unexpected container object for annotation:"
1477 << domTypeToString(containingElement.kind);
1480 pushEl(pathFromOwner, *aPtr, el);
1486 DomValue &containingElement = currentNode(1);
1489 switch (containingElement.kind) {
1490 case DomType::QmlObject:
1491 std::get<QmlObject>(containingElement.value).m_annotations[currentIndex()] = a;
1493 case DomType::Binding:
1494 std::get<Binding>(containingElement.value).m_annotations[currentIndex()] = a;
1497 std::get<Id>(containingElement.value).annotations[currentIndex()] = a;
1499 case DomType::PropertyDefinition:
1500 std::get<PropertyDefinition>(containingElement.value).annotations[currentIndex()] = a;
1502 case DomType::MethodInfo:
1503 std::get<MethodInfo>(containingElement.value).annotations[currentIndex()] = a;
1513 qmlFile.addError(astParseErrors().error(
1514 tr(
"Maximum statement or expression depth exceeded in QmlDomAstCreator")));
1519 endVisitForLists(list);
1524 if (!m_enableScriptExpressions)
1532 if (!m_enableScriptExpressions)
1536 current->addLocation(OperatorTokenRegion, exp->operatorToken);
1538 current->setRight(currentScriptNodeEl().takeVariant());
1539 removeCurrentScriptNode({});
1541 current->setLeft(currentScriptNodeEl().takeVariant());
1542 removeCurrentScriptNode({});
1544 pushScriptElement(current);
1549 if (!m_enableScriptExpressions)
1557 if (!m_enableScriptExpressions)
1562 if (block->statements) {
1564 current->setStatements(currentScriptNodeEl().takeList());
1568 pushScriptElement(current);
1573 if (!m_enableScriptExpressions)
1581 if (!m_enableScriptExpressions)
1585 current->addLocation(FileLocationRegion::ForKeywordRegion, forStatement->forToken);
1586 current->addLocation(FileLocationRegion::LeftParenthesisRegion, forStatement->lparenToken);
1587 current->addLocation(FileLocationRegion::FirstSemicolonTokenRegion,
1588 forStatement->firstSemicolonToken);
1589 current->addLocation(FileLocationRegion::SecondSemicolonRegion,
1590 forStatement->secondSemicolonToken);
1591 current->addLocation(FileLocationRegion::RightParenthesisRegion, forStatement->rparenToken);
1593 if (forStatement->statement) {
1595 current->setBody(currentScriptNodeEl().takeVariant());
1596 removeCurrentScriptNode(
std::nullopt);
1599 if (forStatement->expression) {
1601 current->setExpression(currentScriptNodeEl().takeVariant());
1602 removeCurrentScriptNode(
std::nullopt);
1605 if (forStatement->condition) {
1607 current->setCondition(currentScriptNodeEl().takeVariant());
1608 removeCurrentScriptNode(
std::nullopt);
1611 if (forStatement->declarations) {
1613 auto variableDeclaration = makeGenericScriptElement(forStatement->declarations,
1619 variableDeclaration->insertChild(Fields::declarations,
std::move(list));
1620 removeCurrentScriptNode({});
1624 if (
auto pe = forStatement->declarations->declaration;
1625 pe && pe->declarationKindToken.isValid()) {
1626 current->addLocation(FileLocationRegion::TypeIdentifierRegion,
1627 pe->declarationKindToken);
1631 if (forStatement->initialiser) {
1633 current->setInitializer(currentScriptNodeEl().takeVariant());
1634 removeCurrentScriptNode(
std::nullopt);
1636 pushScriptElement(current);
1641 if (!m_enableScriptExpressions)
1645 current->setName(expression->name);
1646 pushScriptElement(current);
1652 if (!m_enableScriptExpressions)
1656 current->setLiteralValue(expression->value);
1657 pushScriptElement(current);
1663 if (!m_enableScriptExpressions)
1666 pushScriptElement(makeStringLiteral(expression->value, expression));
1672 if (!m_enableScriptExpressions)
1676 current->setLiteralValue(
nullptr);
1677 pushScriptElement(current);
1683 if (!m_enableScriptExpressions)
1687 current->setLiteralValue(
true);
1688 pushScriptElement(current);
1694 if (!m_enableScriptExpressions)
1698 current->setLiteralValue(
false);
1699 pushScriptElement(current);
1705 if (!m_enableScriptExpressions)
1709 current->setName(expression->id);
1710 pushScriptElement(current);
1716 if (!m_enableScriptExpressions)
1719 pushScriptElement(makeStringLiteral(expression->id, expression));
1725 if (!m_enableScriptExpressions)
1734 if (!m_enableScriptExpressions)
1738 current->insertValue(Fields::regExpPattern, literal->pattern);
1739 current->insertValue(Fields::regExpFlags, literal->flags);
1740 pushScriptElement(current);
1747 if (!m_enableScriptExpressions)
1751 if (expression->thisToken.isValid())
1752 current->addLocation(ThisKeywordRegion, expression->thisToken);
1753 pushScriptElement(current);
1759 if (!m_enableScriptExpressions)
1763 if (expression->superToken.isValid())
1764 current->addLocation(SuperKeywordRegion, expression->superToken);
1765 pushScriptElement(current);
1771 if (!m_enableScriptExpressions)
1775 current->setLiteralValue(expression->id);
1776 pushScriptElement(current);
1782 if (!m_enableScriptExpressions)
1791 const std::function<
int(T *)> &scriptElementsPerEntry)
1793 if (!m_enableScriptExpressions)
1796 auto current = makeScriptList(list);
1797 for (
auto it = list; it; it = it->next) {
1798 const int entriesToCollect = scriptElementsPerEntry ? scriptElementsPerEntry(it) : 1;
1799 for (
int i = 0; i < entriesToCollect; ++i) {
1801 auto last = scriptNodeStack.takeLast();
1803 current.append(last.takeList());
1805 current.append(last.takeVariant());
1810 pushScriptElement(current);
1815 endVisitForLists(list);
1820 if (!m_enableScriptExpressions)
1823 auto currentList = makeScriptList(list);
1825 for (
auto it = list; it; it = it->next) {
1829 pushScriptElement(currentList);
1837 if (!m_enableScriptExpressions)
1844
1845
1846
1847
1849 AST::PatternElement *pe,
1852 if (pe->equalToken.isValid())
1853 current->addLocation(FileLocationRegion::EqualTokenRegion, pe->equalToken);
1855 if (pe->identifierToken.isValid() && !pe->bindingIdentifier.isEmpty()) {
1858 identifier->setName(pe->bindingIdentifier);
1859 current->insertChild(Fields::identifier, ScriptElementVariant::fromElement(identifier));
1861 if (pe->initializer) {
1863 current->insertChild(Fields::initializer, scriptNodeStack.last().takeVariant());
1864 scriptNodeStack.removeLast();
1866 if (pe->typeAnnotation) {
1868 current->insertChild(Fields::type, scriptNodeStack.last().takeVariant());
1869 scriptNodeStack.removeLast();
1871 if (pe->bindingTarget) {
1873 current->insertChild(Fields::bindingElement, scriptNodeStack.last().takeVariant());
1874 scriptNodeStack.removeLast();
1880 if (!m_enableScriptExpressions)
1884 endVisitHelper(pe, element);
1886 if (!m_enableScriptExpressions)
1889 pushScriptElement(element);
1894 if (!m_enableScriptExpressions)
1902 if (!m_enableScriptExpressions)
1906 current->addLocation(LeftParenthesisRegion, ifStatement->lparenToken);
1907 current->addLocation(RightParenthesisRegion, ifStatement->rparenToken);
1908 current->addLocation(ElseKeywordRegion, ifStatement->elseToken);
1909 current->addLocation(IfKeywordRegion, ifStatement->ifToken);
1911 if (ifStatement->ko) {
1913 current->setAlternative(scriptNodeStack.last().takeVariant());
1914 scriptNodeStack.removeLast();
1917 if (ifStatement->ok) {
1919 current->setConsequence(scriptNodeStack.last().takeVariant());
1920 scriptNodeStack.removeLast();
1922 if (ifStatement->expression) {
1924 current->setCondition(scriptNodeStack.last().takeVariant());
1925 scriptNodeStack.removeLast();
1928 pushScriptElement(current);
1933 if (!m_enableScriptExpressions)
1941 if (!m_enableScriptExpressions)
1945 current->addLocation(ReturnKeywordRegion, returnStatement->returnToken);
1947 if (returnStatement->expression) {
1949 current->setExpression(currentScriptNodeEl().takeVariant());
1950 removeCurrentScriptNode({});
1953 pushScriptElement(current);
1958 if (!m_enableScriptExpressions)
1966 if (!m_enableScriptExpressions)
1970 current->addLocation(YieldKeywordRegion, yExpression->yieldToken);
1972 if (yExpression->expression) {
1974 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
1975 removeCurrentScriptNode({});
1978 pushScriptElement(current);
1983 if (!m_enableScriptExpressions)
1991 if (!m_enableScriptExpressions)
1996 current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->dotToken);
1998 if (expression->base) {
2000 current->setLeft(currentScriptNodeEl().takeVariant());
2001 removeCurrentScriptNode({});
2004 auto scriptIdentifier =
2006 scriptIdentifier->setName(expression->name);
2009 pushScriptElement(current);
2014 if (!m_enableScriptExpressions)
2022 if (!m_enableScriptExpressions)
2027 current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->lbracketToken);
2029 if (expression->expression) {
2033 current->setRight(currentScriptNodeEl().takeVariant());
2034 removeCurrentScriptNode({});
2037 if (expression->base) {
2039 current->setLeft(currentScriptNodeEl().takeVariant());
2040 removeCurrentScriptNode({});
2043 pushScriptElement(current);
2048 if (!m_enableScriptExpressions)
2056 if (!m_enableScriptExpressions)
2060 current->addLocation(LeftParenthesisRegion, exp->lparenToken);
2061 current->addLocation(RightParenthesisRegion, exp->rparenToken);
2063 if (exp->arguments) {
2065 current->insertChild(Fields::arguments, currentScriptNodeEl().takeList());
2066 removeCurrentScriptNode({});
2069 current->insertChild(Fields::arguments,
2075 current->insertChild(Fields::callee, currentScriptNodeEl().takeVariant());
2076 removeCurrentScriptNode({});
2079 pushScriptElement(current);
2084 if (!m_enableScriptExpressions)
2092 if (!m_enableScriptExpressions)
2097 if (exp->elements) {
2101 current->insertChild(Fields::elements,
std::move(list));
2103 removeCurrentScriptNode({});
2106 current->insertChild(Fields::elements,
2110 pushScriptElement(current);
2115 if (!m_enableScriptExpressions)
2123 if (!m_enableScriptExpressions)
2128 if (exp->properties) {
2130 current->insertChild(Fields::properties, currentScriptNodeEl().takeList());
2131 removeCurrentScriptNode({});
2134 current->insertChild(Fields::properties,
2138 pushScriptElement(current);
2143 if (!m_enableScriptExpressions)
2151 if (!m_enableScriptExpressions)
2157 endVisitHelper(
static_cast<PatternElement *>(exp), current);
2160 if (!m_enableScriptExpressions)
2165 current->insertChild(Fields::name, currentScriptNodeEl().takeVariant());
2166 removeCurrentScriptNode({});
2169 pushScriptElement(current);
2174 if (!m_enableScriptExpressions)
2182 if (!m_enableScriptExpressions)
2186 current->addLocation(FileLocationRegion::TypeIdentifierRegion, statement->declarationKindToken);
2188 if (statement->declarations) {
2194 current->insertChild(Fields::declarations,
std::move(list));
2196 removeCurrentScriptNode({});
2199 pushScriptElement(current);
2204 if (!m_enableScriptExpressions)
2212 if (!m_enableScriptExpressions)
2217 if (exp->typeArgument) {
2218 current->insertChild(Fields::typeArgumentName,
2219 fieldMemberExpressionForQualifiedId(exp->typeArgument));
2220 current->addLocation(FileLocationRegion::IdentifierRegion, combineLocations(exp->typeArgument));
2224 current->insertChild(Fields::typeName, fieldMemberExpressionForQualifiedId(exp->typeId));
2225 current->addLocation(FileLocationRegion::TypeIdentifierRegion, combineLocations(exp->typeId));
2228 pushScriptElement(current);
2233 if (!m_enableScriptExpressions)
2241 if (!m_enableScriptExpressions)
2245 current->addLocation(DefaultKeywordRegion, exp->defaultToken);
2246 current->addLocation(ColonTokenRegion, exp->colonToken);
2248 if (exp->statements) {
2250 current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
2251 removeCurrentScriptNode({});
2254 pushScriptElement(current);
2259 if (!m_enableScriptExpressions)
2267 if (!m_enableScriptExpressions)
2271 current->addLocation(FileLocationRegion::CaseKeywordRegion, exp->caseToken);
2272 current->addLocation(FileLocationRegion::ColonTokenRegion, exp->colonToken);
2274 if (exp->statements) {
2276 current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
2277 removeCurrentScriptNode({});
2280 if (exp->expression) {
2282 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2283 removeCurrentScriptNode({});
2286 pushScriptElement(current);
2291 if (!m_enableScriptExpressions)
2299 if (!m_enableScriptExpressions)
2302 auto current = makeScriptList(list);
2304 for (
auto it = list; it; it = it->next) {
2306 current.append(scriptNodeStack.takeLast().takeVariant());
2310 pushScriptElement(current);
2315 if (!m_enableScriptExpressions)
2323 if (!m_enableScriptExpressions)
2327 current->addLocation(FileLocationRegion::LeftBraceRegion, exp->lbraceToken);
2328 current->addLocation(FileLocationRegion::RightBraceRegion, exp->rbraceToken);
2330 if (exp->moreClauses) {
2332 current->insertChild(Fields::moreCaseClauses, currentScriptNodeEl().takeList());
2333 removeCurrentScriptNode({});
2336 if (exp->defaultClause) {
2338 current->insertChild(Fields::defaultClause, currentScriptNodeEl().takeVariant());
2339 removeCurrentScriptNode({});
2344 current->insertChild(Fields::caseClauses, currentScriptNodeEl().takeList());
2345 removeCurrentScriptNode({});
2347 pushScriptElement(current);
2352 if (!m_enableScriptExpressions)
2360 if (!m_enableScriptExpressions)
2364 current->addLocation(FileLocationRegion::SwitchKeywordRegion, exp->switchToken);
2365 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2366 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2370 current->insertChild(Fields::caseBlock, currentScriptNodeEl().takeVariant());
2371 removeCurrentScriptNode({});
2373 if (exp->expression) {
2375 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2376 removeCurrentScriptNode({});
2379 pushScriptElement(current);
2384 if (!m_enableScriptExpressions)
2392 if (!m_enableScriptExpressions)
2396 current->addLocation(FileLocationRegion::WhileKeywordRegion, exp->whileToken);
2397 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2398 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2400 if (exp->statement) {
2402 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2403 removeCurrentScriptNode({});
2406 if (exp->expression) {
2408 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2409 removeCurrentScriptNode({});
2412 pushScriptElement(current);
2417 if (!m_enableScriptExpressions)
2425 if (!m_enableScriptExpressions)
2429 current->addLocation(FileLocationRegion::DoKeywordRegion, exp->doToken);
2430 current->addLocation(FileLocationRegion::WhileKeywordRegion, exp->whileToken);
2431 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2432 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2434 if (exp->expression) {
2436 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2437 removeCurrentScriptNode({});
2440 if (exp->statement) {
2442 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2443 removeCurrentScriptNode({});
2446 pushScriptElement(current);
2451 if (!m_enableScriptExpressions)
2459 if (!m_enableScriptExpressions)
2463 current->addLocation(FileLocationRegion::ForKeywordRegion, exp->forToken);
2464 current->addLocation(FileLocationRegion::InOfTokenRegion, exp->inOfToken);
2465 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2466 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2468 if (exp->statement) {
2470 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2471 removeCurrentScriptNode({});
2473 if (exp->expression) {
2475 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2476 removeCurrentScriptNode({});
2481 current->insertChild(Fields::bindingElement, currentScriptNodeEl().takeVariant());
2482 removeCurrentScriptNode({});
2484 if (
auto pe = AST::cast<PatternElement *>(exp->lhs);
2485 pe && pe->declarationKindToken.isValid()) {
2486 current->addLocation(FileLocationRegion::TypeIdentifierRegion,
2487 pe->declarationKindToken);
2491 pushScriptElement(current);
2499 if (m_enableScriptExpressions)
2510 if (!m_enableScriptExpressions)
2514 current->insertChild(Fields::templateLiteral, scriptNodeStack.takeLast().takeVariant());
2516 current->insertChild(Fields::callee, scriptNodeStack.takeLast().takeVariant());
2517 pushScriptElement(current);
2521
2522
2523
2524
2525
2526enum TemplatePartPosition : quint8 {
2532Q_DECLARE_FLAGS(TemplatePartPositions, TemplatePartPosition)
2535
2536
2537
2538
2539static void extractDollarBraceSourceLocationInto(
2541 const SourceLocation &toBeSplit, QStringView code,
2542 TemplatePartPositions templatePartLocation)
2544 if (templatePartLocation & AtEnd || !currentExpression)
2547 const auto offset = toBeSplit.offset + toBeSplit.length - 2;
2548 constexpr auto length = quint32(
std::char_traits<
char>::length(
"${"));
2549 const auto [row, column] = SourceLocation::rowAndColumnFrom(code, offset, toBeSplit);
2550 currentExpression->addLocation(FileLocationRegion::DollarLeftBraceTokenRegion,
2551 SourceLocation{ offset, length, row, column });
2556
2557
2558
2559static void extractRightBacktickSourceLocationInto(
2561 const SourceLocation &toBeSplit, QStringView code,
2562 TemplatePartPositions templatePartLocation)
2564 if (!(templatePartLocation & AtEnd))
2567 const auto offset = toBeSplit.offset + toBeSplit.length - 1;
2568 constexpr auto length = quint32(
std::char_traits<
char>::length(
"`"));
2569 const auto [row, column] = SourceLocation::rowAndColumnFrom(code, offset, toBeSplit);
2570 currentTemplate->addLocation(FileLocationRegion::RightBacktickTokenRegion,
2571 SourceLocation{ offset, length, row, column });
2575
2576
2577
2578static void extractLeftBacktickSourceLocationInto(
2580 const SourceLocation &toBeSplit, TemplatePartPositions templatePartLocation)
2582 if (!(templatePartLocation & AtBeginning))
2585 constexpr auto length = quint32(
std::char_traits<
char>::length(
"`"));
2586 const QQmlJS::SourceLocation leftBacktick{ toBeSplit.offset, length, toBeSplit.startLine,
2587 toBeSplit.startColumn };
2588 currentTemplate->addLocation(FileLocationRegion::LeftBacktickTokenRegion, leftBacktick);
2592
2593
2594
2595
2596static SourceLocation extractRightBraceSourceLocation(
const SourceLocation &toBeSplit,
2597 TemplatePartPositions templatePartLocation)
2599 if (templatePartLocation & AtBeginning)
2600 return SourceLocation{};
2603 return SourceLocation{ toBeSplit.offset, 1, toBeSplit.startLine, toBeSplit.startColumn };
2607
2608
2609
2610
2611static SourceLocation extractStringLocation(
const SourceLocation &toBeSplit, QStringView code,
2612 TemplatePartPositions location)
2616 const quint32 length = toBeSplit.length - (location & AtEnd ? 2 : 3);
2617 const quint32 offset = toBeSplit.offset + 1;
2618 const auto [row, column] = SourceLocation::rowAndColumnFrom(code, offset, toBeSplit);
2619 return SourceLocation{ offset, length, row, column };
2624 if (!m_enableScriptExpressions)
2629 auto currentList = makeScriptList(literal);
2632 const auto children = [&literal]() {
2633 std::vector<AST::TemplateLiteral *> result;
2634 for (
auto it = literal; it; it = it->next) {
2635 result.push_back(it);
2640 SourceLocation rightBrace;
2641 for (
auto it = children.crbegin(); it != children.crend(); ++it) {
2643 const QQmlJS::SourceLocation toBeSplit = (*it)->literalToken;
2646 if ((*it)->expression) {
2648 currentExpression = makeGenericScriptElement((*it)->expression,
2651 currentExpression->insertChild(Fields::expression,
2652 scriptNodeStack.takeLast().takeVariant());
2653 if (rightBrace.isValid()) {
2654 currentExpression->addLocation(FileLocationRegion::RightBraceRegion,
2655 std::exchange(rightBrace, SourceLocation{}));
2660 if (!toBeSplit.isValid())
2663 const TemplatePartPositions location = [&it, &children]() {
2664 TemplatePartPositions result;
2665 if (it == children.crbegin())
2667 if (it ==
std::prev(children.crend()))
2668 result |= AtBeginning;
2672 extractRightBacktickSourceLocationInto(currentTemplate, toBeSplit, qmlFilePtr->code(),
2674 extractLeftBacktickSourceLocationInto(currentTemplate, toBeSplit, location);
2676 extractDollarBraceSourceLocationInto(currentExpression, toBeSplit, qmlFilePtr->code(),
2678 rightBrace = extractRightBraceSourceLocation(toBeSplit, location);
2680 if ((*it)->rawValue.isEmpty())
2683 const SourceLocation stringLocation =
2684 extractStringLocation(toBeSplit, qmlFilePtr->code(), location);
2685 auto currentString =
2687 currentString->insertValue(Fields::value, (*it)->rawValue);
2691 currentList.reverse();
2693 currentTemplate->insertChild(Fields::components, currentList);
2694 pushScriptElement(currentTemplate);
2699 return m_enableScriptExpressions;
2704 if (!m_enableScriptExpressions)
2708 current->addLocation(FileLocationRegion::TryKeywordRegion, statement->tryToken);
2710 if (
auto exp = statement->finallyExpression) {
2711 current->addLocation(FileLocationRegion::FinallyKeywordRegion, exp->finallyToken);
2714 current->insertChild(Fields::finallyBlock, currentScriptNodeEl().takeVariant());
2715 removeCurrentScriptNode({});
2718 if (
auto exp = statement->catchExpression) {
2719 current->addLocation(FileLocationRegion::CatchKeywordRegion, exp->catchToken);
2720 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2721 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2724 current->insertChild(Fields::catchBlock, currentScriptNodeEl().takeVariant());
2725 removeCurrentScriptNode({});
2727 current->insertChild(Fields::catchParameter, currentScriptNodeEl().takeVariant());
2728 removeCurrentScriptNode({});
2731 if (statement->statement) {
2733 current->insertChild(Fields::block, currentScriptNodeEl().takeVariant());
2734 removeCurrentScriptNode({});
2737 pushScriptElement(current);
2743 return m_enableScriptExpressions;
2754 return m_enableScriptExpressions;
2764 return m_enableScriptExpressions;
2769 if (!m_enableScriptExpressions)
2773 current->addLocation(FileLocationRegion::ThrowKeywordRegion, statement->throwToken);
2775 if (statement->expression) {
2777 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2778 removeCurrentScriptNode({});
2781 pushScriptElement(current);
2786 return m_enableScriptExpressions;
2791 if (!m_enableScriptExpressions)
2795 current->addLocation(FileLocationRegion::ColonTokenRegion, statement->colonToken);
2798 label->setName(statement->label);
2802 if (statement->statement) {
2804 current->insertChild(Fields::statement, currentScriptNodeEl().takeVariant());
2805 removeCurrentScriptNode({});
2808 pushScriptElement(current);
2813 return m_enableScriptExpressions;
2818 if (!m_enableScriptExpressions)
2822 current->addLocation(FileLocationRegion::BreakKeywordRegion, statement->breakToken);
2824 if (!statement->label.isEmpty()) {
2827 label->setName(statement->label);
2831 pushScriptElement(current);
2836 return m_enableScriptExpressions;
2841 if (!m_enableScriptExpressions)
2845 current->addLocation(OperatorTokenRegion, commaExpression->commaToken);
2847 if (commaExpression->right) {
2849 current->setRight(currentScriptNodeEl().takeVariant());
2850 removeCurrentScriptNode({});
2853 if (commaExpression->left) {
2855 current->setLeft(currentScriptNodeEl().takeVariant());
2856 removeCurrentScriptNode({});
2859 pushScriptElement(current);
2864 return m_enableScriptExpressions;
2869 if (!m_enableScriptExpressions)
2873 current->addLocation(FileLocationRegion::QuestionMarkTokenRegion, expression->questionToken);
2874 current->addLocation(FileLocationRegion::ColonTokenRegion, expression->colonToken);
2876 if (expression->ko) {
2878 current->insertChild(Fields::alternative, currentScriptNodeEl().takeVariant());
2879 removeCurrentScriptNode({});
2882 if (expression->ok) {
2884 current->insertChild(Fields::consequence, currentScriptNodeEl().takeVariant());
2885 removeCurrentScriptNode({});
2888 if (expression->expression) {
2890 current->insertChild(Fields::condition, currentScriptNodeEl().takeVariant());
2891 removeCurrentScriptNode({});
2894 pushScriptElement(current);
2899 return m_enableScriptExpressions;
2904 if (!m_enableScriptExpressions)
2908 current->addLocation(FileLocationRegion::ContinueKeywordRegion, statement->continueToken);
2910 if (!statement->label.isEmpty()) {
2913 label->setName(statement->label);
2917 pushScriptElement(current);
2921
2922
2923
2924
2926QQmlDomAstCreatorBase::makeUnaryExpression(AST::Node *expression, QQmlJS::SourceLocation operatorToken,
2927 bool hasExpression, UnaryExpressionKind kind)
2929 const DomType type = [&kind]() {
2939 auto current = makeGenericScriptElement(expression, type);
2940 current->addLocation(FileLocationRegion::OperatorTokenRegion, operatorToken);
2942 if (hasExpression) {
2947 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2948 removeCurrentScriptNode({});
2956 return m_enableScriptExpressions;
2961 if (!m_enableScriptExpressions)
2965 makeUnaryExpression(statement, statement->minusToken, statement->expression, Prefix);
2969 pushScriptElement(current);
2974 return m_enableScriptExpressions;
2979 if (!m_enableScriptExpressions)
2983 makeUnaryExpression(statement, statement->plusToken, statement->expression, Prefix);
2987 pushScriptElement(current);
2992 return m_enableScriptExpressions;
2997 if (!m_enableScriptExpressions)
3001 makeUnaryExpression(statement, statement->tildeToken, statement->expression, Prefix);
3005 pushScriptElement(current);
3010 return m_enableScriptExpressions;
3015 if (!m_enableScriptExpressions)
3019 makeUnaryExpression(statement, statement->notToken, statement->expression, Prefix);
3023 pushScriptElement(current);
3028 return m_enableScriptExpressions;
3033 if (!m_enableScriptExpressions)
3037 makeUnaryExpression(statement, statement->typeofToken, statement->expression, Prefix);
3041 pushScriptElement(current);
3046 return m_enableScriptExpressions;
3051 if (!m_enableScriptExpressions)
3055 makeUnaryExpression(statement, statement->deleteToken, statement->expression, Prefix);
3059 pushScriptElement(current);
3064 return m_enableScriptExpressions;
3069 if (!m_enableScriptExpressions)
3073 makeUnaryExpression(statement, statement->voidToken, statement->expression, Prefix);
3077 pushScriptElement(current);
3082 return m_enableScriptExpressions;
3087 if (!m_enableScriptExpressions)
3091 makeUnaryExpression(statement, statement->decrementToken, statement->base, Postfix);
3095 pushScriptElement(current);
3100 return m_enableScriptExpressions;
3105 if (!m_enableScriptExpressions)
3109 makeUnaryExpression(statement, statement->incrementToken, statement->base, Postfix);
3113 pushScriptElement(current);
3118 return m_enableScriptExpressions;
3123 if (!m_enableScriptExpressions)
3126 auto current = makeUnaryExpression(statement, statement->incrementToken, statement->expression,
3131 pushScriptElement(current);
3136 return m_enableScriptExpressions;
3141 if (!m_enableScriptExpressions)
3145 current->addLocation(FileLocationRegion::SemicolonTokenRegion, statement->semicolonToken);
3146 pushScriptElement(current);
3151 return m_enableScriptExpressions;
3156 if (!m_enableScriptExpressions)
3160 current->addLocation(FileLocationRegion::LeftParenthesisRegion, expression->lparenToken);
3161 current->addLocation(FileLocationRegion::RightParenthesisRegion, expression->rparenToken);
3163 if (expression->expression) {
3165 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
3166 removeCurrentScriptNode({});
3169 pushScriptElement(current);
3174 return m_enableScriptExpressions;
3179 if (!m_enableScriptExpressions)
3183 current->addLocation(FileLocationRegion::NewKeywordRegion, expression->newToken);
3185 if (expression->expression) {
3187 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
3188 removeCurrentScriptNode({});
3191 pushScriptElement(current);
3196 return m_enableScriptExpressions;
3201 if (!m_enableScriptExpressions)
3205 current->addLocation(FileLocationRegion::NewKeywordRegion, expression->newToken);
3206 current->addLocation(FileLocationRegion::LeftParenthesisRegion, expression->lparenToken);
3207 current->addLocation(FileLocationRegion::RightParenthesisRegion, expression->rparenToken);
3209 if (expression->arguments) {
3211 current->insertChild(Fields::arguments, scriptNodeStack.takeLast().takeList());
3213 if (expression->base) {
3215 current->insertChild(Fields::base, scriptNodeStack.takeLast().takeVariant());
3218 pushScriptElement(current);
3223 if (!m_enableScriptExpressions)
3228 if (ast->statement) {
3230 current->insertChild(Fields::statement, scriptNodeStack.takeLast().takeVariant());
3232 if (ast->expression) {
3234 current->insertChild(Fields::expression, scriptNodeStack.takeLast().takeVariant());
3237 pushScriptElement(current);
3242 return m_enableScriptExpressions;
3247 if (!m_enableScriptExpressions)
3250 auto current = makeUnaryExpression(statement, statement->decrementToken, statement->expression,
3255 pushScriptElement(current);
3258static const DomEnvironment *environmentFrom(
MutableDomItem &qmlFile)
3260 auto top = qmlFile
.top();
3264 auto domEnvironment = top.as<DomEnvironment>();
3265 if (!domEnvironment) {
3268 return domEnvironment;
3273 if (
auto env = environmentFrom(qmlFile))
3274 return env->qmldirFiles();
3281 QQmlJSLogger *logger,
3282 QQmlJSImporter *importer)
3295 bool QQmlDomAstCreatorWithQQmlJSScope::visit(name *node)
3297 return visitT(node);
3299 void QQmlDomAstCreatorWithQQmlJSScope::endVisit(name *node)
3303QQmlJSASTClassListToVisit
3308 const QQmlJSScope::ConstPtr scope = m_scopeCreator.m_currentScope;
3309 if (!m_domCreator.scriptNodeStack.isEmpty()) {
3310 auto topOfStack = m_domCreator.currentScriptNodeEl();
3311 switch (topOfStack.kind) {
3314 if (scope->scopeType() == QQmlJSScope::ScopeType::QMLScope)
3315 m_domCreator.currentScriptNodeEl().setSemanticScope(scope);
3318 case DomType::ScriptBlockStatement:
3319 case DomType::ScriptForStatement:
3320 case DomType::ScriptForEachStatement:
3321 case DomType::ScriptDoWhileStatement:
3322 case DomType::ScriptWhileStatement:
3324 m_domCreator.currentScriptNodeEl().setSemanticScope(scope);
3329 auto element = m_domCreator.currentScriptNodeEl().value;
3331 if (!scriptElementVariant || !scriptElementVariant->data())
3333 scriptElementVariant->visit([](
auto &&e) {
3334 using U = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
3338 if constexpr (std::is_same_v<U,
3339 ScriptElement::PointerType<
3340 ScriptElements::GenericScriptElement>>) {
3341 if (
auto bodyPtr = e->elementChild(Fields::body)) {
3342 const auto bodyScope = bodyPtr.base()->semanticScope();
3343 e->setSemanticScope(bodyScope);
3354 }
else if (!m_domCreator.nodeStack.isEmpty()) {
3356 [&scope](
auto &&e) {
3357 using U = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
3359 if constexpr (std::is_same_v<U, QmlObject>) {
3360 e.setSemanticScope(scope);
3361 }
else if constexpr (std::is_same_v<U, QmlComponent>) {
3362 e.setSemanticScope(scope);
3363 }
else if constexpr (std::is_same_v<U, MethodInfo>) {
3365 if (
auto scriptElement = e.body->scriptElement()) {
3366 scriptElement.base()->setSemanticScope(scope);
3369 e.setSemanticScope(scope);
3372 m_domCreator.currentNodeEl().item.value);
3378 const QQmlJSScope::ConstPtr scope = m_scopeCreator.m_currentScope;
3382 if (m_domCreator.nodeStack.size() > 1
3383 && m_domCreator.nodeStack.last().item.kind == DomType::Binding) {
3385 [&scope](
auto &&e) {
3386 using U = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
3387 if constexpr (std::is_same_v<U, PropertyDefinition>) {
3393 const bool usePropertyDefinitionScopeInsteadOfTheBindingScope =
3394 QQmlSA::isFunctionScope(scope->scopeType())
3395 && scope->parentScope()
3396 && scope->parentScope()->scopeType() == QQmlSA::ScopeType::QMLScope;
3397 e.setSemanticScope(usePropertyDefinitionScopeInsteadOfTheBindingScope
3398 ? scope->parentScope()
3402 m_domCreator.currentNodeEl(1).item.value);
3404 if (m_domCreator.nodeStack.size() > 0) {
3406 [&scope](
auto &&e) {
3407 using U = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
3408 if constexpr (std::is_same_v<U, PropertyDefinition>) {
3409 e.setSemanticScope(scope);
3410 Q_ASSERT(e.semanticScope());
3411 }
else if constexpr (std::is_same_v<U, MethodInfo>) {
3412 if (e.methodType == MethodInfo::Signal) {
3413 e.setSemanticScope(scope);
3417 m_domCreator.currentNodeEl().item.value);
3426 bool QQmlDomAstCreator::visit(AST::name *ast)
3428 return QQmlDomAstCreatorBase::visit(ast) && visitWithCustomListIteration(ast, this);
3436#undef Q_SCRIPTELEMENT_DISABLE
3437#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
static constexpr DomType kindValue
Path addPrototypePath(const Path &prototypePath)
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)