15#include <QtQml/private/qqmljsast_p.h>
16#include <QtQmlCompiler/private/qqmljsutils_p.h>
19#include <QtCore/QFileInfo>
20#include <QtCore/QScopeGuard>
21#include <QtCore/QLoggingCategory>
32
33
34
35#define Q_SCRIPTELEMENT_DISABLE()
37 qDebug() << "Could not construct the JS DOM at" << __FILE__ << ":" << __LINE__
38 << ", skipping JS elements...";
39 disableScriptElements();
42#define Q_SCRIPTELEMENT_EXIT_IF(check)
44 if (m_enableScriptExpressions && (check)) {
45 Q_SCRIPTELEMENT_DISABLE();
56template<
typename K,
typename V>
57V *valueFromMultimap(QMultiMap<K, V> &mmap,
const K &key, index_type idx)
61 auto it = mmap.find(key);
62 auto end = mmap.end();
67 while (it2 != end && it2.key() == key) {
73 for (index_type i = idx + 1; i < nEl; ++i)
85static QString toString(
const UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char(
'.'))
89 for (
const UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) {
90 if (iter != qualifiedId)
99static QString typeToString(AST::Type *t)
102 QString res = toString(t->typeId);
104 if (UiQualifiedId *arg = t->typeArgument)
105 res += u'<' + toString(arg) + u'>';
110SourceLocation combineLocations(SourceLocation s1, SourceLocation s2)
112 return combine(s1, s2);
115SourceLocation combineLocations(Node *n)
117 return combineLocations(n->firstSourceLocation(), n->lastSourceLocation());
121 const SourceLocation &dotToken,
124 SourceLocation s1, s2;
125 left.visitConst([&s1](
auto &&el) { s1 = el->mainRegionLocation(); });
126 right.visitConst([&s2](
auto &&el) { s2 = el->mainRegionLocation(); });
129 result->addLocation(OperatorTokenRegion, dotToken);
131 result->setLeft(left);
132 result->setRight(right);
137
138
139
141fieldMemberExpressionForQualifiedId(
const AST::UiQualifiedId *qualifiedId)
145 for (
auto exp = qualifiedId; exp; exp = exp->next) {
146 const SourceLocation identifierLoc = exp->identifierToken;
148 id->setName(exp->name);
154 bindable = wrapIntoFieldMemberExpression(bindable, exp->dotToken,
155 ScriptElementVariant::fromElement(id));
163 Q_ASSERT_X(idx < nodeStack.size() && idx >= 0,
"currentQmlObjectOrComponentEl",
164 "Stack does not contain enough elements!");
165 int i = nodeStack.size() - idx;
167 DomType k = nodeStack.at(i).item.kind;
168 if (k == DomType::QmlObject || k == DomType::QmlComponent)
171 Q_ASSERT_X(
false,
"currentQmlObjectEl",
"No QmlObject or component in stack");
172 return nodeStack.last();
177 Q_ASSERT_X(i < nodeStack.size() && i >= 0,
"currentNode",
"Stack does not contain element!");
178 return nodeStack[nodeStack.size() - i - 1];
183 Q_ASSERT_X(i < scriptNodeStack.size() && i >= 0,
"currentNode",
184 "Stack does not contain element!");
185 return scriptNodeStack[scriptNodeStack.size() - i - 1];
190 Q_ASSERT_X(i < nodeStack.size() && i >= 0,
"currentNode",
191 "Stack does not contain element!");
192 return nodeStack[nodeStack.size() - i - 1].item;
197 Q_ASSERT_X(!nodeStack.isEmpty(), className,
"popCurrentNode() without any node");
199 Q_ASSERT(nodeStack.last().item.kind == *expectedType);
200 nodeStack.removeLast();
206 Q_ASSERT_X(!scriptNodeStack.isEmpty(), className,
207 "popCurrentScriptNode() without any node");
209 Q_ASSERT(scriptNodeStack.last().kind == *expectedType);
210 scriptNodeStack.removeLast();
214
215
216
217
218
219
220
221
222
223
224
229 auto e = element.base();
232 qCDebug(creatorLog) <<
"Finalizing script expression with path:"
233 << FileLocations::canonicalPathForTesting(ownerFileLocations)
234 .append(pathFromOwner.toString());
235 e->updatePathFromOwner(pathFromOwner);
236 e->createFileLocations(ownerFileLocations);
254 switch (currentNode().kind) {
263 qCWarning(domLog) <<
"unexpected type" << domTypeToString(currentNode().kind);
266 base = currentNodeEl().fileLocations;
270 && (p2.checkHeadName(Fields::children) || p2.checkHeadName(Fields::objects)
271 || p2.checkHeadName(Fields::value) || p2.checkHeadName(Fields::annotations)
272 || p2.checkHeadName(Fields::children)))
274 else if (p
.last().checkHeadName(Fields::value)
278 qCWarning(domLog) <<
"unexpected path to QmlObject in createMap" << p;
282 qCWarning(domLog) <<
"unexpected path to QmlObject in createMap" << p;
288 base = currentNodeEl().fileLocations;
301 base = currentEl<
QmlObject>().fileLocations;
309 qCWarning(domLog) <<
"Unexpected type in createMap:" << domTypeToString(k);
313 return createMap(base, relative, n);
325 QFileInfo fInfo(qmlFile.canonicalFilePath());
326 QString componentName = fInfo.baseName();
328 Path p = qmlFilePtr->addComponent(QmlComponent(componentName), AddOption::KeepExisting,
331 Q_ASSERT_X(newC
.item(), className,
"could not recover component added with addComponent");
335 pushEl(p, *cPtr, program);
337 auto envPtr = qmlFile.environment().ownerAs<DomEnvironment>();
338 const bool loadDependencies =
341 if (!fInfo.canonicalPath().isEmpty()) {
342 Import selfDirImport(QmlUri::fromDirectoryString(fInfo.canonicalPath()));
344 qmlFilePtr->addImport(selfDirImport);
346 if (loadDependencies) {
347 const QString currentFile = envPtr->domCreationOption() == Extended
348 ? QQmlJSUtils::qmlBuildPathFromSourcePath(
349 envPtr->semanticAnalysis().m_mapper.get(),
350 qmlFile.canonicalFilePath())
351 : qmlFile.canonicalFilePath();
353 const QDir implicitImportDir = QFileInfo(currentFile).dir();
354 const QString implicitImportDirPath = implicitImportDir.canonicalPath();
355 envPtr->loadFile(FileToLoad::fromFileSystem(envPtr, implicitImportDirPath),
359 if (implicitImportDir.exists(u"qmldir"_s)) {
360 const QString implicitImportQmldir = implicitImportDirPath + u"/qmldir"_s;
361 envPtr->loadFile(FileToLoad::fromFileSystem(envPtr, implicitImportQmldir),
367 for (Import i : qmlFile.environment().ownerAs<DomEnvironment>()->implicitImports()) {
369 qmlFilePtr->addImport(i);
371 if (loadDependencies)
372 envPtr->loadModuleDependency(i.uri.moduleUri(), i.version, DomItem::Callback());
374 if (m_loadFileLazily && loadDependencies) {
375 envPtr->loadPendingDependencies();
376 envPtr->commitToBase(qmlFile.environment().item());
385 QmlComponent &comp = current<QmlComponent>();
386 for (
const Pragma &p : qmlFilePtr->pragmas()) {
387 if (p.name.compare(u"singleton", Qt::CaseInsensitive) == 0) {
388 comp.setIsSingleton(
true);
389 comp.setIsCreatable(
false);
392 *newC.mutableAs<QmlComponent>() = comp;
394 Q_ASSERT_X(nodeStack.isEmpty(), className,
"ui program did not finish node stack");
399 QStringList valueList;
400 for (
auto t = el->values; t; t = t->next)
401 valueList << t->value.toString();
403 auto fileLocation = createMap(
404 DomType::Pragma, qmlFilePtr->addPragma(Pragma(el->name.toString(), valueList)), el);
407 if (el->colonToken.isValid()) {
411 for (
auto t = el->values; t; t = t->next) {
412 auto subMap = createMap(fileLocation, Path().withField(Fields::values).withIndex(i), t);
422 Version v(Version::Latest, Version::Latest);
423 if (el->version && el->version->version.hasMajorVersion())
424 v.majorVersion = el->version->version.majorVersion();
425 if (el->version && el->version->version.hasMinorVersion())
426 v.minorVersion = el->version->version.minorVersion();
428 auto envPtr = qmlFile.environment().ownerAs<DomEnvironment>();
429 const bool loadDependencies =
432 if (el->importUri !=
nullptr) {
434 Import::fromUriString(toString(el->importUri), v, el->importId.toString());
435 fileLocation = createMap(DomType::Import, qmlFilePtr->addImport(import), el);
437 if (loadDependencies) {
438 envPtr->loadModuleDependency(import.uri.moduleUri(), import.version,
439 DomItem::Callback());
444 Import::fromFileString(el->fileName.toString(), el->importId.toString());
445 fileLocation = createMap(DomType::Import, qmlFilePtr->addImport(import), el);
447 if (loadDependencies) {
448 const QString currentFileDir =
449 QFileInfo(qmlFile.canonicalFilePath()).dir().canonicalPath();
450 envPtr->loadFile(FileToLoad::fromFileSystem(
451 envPtr, import.uri.absoluteLocalPath(currentFileDir)),
456 if (m_loadFileLazily && loadDependencies) {
457 envPtr->loadPendingDependencies();
458 envPtr->commitToBase(qmlFile.environment().item());
461 if (el->importToken.isValid())
464 if (el->asToken.isValid())
467 if (el->importIdToken.isValid())
480 case AST::UiPublicMember::Signal: {
482 m.name = el->name.toString();
483 m.typeName = toString(el->memberType);
484 m.isReadonly = el->isReadonly();
486 m.methodType = MethodInfo::Signal;
487 m.isList = el->typeModifier == QLatin1String(
"list");
490 pushEl(p, *mPtr, el);
492 const auto fileLocations = nodeStack.last().fileLocations;
495 if (el->lparenToken.isValid())
497 if (el->rparenToken.isValid())
501 AST::UiParameterList *args = el->parameters;
504 param.name = args->name.toString();
505 param.typeName = args->type ? args->type->toString() : QString();
506 index_type idx = index_type(mInfo.parameters.size());
507 if (!args->colonToken.isValid())
509 mInfo.parameters.append(param);
511 Path::fromField(Fields::parameters).withIndex(idx));
515 if (args->colonToken.isValid())
523 case AST::UiPublicMember::Property: {
525 p.name = el->name.toString();
526 p.typeName = toString(el->memberType);
527 p.isReadonly = el->isReadonly();
530 p.isList = el->typeModifier == QLatin1String(
"list");
534 if (!el->typeModifier.isEmpty())
535 p.typeName = el->typeModifier.toString() + QChar(u'<') + p.typeName + QChar(u'>');
537 Path pPathFromOwner =
539 if (m_enableScriptExpressions) {
541 qmlObjectType->insertChild(Fields::typeName,
542 fieldMemberExpressionForQualifiedId(el->memberType));
545 pPathFromOwner.withField(Fields::nameIdentifiers), rootMap)
);
548 m_skipBindingIdentifiers = el->binding;
550 pushEl(pPathFromOwner, *pPtr, el);
552 el->propertyToken());
554 el->identifierToken);
558 if (el->typeModifierToken.isValid())
561 qmlFile.addError(std::move(astParseErrors()
562 .warning(tr(
"id is a special attribute, that should not be "
563 "used as property name"))
564 .withPath(currentNodeEl().path)));
575 el->overrideToken());
583 el->requiredToken());
587 el->readonlyToken());
591 SourceLocation loc = combineLocations(el->statement);
592 QStringView code = qmlFilePtr->code();
595 code.mid(loc.offset, loc.length), qmlFilePtr->engine(), el->statement,
596 qmlFilePtr->astComments(), ScriptExpression::ExpressionType::BindingExpression,
601 FileLocations::
Tree bLoc = createMap(DomType::Binding, bPathFromOwner, el->statement);
603 FileLocations::
Tree valueLoc = FileLocations::ensure(bLoc, Path::fromField(Fields::value));
607 nodeStack.append({ std::move(bPathFromOwner), *bPtr, std::move(bLoc) });
619 if (m_enableScriptExpressions
620 && (scriptNodeStack.size() != 1 || scriptNodeStack.last().isList())) {
623 if (m_enableScriptExpressions) {
624 b.scriptExpressionValue()->setScriptElement(finalizeScriptExpression(
625 currentScriptNodeEl().takeVariant(), Path().withField(Fields::scriptElement),
626 FileLocations::ensure(currentNodeEl().fileLocations,
627 Path().withField(Fields::value))));
628 removeCurrentScriptNode({});
633 valueFromMultimap(containingObject.m_bindings, b.name(), currentIndex());
635 removeCurrentNode({});
637 Node::accept(el->parameters,
this);
639 if ((el->binding || el->statement)
640 && nodeStack.last().item.kind == DomType::PropertyDefinition) {
642 if (!pDef.annotations.isEmpty()) {
644 duplicate.setName(QLatin1String(
"duplicate"));
646 auto it = obj.m_bindings.find(pDef.name);
647 if (it != obj.m_bindings.end()) {
648 for (QmlObject ann : pDef.annotations) {
649 ann.addAnnotation(duplicate);
650 it->addAnnotation(currentEl<QmlObject>()
651 .path.withField(Fields::bindings)
653 .withIndex(obj.m_bindings.values(pDef.name).size() - 1),
660 QmlStackElement &sEl = nodeStack.last();
661 switch (sEl.item.kind) {
665 valueFromMultimap(obj.m_propertyDefs, pDef.name, sEl.path.last().headIndex());
667 *pDefPtr =
std::move(pDef);
671 MethodInfo *mPtr = valueFromMultimap(obj.m_methods, m.name, sEl.path.last().headIndex());
673 *mPtr =
std::move(m);
678 removeCurrentNode({});
683 endVisitForLists(list);
688 ++m_nestedFunctionDepth;
689 if (!m_enableScriptExpressions)
697 Q_ASSERT(!scriptNodeStack.isEmpty() || !fExpression->body);
699 if (fExpression->body) {
700 if (currentScriptNodeEl().isList()) {
704 combineLocations(fExpression->lbraceToken, fExpression->rbraceToken));
705 body->setStatements(currentScriptNodeEl().takeList());
706 if (
auto semanticScope = body->statements().semanticScope())
707 body->setSemanticScope(semanticScope);
709 removeCurrentScriptNode({});
712 auto result = currentScriptNodeEl().takeVariant();
713 removeCurrentScriptNode({});
716 Q_UNREACHABLE_RETURN({});
721 combineLocations(fExpression->lbraceToken, fExpression->rbraceToken));
727 --m_nestedFunctionDepth;
728 if (!m_enableScriptExpressions)
732 if (fExpression->identifierToken.isValid())
733 current->addLocation(IdentifierRegion, fExpression->identifierToken);
734 if (fExpression->functionToken.isValid())
735 current->addLocation(FunctionKeywordRegion, fExpression->functionToken);
736 if (fExpression->starToken.isValid())
737 current->addLocation(StarTokenRegion, fExpression->starToken);
738 if (fExpression->lparenToken.isValid())
739 current->addLocation(LeftParenthesisRegion, fExpression->lparenToken);
740 if (fExpression->rparenToken.isValid())
741 current->addLocation(RightParenthesisRegion, fExpression->rparenToken);
742 if (fExpression->lbraceToken.isValid())
743 current->addLocation(LeftBraceRegion, fExpression->lbraceToken);
744 if (fExpression->rbraceToken.isValid())
745 current->addLocation(RightBraceRegion, fExpression->rbraceToken);
746 if (fExpression->typeAnnotation) {
747 current->addLocation(TypeIdentifierRegion,
748 combineLocations(fExpression->typeAnnotation->type));
752 current->insertChild(Fields::body, prepareBodyForFunction(fExpression));
754 if (fExpression->typeAnnotation) {
756 current->insertChild(Fields::returnType, currentScriptNodeEl().takeVariant());
757 scriptNodeStack.removeLast();
759 if (fExpression->formals) {
761 current->insertChild(Fields::parameters, currentScriptNodeEl().takeList());
762 scriptNodeStack.removeLast();
765 if (!fExpression->name.isEmpty())
766 current->insertValue(Fields::name, fExpression->name);
768 pushScriptElement(current);
774 if (m_nestedFunctionDepth > 0) {
775 return visit(
static_cast<FunctionExpression *>(fDef));
777 ++m_nestedFunctionDepth;
778 const QStringView code(qmlFilePtr->code());
780 m.name = fDef->name.toString();
781 if (AST::TypeAnnotation *tAnn = fDef->typeAnnotation) {
782 if (AST::Type *t = tAnn->type)
783 m.typeName = typeToString(t);
786 m.methodType = MethodInfo::Method;
789 SourceLocation bodyLoc = fDef->body ? combineLocations(fDef->body)
790 : combineLocations(fDef->lbraceToken, fDef->rbraceToken);
792 code.mid(bodyLoc.offset, bodyLoc.length), qmlFilePtr->engine(), fDef->body,
793 qmlFilePtr->astComments(), ScriptExpression::ExpressionType::FunctionBody, bodyLoc);
795 if (fDef->typeAnnotation) {
796 SourceLocation typeLoc = combineLocations(fDef->typeAnnotation);
798 code.mid(typeLoc.offset, typeLoc.length), qmlFilePtr->engine(),
799 fDef->typeAnnotation, qmlFilePtr->astComments(),
800 ScriptExpression::ExpressionType::ReturnType, typeLoc);
805 pushEl(mPathFromOwner, *mPtr,
808 if (fDef->identifierToken.isValid())
812 if (fDef->functionToken.isValid())
814 if (fDef->starToken.isValid())
816 if (fDef->lparenToken.length != 0)
818 if (fDef->rparenToken.length != 0)
820 if (fDef->lbraceToken.length != 0)
822 if (fDef->rbraceToken.length != 0)
824 if (fDef->typeAnnotation)
827 AST::FormalParameterList *args = fDef->formals;
830 param.name = args->element->bindingIdentifier.toString();
831 if (AST::TypeAnnotation *tAnn = args->element->typeAnnotation) {
832 if (AST::Type *t = tAnn->type)
833 param.typeName = typeToString(t);
835 if (args->element->initializer) {
836 SourceLocation loc = combineLocations(args->element->initializer);
838 code.mid(loc.offset, loc.length), qmlFilePtr->engine(),
839 args->element->initializer, qmlFilePtr->astComments(),
840 ScriptExpression::ExpressionType::ArgInitializer, loc);
842 if (args->element->type == AST::PatternElement::SpreadElement)
844 SourceLocation parameterLoc = combineLocations(args->element);
846 code.mid(parameterLoc.offset, parameterLoc.length), qmlFilePtr->engine(),
847 args->element, qmlFilePtr->astComments(),
848 ScriptExpression::ExpressionType::ArgumentStructure, parameterLoc);
850 index_type idx = index_type(mInfo.parameters.size());
851 mInfo.parameters.append(param);
853 Path::fromField(Fields::parameters).withIndex(idx));
855 if (args->element->identifierToken.isValid())
857 if (args->element->typeAnnotation)
866 if (AST::cast<VariableStatement *>(el->sourceElement)) {
867 qmlFile.addError(astParseErrors().warning(
868 "JavaScript declarations are not allowed in QML elements"_L1));
876 if (
auto data = variant.data()) {
877 if (
auto genericElement =
878 std::get_if<std::shared_ptr<ScriptElements::GenericScriptElement>>(&*data)) {
887 if (m_nestedFunctionDepth > 1) {
888 endVisit(
static_cast<FunctionExpression *>(fDef));
891 --m_nestedFunctionDepth;
894 FileLocations::ensure(currentNodeEl().fileLocations, Path().withField(Fields::body));
895 const Path bodyPath =
Path().withField(Fields::scriptElement);
897 if (!m_enableScriptExpressions)
901 m.body->setScriptElement(
902 finalizeScriptExpression(prepareBodyForFunction(fDef), bodyPath, bodyTree));
904 if (fDef->typeAnnotation) {
906 Path().withField(Fields::returnType));
907 const Path pathToReturnType =
Path().withField(Fields::scriptElement);
911 finalizeScriptExpression(variant, pathToReturnType, argLoc);
912 m.returnType->setScriptElement(variant);
913 removeCurrentScriptNode({});
917 const auto parameterList = scriptNodeStack.takeLast().takeList();
918 const auto ¶meterQList = parameterList.qList();
919 size_t size = (size_t)parameterQList.size();
920 for (size_t idx = size - 1; idx < size; --idx) {
922 nodeStack.last().fileLocations,
923 Path().withField(Fields::parameters).withIndex(idx).withField(Fields::value));
924 const Path pathToArgument =
Path().withField(Fields::scriptElement);
927 setFormalParameterKind(variant);
928 finalizeScriptExpression(variant, pathToArgument, argLoc);
929 m.parameters[idx].value->setScriptElement(variant);
934 if (m_enableScriptExpressions && !scriptNodeStack.empty()) {
941 if (AST::cast<VariableStatement *>(el->sourceElement))
947 valueFromMultimap(obj.m_methods, m.name, nodeStack.last().path.last().headIndex());
956 scope.setName(toString(el->qualifiedTypeNameId));
960 if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last()) {
962 QList<QmlObject> *vals =
std::get<
Binding>(currentNode().value).arrayValue();
964 int idx = vals->size();
966 sPathFromOwner = currentNodeEl().path.withField(Fields::value).withIndex(idx);
967 sPtr = &((*vals)[idx]);
970 Q_ASSERT_X(
false, className,
971 "expected an array binding with a valid QList<QmlScope> as value");
974 Q_ASSERT_X(
false, className,
"expected an array binding as last node on the stack");
977 DomValue &containingObject = currentQmlObjectOrComponentEl().item;
978 switch (containingObject.kind) {
980 sPathFromOwner =
std::get<QmlComponent>(containingObject.value).addObject(scope, &sPtr);
983 sPathFromOwner =
std::get<
QmlObject>(containingObject.value).addChild(scope, &sPtr);
988 Path pathFromContainingObject = sPathFromOwner.mid(currentNodeEl().path.length());
990 FileLocations::ensure(currentNodeEl().fileLocations, pathFromContainingObject);
992 el->qualifiedTypeNameId->identifierToken);
994 Q_ASSERT_X(sPtr, className,
"could not recover new scope");
996 if (m_enableScriptExpressions) {
997 auto qmlObjectType = makeGenericScriptElement(el->qualifiedTypeNameId,
DomType::ScriptType);
998 qmlObjectType->insertChild(Fields::typeName,
999 fieldMemberExpressionForQualifiedId(el->qualifiedTypeNameId));
1002 sPathFromOwner.withField(Fields::nameIdentifiers), rootMap)
);
1004 pushEl(sPathFromOwner, *sPtr, el);
1006 if (el->initializer) {
1008 el->initializer->lbraceToken);
1010 el->initializer->rbraceToken);
1012 loadAnnotations(el);
1019 int idx = currentIndex();
1020 if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last() + 1) {
1023 QList<QmlObject> *vals = b.arrayValue();
1024 Q_ASSERT_X(vals, className,
1025 "expected an array binding with a valid QList<QmlScope> as value");
1028 Q_ASSERT_X(
false, className,
"expected an array binding as last node on the stack");
1031 DomValue &containingObject = currentNodeEl(1).item;
1032 Path p = currentNodeEl().path;
1033 switch (containingObject.kind) {
1035 if (p
[p
.length() - 2
] == Path::fromField(Fields::objects))
1036 std::get<QmlComponent>(containingObject.value).m_objects[idx] = obj;
1041 if (p
[p
.length() - 2
] == Path::fromField(Fields::children))
1042 std::get<
QmlObject>(containingObject.value).m_children[idx] = obj;
1054 const UiQualifiedId *identifiers,
Binding *bindingPtr)
1056 const bool skipBindingIdentifiers =
std::exchange(m_skipBindingIdentifiers,
false);
1057 if (!m_enableScriptExpressions || skipBindingIdentifiers)
1062 bindable, pathFromOwner.withField(Fields::bindingIdentifiers), rootMap)
);
1069 value.setName(toString(el->qualifiedTypeNameId));
1073 if (bPtr->name() == u"id")
1074 qmlFile.addError(std::move(astParseErrors()
1075 .warning(tr(
"id attributes should only be a lower case letter "
1076 "followed by letters, numbers or underscore, "
1077 "assuming they refer to an id property"))
1078 .withPath(bPathFromOwner)));
1079 setBindingIdentifiers(bPathFromOwner, el->qualifiedId, bPtr);
1081 pushEl(bPathFromOwner, *bPtr, el);
1087 loadAnnotations(el);
1089 Q_ASSERT_X(objValue, className,
"could not recover objectValue");
1090 objValue->setName(toString(el->qualifiedTypeNameId));
1092 if (m_enableScriptExpressions) {
1093 auto qmlObjectType = makeGenericScriptElement(el->qualifiedTypeNameId,
DomType::ScriptType);
1094 qmlObjectType->insertChild(Fields::typeName,
1095 fieldMemberExpressionForQualifiedId(el->qualifiedTypeNameId));
1098 bPathFromOwner.withField(Fields::value).withField(Fields::nameIdentifiers), rootMap)
);
1102 pushEl(bPathFromOwner.withField(Fields::value), *objValue, el->initializer);
1103 if (m_enableScriptExpressions && el->initializer) {
1105 el->initializer->lbraceToken);
1107 el->initializer->rbraceToken);
1120 index_type idx = currentNodeEl(1).path.last().headIndex();
1121 Binding *bPtr = valueFromMultimap(containingObj.m_bindings, b.name(), idx);
1130 ++m_nestedFunctionDepth;
1131 QStringView code = qmlFilePtr->code();
1132 SourceLocation loc = combineLocations(el->statement);
1134 code.mid(loc.offset, loc.length), qmlFilePtr->engine(), el->statement,
1135 qmlFilePtr->astComments(), ScriptExpression::ExpressionType::BindingExpression, loc);
1137 Binding *bindingPtr =
nullptr;
1138 Id *idPtr =
nullptr;
1140 if (bindingV.name() == u"id") {
1141 Node *exp = script->ast();
1142 if (ExpressionStatement *eStat = cast<ExpressionStatement *>(script->ast()))
1143 exp = eStat->expression;
1144 if (IdentifierExpression *iExp = cast<IdentifierExpression *>(exp)) {
1145 QmlStackElement &containingObjectEl = currentEl<
QmlObject>();
1147 QString idName = iExp->name.toString();
1148 Id idVal(idName, qmlFile.canonicalPath().withPath(containingObject.pathFromOwner()));
1149 idVal.value = script;
1150 containingObject.setIdStr(idName);
1152 combineLocations(el->qualifiedId));
1156 combineLocations(el->statement));
1157 QmlComponent &comp = current<QmlComponent>();
1159 QRegularExpression idRe(QRegularExpression::anchoredPattern(
1160 QStringLiteral(uR"([[:lower:]][[:lower:][:upper:]0-9_]*)")));
1161 auto m = idRe.matchView(iExp->name);
1162 if (!m.hasMatch()) {
1163 qmlFile.addError(std::move(
1165 .warning(tr(
"id attributes should only be a lower case letter "
1166 "followed by letters, numbers or underscore, not %1")
1168 .withPath(pathFromOwner)));
1173 Q_ASSERT_X(bindingPtr, className,
"binding could not be retrieved");
1174 qmlFile.addError(std::move(
1176 .warning(tr(
"id attributes should only be a lower case letter "
1177 "followed by letters, numbers or underscore, not %1 "
1178 "%2, assuming they refer to a property")
1179 .arg(script->code(), script->astRelocatableDump()))
1180 .withPath(pathFromOwner)));
1185 QmlStackElement &containingObjectEl = currentEl<
QmlObject>();
1187 Path pathFromContainingObject = pathFromOwner.mid(containingObjectEl.path.length());
1188 auto bindingFileLocation =
1191 el->qualifiedId->identifierToken);
1194 setBindingIdentifiers(pathFromOwner, el->qualifiedId, bindingPtr);
1196 Q_ASSERT_X(bindingPtr, className,
"binding could not be retrieved");
1199 pushEl(pathFromOwner, *bindingPtr, el);
1201 pushEl(pathFromOwner, *idPtr, el);
1204 loadAnnotations(el);
1212 if (m_enableScriptExpressions
1213 && (scriptNodeStack.size() != 1 || currentScriptNodeEl().isList()))
1215 if (m_enableScriptExpressions) {
1216 FileLocations::
Tree valueLoc = FileLocations::ensure(currentNodeEl().fileLocations,
1217 Path().withField(Fields::value));
1218 value->setScriptElement(finalizeScriptExpression(currentScriptNodeEl().takeVariant(),
1219 Path().withField(Fields::scriptElement),
1221 removeCurrentScriptNode({});
1227 --m_nestedFunctionDepth;
1228 DomValue &lastEl = currentNode();
1229 index_type idx = currentIndex();
1236 Binding *bPtr = valueFromMultimap(containingObject.m_bindings, b.name(), idx);
1240 Id &id =
std::get<
Id>(lastEl.value);
1242 setScriptExpression(id.value);
1244 QmlComponent &comp = current<QmlComponent>();
1245 Id *idPtr = valueFromMultimap(comp.m_ids, id.name, idx);
1252 if (m_enableScriptExpressions && !scriptNodeStack.empty()) {
1255 removeCurrentNode({});
1260 QList<QmlObject> value;
1263 Path bindingPathFromOwner =
1265 if (bindingV.name() == u"id")
1266 qmlFile.addError(std::move(
1268 .error(tr(
"id attributes should have only simple strings as values"))
1269 .withPath(bindingPathFromOwner)));
1271 setBindingIdentifiers(bindingPathFromOwner, el->qualifiedId, bindingPtr);
1273 pushEl(bindingPathFromOwner, *bindingPtr, el);
1275 loadAnnotations(el);
1277 createMap(currentNodeEl().fileLocations, Path::fromField(Fields::value),
nullptr);
1280 arrayBindingLevels.append(nodeStack.size());
1286 index_type idx = currentIndex();
1288 Binding *bPtr = valueFromMultimap(current<
QmlObject>().m_bindings, b.name(), idx);
1290 arrayBindingLevels.removeLast();
1296 endVisitForLists(list);
1306 endVisitForLists<AST::PatternElementList>(list, [](AST::PatternElementList *current) {
1308 toCollect +=
bool(current->elision);
1309 toCollect +=
bool(current->element);
1316 endVisitForLists(list);
1320
1321
1322
1323
1324
1328 expression->firstSourceLocation(), expression->lastSourceLocation());
1329 id->setName(expression->toString());
1336 if (!m_enableScriptExpressions)
1345 eDecl.setName(el->name.toString());
1347 Path enumPathFromOwner =
1349 pushEl(enumPathFromOwner, *ePtr, el);
1354 loadAnnotations(el);
1360 EnumDecl &e =
std::get<EnumDecl>(currentNode().value);
1362 valueFromMultimap(current<QmlComponent>().m_enumerations, e.name(), currentIndex());
1370 EnumItem it(el->member.toString(), el->value,
1373 EnumDecl &eDecl =
std::get<EnumDecl>(currentNode().value);
1375 const auto map = createMap(DomType::EnumItem, itPathFromDecl,
nullptr);
1376 if (el->commaToken.isValid())
1378 if (el->memberToken.isValid())
1380 if (el->equalToken.isValid())
1382 if (el->valueToken.isValid())
1385 map, MainRegion, combine(combine(el->memberToken, el->commaToken), el->valueToken));
1391 Node::accept(el->next,
this);
1396 QStringList els = current<QmlComponent>().name().split(QLatin1Char(
'.'));
1397 els.append(el->name.toString());
1398 QString cName = els.join(QLatin1Char(
'.'));
1399 QmlComponent *compPtr;
1400 Path p = qmlFilePtr->addComponent(QmlComponent(cName), AddOption::KeepExisting, &compPtr);
1402 if (m_enableScriptExpressions) {
1403 auto inlineComponentType =
1407 typeName->setName(el->name);
1408 inlineComponentType->insertChild(Fields::typeName,
1412 p.withField(Fields::nameIdentifiers), rootMap)
);
1415 pushEl(p, *compPtr, el);
1417 el->componentToken);
1419 loadAnnotations(el);
1425 QmlComponent &component =
std::get<QmlComponent>(currentNode().value);
1426 QStringList nameEls = component.name().split(QChar::fromLatin1(
'.'));
1427 QString key = nameEls.mid(1).join(QChar::fromLatin1(
'.'));
1428 QmlComponent *cPtr = valueFromMultimap(qmlFilePtr->lazyMembers().m_components, key, currentIndex());
1437 pDef.name = el->name.toString();
1440 Path pathFromOwner =
1442 createMap(DomType::PropertyDefinition, pathFromOwner, el);
1449 a.setName(QStringLiteral(u"@") + toString(el->qualifiedTypeNameId));
1451 DomValue &containingElement = currentNode();
1454 switch (containingElement.kind) {
1456 pathFromOwner =
std::get<
QmlObject>(containingElement.value).addAnnotation(a, &aPtr);
1459 pathFromOwner =
std::get<
Binding>(containingElement.value)
1460 .addAnnotation(currentNodeEl().path, a, &aPtr);
1464 std::get<
Id>(containingElement.value).addAnnotation(currentNodeEl().path, a, &aPtr);
1468 .addAnnotation(currentNodeEl().path, a, &aPtr);
1471 pathFromOwner =
std::get<
MethodInfo>(containingElement.value)
1472 .addAnnotation(currentNodeEl().path, a, &aPtr);
1475 qCWarning(domLog) <<
"Unexpected container object for annotation:"
1476 << domTypeToString(containingElement.kind);
1479 pushEl(pathFromOwner, *aPtr, el);
1485 DomValue &containingElement = currentNode(1);
1488 switch (containingElement.kind) {
1489 case DomType::QmlObject:
1490 std::get<QmlObject>(containingElement.value).m_annotations[currentIndex()] = a;
1492 case DomType::Binding:
1493 std::get<Binding>(containingElement.value).m_annotations[currentIndex()] = a;
1496 std::get<Id>(containingElement.value).annotations[currentIndex()] = a;
1498 case DomType::PropertyDefinition:
1499 std::get<PropertyDefinition>(containingElement.value).annotations[currentIndex()] = a;
1501 case DomType::MethodInfo:
1502 std::get<MethodInfo>(containingElement.value).annotations[currentIndex()] = a;
1512 qmlFile.addError(astParseErrors().error(
1513 tr(
"Maximum statement or expression depth exceeded in QmlDomAstCreator")));
1518 endVisitForLists(list);
1523 if (!m_enableScriptExpressions)
1531 if (!m_enableScriptExpressions)
1535 current->addLocation(OperatorTokenRegion, exp->operatorToken);
1537 current->setRight(currentScriptNodeEl().takeVariant());
1538 removeCurrentScriptNode({});
1540 current->setLeft(currentScriptNodeEl().takeVariant());
1541 removeCurrentScriptNode({});
1543 pushScriptElement(current);
1548 if (!m_enableScriptExpressions)
1556 if (!m_enableScriptExpressions)
1561 if (block->statements) {
1563 current->setStatements(currentScriptNodeEl().takeList());
1567 pushScriptElement(current);
1572 if (!m_enableScriptExpressions)
1580 if (!m_enableScriptExpressions)
1584 current->addLocation(FileLocationRegion::ForKeywordRegion, forStatement->forToken);
1585 current->addLocation(FileLocationRegion::LeftParenthesisRegion, forStatement->lparenToken);
1586 current->addLocation(FileLocationRegion::FirstSemicolonTokenRegion,
1587 forStatement->firstSemicolonToken);
1588 current->addLocation(FileLocationRegion::SecondSemicolonRegion,
1589 forStatement->secondSemicolonToken);
1590 current->addLocation(FileLocationRegion::RightParenthesisRegion, forStatement->rparenToken);
1592 if (forStatement->statement) {
1594 current->setBody(currentScriptNodeEl().takeVariant());
1595 removeCurrentScriptNode(
std::nullopt);
1598 if (forStatement->expression) {
1600 current->setExpression(currentScriptNodeEl().takeVariant());
1601 removeCurrentScriptNode(
std::nullopt);
1604 if (forStatement->condition) {
1606 current->setCondition(currentScriptNodeEl().takeVariant());
1607 removeCurrentScriptNode(
std::nullopt);
1610 if (forStatement->declarations) {
1612 auto variableDeclaration = makeGenericScriptElement(forStatement->declarations,
1618 variableDeclaration->insertChild(Fields::declarations,
std::move(list));
1619 removeCurrentScriptNode({});
1623 if (
auto pe = forStatement->declarations->declaration;
1624 pe && pe->declarationKindToken.isValid()) {
1625 current->addLocation(FileLocationRegion::TypeIdentifierRegion,
1626 pe->declarationKindToken);
1630 if (forStatement->initialiser) {
1632 current->setInitializer(currentScriptNodeEl().takeVariant());
1633 removeCurrentScriptNode(
std::nullopt);
1635 pushScriptElement(current);
1640 if (!m_enableScriptExpressions)
1644 current->setName(expression->name);
1645 pushScriptElement(current);
1651 if (!m_enableScriptExpressions)
1655 current->setLiteralValue(expression->value);
1656 pushScriptElement(current);
1662 if (!m_enableScriptExpressions)
1665 pushScriptElement(makeStringLiteral(expression->value, expression));
1671 if (!m_enableScriptExpressions)
1675 current->setLiteralValue(
nullptr);
1676 pushScriptElement(current);
1682 if (!m_enableScriptExpressions)
1686 current->setLiteralValue(
true);
1687 pushScriptElement(current);
1693 if (!m_enableScriptExpressions)
1697 current->setLiteralValue(
false);
1698 pushScriptElement(current);
1704 if (!m_enableScriptExpressions)
1708 current->setName(expression->id);
1709 pushScriptElement(current);
1715 if (!m_enableScriptExpressions)
1718 pushScriptElement(makeStringLiteral(expression->id, expression));
1724 if (!m_enableScriptExpressions)
1733 if (!m_enableScriptExpressions)
1737 current->insertValue(Fields::regExpPattern, literal->pattern);
1738 current->insertValue(Fields::regExpFlags, literal->flags);
1739 pushScriptElement(current);
1746 if (!m_enableScriptExpressions)
1750 if (expression->thisToken.isValid())
1751 current->addLocation(ThisKeywordRegion, expression->thisToken);
1752 pushScriptElement(current);
1758 if (!m_enableScriptExpressions)
1762 if (expression->superToken.isValid())
1763 current->addLocation(SuperKeywordRegion, expression->superToken);
1764 pushScriptElement(current);
1770 if (!m_enableScriptExpressions)
1774 current->setLiteralValue(expression->id);
1775 pushScriptElement(current);
1781 if (!m_enableScriptExpressions)
1790 const std::function<
int(T *)> &scriptElementsPerEntry)
1792 if (!m_enableScriptExpressions)
1795 auto current = makeScriptList(list);
1796 for (
auto it = list; it; it = it->next) {
1797 const int entriesToCollect = scriptElementsPerEntry ? scriptElementsPerEntry(it) : 1;
1798 for (
int i = 0; i < entriesToCollect; ++i) {
1800 auto last = scriptNodeStack.takeLast();
1802 current.append(last.takeList());
1804 current.append(last.takeVariant());
1809 pushScriptElement(current);
1814 endVisitForLists(list);
1819 if (!m_enableScriptExpressions)
1822 auto currentList = makeScriptList(list);
1824 for (
auto it = list; it; it = it->next) {
1828 pushScriptElement(currentList);
1836 if (!m_enableScriptExpressions)
1843
1844
1845
1846
1848 AST::PatternElement *pe,
1851 if (pe->equalToken.isValid())
1852 current->addLocation(FileLocationRegion::EqualTokenRegion, pe->equalToken);
1854 if (pe->identifierToken.isValid() && !pe->bindingIdentifier.isEmpty()) {
1857 identifier->setName(pe->bindingIdentifier);
1858 current->insertChild(Fields::identifier, ScriptElementVariant::fromElement(identifier));
1860 if (pe->initializer) {
1862 current->insertChild(Fields::initializer, scriptNodeStack.last().takeVariant());
1863 scriptNodeStack.removeLast();
1865 if (pe->typeAnnotation) {
1867 current->insertChild(Fields::type, scriptNodeStack.last().takeVariant());
1868 scriptNodeStack.removeLast();
1870 if (pe->bindingTarget) {
1872 current->insertChild(Fields::bindingElement, scriptNodeStack.last().takeVariant());
1873 scriptNodeStack.removeLast();
1879 if (!m_enableScriptExpressions)
1883 endVisitHelper(pe, element);
1885 if (!m_enableScriptExpressions)
1888 pushScriptElement(element);
1893 if (!m_enableScriptExpressions)
1901 if (!m_enableScriptExpressions)
1905 current->addLocation(LeftParenthesisRegion, ifStatement->lparenToken);
1906 current->addLocation(RightParenthesisRegion, ifStatement->rparenToken);
1907 current->addLocation(ElseKeywordRegion, ifStatement->elseToken);
1908 current->addLocation(IfKeywordRegion, ifStatement->ifToken);
1910 if (ifStatement->ko) {
1912 current->setAlternative(scriptNodeStack.last().takeVariant());
1913 scriptNodeStack.removeLast();
1916 if (ifStatement->ok) {
1918 current->setConsequence(scriptNodeStack.last().takeVariant());
1919 scriptNodeStack.removeLast();
1921 if (ifStatement->expression) {
1923 current->setCondition(scriptNodeStack.last().takeVariant());
1924 scriptNodeStack.removeLast();
1927 pushScriptElement(current);
1932 if (!m_enableScriptExpressions)
1940 if (!m_enableScriptExpressions)
1944 current->addLocation(ReturnKeywordRegion, returnStatement->returnToken);
1946 if (returnStatement->expression) {
1948 current->setExpression(currentScriptNodeEl().takeVariant());
1949 removeCurrentScriptNode({});
1952 pushScriptElement(current);
1957 if (!m_enableScriptExpressions)
1965 if (!m_enableScriptExpressions)
1969 current->addLocation(YieldKeywordRegion, yExpression->yieldToken);
1971 if (yExpression->expression) {
1973 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
1974 removeCurrentScriptNode({});
1977 pushScriptElement(current);
1982 if (!m_enableScriptExpressions)
1990 if (!m_enableScriptExpressions)
1995 current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->dotToken);
1997 if (expression->base) {
1999 current->setLeft(currentScriptNodeEl().takeVariant());
2000 removeCurrentScriptNode({});
2003 auto scriptIdentifier =
2005 scriptIdentifier->setName(expression->name);
2008 pushScriptElement(current);
2013 if (!m_enableScriptExpressions)
2021 if (!m_enableScriptExpressions)
2026 current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->lbracketToken);
2028 if (expression->expression) {
2032 current->setRight(currentScriptNodeEl().takeVariant());
2033 removeCurrentScriptNode({});
2036 if (expression->base) {
2038 current->setLeft(currentScriptNodeEl().takeVariant());
2039 removeCurrentScriptNode({});
2042 pushScriptElement(current);
2047 if (!m_enableScriptExpressions)
2055 if (!m_enableScriptExpressions)
2059 current->addLocation(LeftParenthesisRegion, exp->lparenToken);
2060 current->addLocation(RightParenthesisRegion, exp->rparenToken);
2062 if (exp->arguments) {
2064 current->insertChild(Fields::arguments, currentScriptNodeEl().takeList());
2065 removeCurrentScriptNode({});
2068 current->insertChild(Fields::arguments,
2074 current->insertChild(Fields::callee, currentScriptNodeEl().takeVariant());
2075 removeCurrentScriptNode({});
2078 pushScriptElement(current);
2083 if (!m_enableScriptExpressions)
2091 if (!m_enableScriptExpressions)
2096 if (exp->elements) {
2100 current->insertChild(Fields::elements,
std::move(list));
2102 removeCurrentScriptNode({});
2105 current->insertChild(Fields::elements,
2109 pushScriptElement(current);
2114 if (!m_enableScriptExpressions)
2122 if (!m_enableScriptExpressions)
2127 if (exp->properties) {
2129 current->insertChild(Fields::properties, currentScriptNodeEl().takeList());
2130 removeCurrentScriptNode({});
2133 current->insertChild(Fields::properties,
2137 pushScriptElement(current);
2142 if (!m_enableScriptExpressions)
2150 if (!m_enableScriptExpressions)
2156 endVisitHelper(
static_cast<PatternElement *>(exp), current);
2159 if (!m_enableScriptExpressions)
2164 current->insertChild(Fields::name, currentScriptNodeEl().takeVariant());
2165 removeCurrentScriptNode({});
2168 pushScriptElement(current);
2173 if (!m_enableScriptExpressions)
2181 if (!m_enableScriptExpressions)
2185 current->addLocation(FileLocationRegion::TypeIdentifierRegion, statement->declarationKindToken);
2187 if (statement->declarations) {
2193 current->insertChild(Fields::declarations,
std::move(list));
2195 removeCurrentScriptNode({});
2198 pushScriptElement(current);
2203 if (!m_enableScriptExpressions)
2211 if (!m_enableScriptExpressions)
2216 if (exp->typeArgument) {
2217 current->insertChild(Fields::typeArgumentName,
2218 fieldMemberExpressionForQualifiedId(exp->typeArgument));
2219 current->addLocation(FileLocationRegion::IdentifierRegion, combineLocations(exp->typeArgument));
2223 current->insertChild(Fields::typeName, fieldMemberExpressionForQualifiedId(exp->typeId));
2224 current->addLocation(FileLocationRegion::TypeIdentifierRegion, combineLocations(exp->typeId));
2227 pushScriptElement(current);
2232 if (!m_enableScriptExpressions)
2240 if (!m_enableScriptExpressions)
2244 current->addLocation(DefaultKeywordRegion, exp->defaultToken);
2245 current->addLocation(ColonTokenRegion, exp->colonToken);
2247 if (exp->statements) {
2249 current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
2250 removeCurrentScriptNode({});
2253 pushScriptElement(current);
2258 if (!m_enableScriptExpressions)
2266 if (!m_enableScriptExpressions)
2270 current->addLocation(FileLocationRegion::CaseKeywordRegion, exp->caseToken);
2271 current->addLocation(FileLocationRegion::ColonTokenRegion, exp->colonToken);
2273 if (exp->statements) {
2275 current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
2276 removeCurrentScriptNode({});
2279 if (exp->expression) {
2281 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2282 removeCurrentScriptNode({});
2285 pushScriptElement(current);
2290 if (!m_enableScriptExpressions)
2298 if (!m_enableScriptExpressions)
2301 auto current = makeScriptList(list);
2303 for (
auto it = list; it; it = it->next) {
2305 current.append(scriptNodeStack.takeLast().takeVariant());
2309 pushScriptElement(current);
2314 if (!m_enableScriptExpressions)
2322 if (!m_enableScriptExpressions)
2326 current->addLocation(FileLocationRegion::LeftBraceRegion, exp->lbraceToken);
2327 current->addLocation(FileLocationRegion::RightBraceRegion, exp->rbraceToken);
2329 if (exp->moreClauses) {
2331 current->insertChild(Fields::moreCaseClauses, currentScriptNodeEl().takeList());
2332 removeCurrentScriptNode({});
2335 if (exp->defaultClause) {
2337 current->insertChild(Fields::defaultClause, currentScriptNodeEl().takeVariant());
2338 removeCurrentScriptNode({});
2343 current->insertChild(Fields::caseClauses, currentScriptNodeEl().takeList());
2344 removeCurrentScriptNode({});
2346 pushScriptElement(current);
2351 if (!m_enableScriptExpressions)
2359 if (!m_enableScriptExpressions)
2363 current->addLocation(FileLocationRegion::SwitchKeywordRegion, exp->switchToken);
2364 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2365 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2369 current->insertChild(Fields::caseBlock, currentScriptNodeEl().takeVariant());
2370 removeCurrentScriptNode({});
2372 if (exp->expression) {
2374 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2375 removeCurrentScriptNode({});
2378 pushScriptElement(current);
2383 if (!m_enableScriptExpressions)
2391 if (!m_enableScriptExpressions)
2395 current->addLocation(FileLocationRegion::WhileKeywordRegion, exp->whileToken);
2396 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2397 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2399 if (exp->statement) {
2401 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2402 removeCurrentScriptNode({});
2405 if (exp->expression) {
2407 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2408 removeCurrentScriptNode({});
2411 pushScriptElement(current);
2416 if (!m_enableScriptExpressions)
2424 if (!m_enableScriptExpressions)
2428 current->addLocation(FileLocationRegion::DoKeywordRegion, exp->doToken);
2429 current->addLocation(FileLocationRegion::WhileKeywordRegion, exp->whileToken);
2430 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2431 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2433 if (exp->expression) {
2435 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2436 removeCurrentScriptNode({});
2439 if (exp->statement) {
2441 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2442 removeCurrentScriptNode({});
2445 pushScriptElement(current);
2450 if (!m_enableScriptExpressions)
2458 if (!m_enableScriptExpressions)
2462 current->addLocation(FileLocationRegion::ForKeywordRegion, exp->forToken);
2463 current->addLocation(FileLocationRegion::InOfTokenRegion, exp->inOfToken);
2464 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2465 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2467 if (exp->statement) {
2469 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2470 removeCurrentScriptNode({});
2472 if (exp->expression) {
2474 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2475 removeCurrentScriptNode({});
2480 current->insertChild(Fields::bindingElement, currentScriptNodeEl().takeVariant());
2481 removeCurrentScriptNode({});
2483 if (
auto pe = AST::cast<PatternElement *>(exp->lhs);
2484 pe && pe->declarationKindToken.isValid()) {
2485 current->addLocation(FileLocationRegion::TypeIdentifierRegion,
2486 pe->declarationKindToken);
2490 pushScriptElement(current);
2498 if (m_enableScriptExpressions)
2509 if (!m_enableScriptExpressions)
2513 current->insertChild(Fields::templateLiteral, scriptNodeStack.takeLast().takeVariant());
2515 current->insertChild(Fields::callee, scriptNodeStack.takeLast().takeVariant());
2516 pushScriptElement(current);
2520
2521
2522
2523
2524
2525enum TemplatePartPosition : quint8 {
2531Q_DECLARE_FLAGS(TemplatePartPositions, TemplatePartPosition)
2534
2535
2536
2537
2538static void extractDollarBraceSourceLocationInto(
2540 const SourceLocation &toBeSplit, QStringView code,
2541 TemplatePartPositions templatePartLocation)
2543 if (templatePartLocation & AtEnd || !currentExpression)
2546 const auto offset = toBeSplit.offset + toBeSplit.length - 2;
2547 constexpr auto length = quint32(
std::char_traits<
char>::length(
"${"));
2548 const auto [row, column] = SourceLocation::rowAndColumnFrom(code, offset, toBeSplit);
2549 currentExpression->addLocation(FileLocationRegion::DollarLeftBraceTokenRegion,
2550 SourceLocation{ offset, length, row, column });
2555
2556
2557
2558static void extractRightBacktickSourceLocationInto(
2560 const SourceLocation &toBeSplit, QStringView code,
2561 TemplatePartPositions templatePartLocation)
2563 if (!(templatePartLocation & AtEnd))
2566 const auto offset = toBeSplit.offset + toBeSplit.length - 1;
2567 constexpr auto length = quint32(
std::char_traits<
char>::length(
"`"));
2568 const auto [row, column] = SourceLocation::rowAndColumnFrom(code, offset, toBeSplit);
2569 currentTemplate->addLocation(FileLocationRegion::RightBacktickTokenRegion,
2570 SourceLocation{ offset, length, row, column });
2574
2575
2576
2577static void extractLeftBacktickSourceLocationInto(
2579 const SourceLocation &toBeSplit, TemplatePartPositions templatePartLocation)
2581 if (!(templatePartLocation & AtBeginning))
2584 constexpr auto length = quint32(
std::char_traits<
char>::length(
"`"));
2585 const QQmlJS::SourceLocation leftBacktick{ toBeSplit.offset, length, toBeSplit.startLine,
2586 toBeSplit.startColumn };
2587 currentTemplate->addLocation(FileLocationRegion::LeftBacktickTokenRegion, leftBacktick);
2591
2592
2593
2594
2595static SourceLocation extractRightBraceSourceLocation(
const SourceLocation &toBeSplit,
2596 TemplatePartPositions templatePartLocation)
2598 if (templatePartLocation & AtBeginning)
2599 return SourceLocation{};
2602 return SourceLocation{ toBeSplit.offset, 1, toBeSplit.startLine, toBeSplit.startColumn };
2606
2607
2608
2609
2610static SourceLocation extractStringLocation(
const SourceLocation &toBeSplit, QStringView code,
2611 TemplatePartPositions location)
2615 const quint32 length = toBeSplit.length - (location & AtEnd ? 2 : 3);
2616 const quint32 offset = toBeSplit.offset + 1;
2617 const auto [row, column] = SourceLocation::rowAndColumnFrom(code, offset, toBeSplit);
2618 return SourceLocation{ offset, length, row, column };
2623 if (!m_enableScriptExpressions)
2628 auto currentList = makeScriptList(literal);
2631 const auto children = [&literal]() {
2632 std::vector<AST::TemplateLiteral *> result;
2633 for (
auto it = literal; it; it = it->next) {
2634 result.push_back(it);
2639 SourceLocation rightBrace;
2640 for (
auto it = children.crbegin(); it != children.crend(); ++it) {
2642 const QQmlJS::SourceLocation toBeSplit = (*it)->literalToken;
2645 if ((*it)->expression) {
2647 currentExpression = makeGenericScriptElement((*it)->expression,
2650 currentExpression->insertChild(Fields::expression,
2651 scriptNodeStack.takeLast().takeVariant());
2652 if (rightBrace.isValid()) {
2653 currentExpression->addLocation(FileLocationRegion::RightBraceRegion,
2654 std::exchange(rightBrace, SourceLocation{}));
2659 if (!toBeSplit.isValid())
2662 const TemplatePartPositions location = [&it, &children]() {
2663 TemplatePartPositions result;
2664 if (it == children.crbegin())
2666 if (it ==
std::prev(children.crend()))
2667 result |= AtBeginning;
2671 extractRightBacktickSourceLocationInto(currentTemplate, toBeSplit, qmlFilePtr->code(),
2673 extractLeftBacktickSourceLocationInto(currentTemplate, toBeSplit, location);
2675 extractDollarBraceSourceLocationInto(currentExpression, toBeSplit, qmlFilePtr->code(),
2677 rightBrace = extractRightBraceSourceLocation(toBeSplit, location);
2679 if ((*it)->rawValue.isEmpty())
2682 const SourceLocation stringLocation =
2683 extractStringLocation(toBeSplit, qmlFilePtr->code(), location);
2684 auto currentString =
2686 currentString->insertValue(Fields::value, (*it)->rawValue);
2690 currentList.reverse();
2692 currentTemplate->insertChild(Fields::components, currentList);
2693 pushScriptElement(currentTemplate);
2698 return m_enableScriptExpressions;
2703 if (!m_enableScriptExpressions)
2707 current->addLocation(FileLocationRegion::TryKeywordRegion, statement->tryToken);
2709 if (
auto exp = statement->finallyExpression) {
2710 current->addLocation(FileLocationRegion::FinallyKeywordRegion, exp->finallyToken);
2713 current->insertChild(Fields::finallyBlock, currentScriptNodeEl().takeVariant());
2714 removeCurrentScriptNode({});
2717 if (
auto exp = statement->catchExpression) {
2718 current->addLocation(FileLocationRegion::CatchKeywordRegion, exp->catchToken);
2719 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2720 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2723 current->insertChild(Fields::catchBlock, currentScriptNodeEl().takeVariant());
2724 removeCurrentScriptNode({});
2726 current->insertChild(Fields::catchParameter, currentScriptNodeEl().takeVariant());
2727 removeCurrentScriptNode({});
2730 if (statement->statement) {
2732 current->insertChild(Fields::block, currentScriptNodeEl().takeVariant());
2733 removeCurrentScriptNode({});
2736 pushScriptElement(current);
2742 return m_enableScriptExpressions;
2753 return m_enableScriptExpressions;
2763 return m_enableScriptExpressions;
2768 if (!m_enableScriptExpressions)
2772 current->addLocation(FileLocationRegion::ThrowKeywordRegion, statement->throwToken);
2774 if (statement->expression) {
2776 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2777 removeCurrentScriptNode({});
2780 pushScriptElement(current);
2785 return m_enableScriptExpressions;
2790 if (!m_enableScriptExpressions)
2794 current->addLocation(FileLocationRegion::ColonTokenRegion, statement->colonToken);
2797 label->setName(statement->label);
2801 if (statement->statement) {
2803 current->insertChild(Fields::statement, currentScriptNodeEl().takeVariant());
2804 removeCurrentScriptNode({});
2807 pushScriptElement(current);
2812 return m_enableScriptExpressions;
2817 if (!m_enableScriptExpressions)
2821 current->addLocation(FileLocationRegion::BreakKeywordRegion, statement->breakToken);
2823 if (!statement->label.isEmpty()) {
2826 label->setName(statement->label);
2830 pushScriptElement(current);
2835 return m_enableScriptExpressions;
2840 if (!m_enableScriptExpressions)
2844 current->addLocation(OperatorTokenRegion, commaExpression->commaToken);
2846 if (commaExpression->right) {
2848 current->setRight(currentScriptNodeEl().takeVariant());
2849 removeCurrentScriptNode({});
2852 if (commaExpression->left) {
2854 current->setLeft(currentScriptNodeEl().takeVariant());
2855 removeCurrentScriptNode({});
2858 pushScriptElement(current);
2863 return m_enableScriptExpressions;
2868 if (!m_enableScriptExpressions)
2872 current->addLocation(FileLocationRegion::QuestionMarkTokenRegion, expression->questionToken);
2873 current->addLocation(FileLocationRegion::ColonTokenRegion, expression->colonToken);
2875 if (expression->ko) {
2877 current->insertChild(Fields::alternative, currentScriptNodeEl().takeVariant());
2878 removeCurrentScriptNode({});
2881 if (expression->ok) {
2883 current->insertChild(Fields::consequence, currentScriptNodeEl().takeVariant());
2884 removeCurrentScriptNode({});
2887 if (expression->expression) {
2889 current->insertChild(Fields::condition, currentScriptNodeEl().takeVariant());
2890 removeCurrentScriptNode({});
2893 pushScriptElement(current);
2898 return m_enableScriptExpressions;
2903 if (!m_enableScriptExpressions)
2907 current->addLocation(FileLocationRegion::ContinueKeywordRegion, statement->continueToken);
2909 if (!statement->label.isEmpty()) {
2912 label->setName(statement->label);
2916 pushScriptElement(current);
2920
2921
2922
2923
2925QQmlDomAstCreatorBase::makeUnaryExpression(AST::Node *expression, QQmlJS::SourceLocation operatorToken,
2926 bool hasExpression, UnaryExpressionKind kind)
2928 const DomType type = [&kind]() {
2938 auto current = makeGenericScriptElement(expression, type);
2939 current->addLocation(FileLocationRegion::OperatorTokenRegion, operatorToken);
2941 if (hasExpression) {
2946 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2947 removeCurrentScriptNode({});
2955 return m_enableScriptExpressions;
2960 if (!m_enableScriptExpressions)
2964 makeUnaryExpression(statement, statement->minusToken, statement->expression, Prefix);
2968 pushScriptElement(current);
2973 return m_enableScriptExpressions;
2978 if (!m_enableScriptExpressions)
2982 makeUnaryExpression(statement, statement->plusToken, statement->expression, Prefix);
2986 pushScriptElement(current);
2991 return m_enableScriptExpressions;
2996 if (!m_enableScriptExpressions)
3000 makeUnaryExpression(statement, statement->tildeToken, statement->expression, Prefix);
3004 pushScriptElement(current);
3009 return m_enableScriptExpressions;
3014 if (!m_enableScriptExpressions)
3018 makeUnaryExpression(statement, statement->notToken, statement->expression, Prefix);
3022 pushScriptElement(current);
3027 return m_enableScriptExpressions;
3032 if (!m_enableScriptExpressions)
3036 makeUnaryExpression(statement, statement->typeofToken, statement->expression, Prefix);
3040 pushScriptElement(current);
3045 return m_enableScriptExpressions;
3050 if (!m_enableScriptExpressions)
3054 makeUnaryExpression(statement, statement->deleteToken, statement->expression, Prefix);
3058 pushScriptElement(current);
3063 return m_enableScriptExpressions;
3068 if (!m_enableScriptExpressions)
3072 makeUnaryExpression(statement, statement->voidToken, statement->expression, Prefix);
3076 pushScriptElement(current);
3081 return m_enableScriptExpressions;
3086 if (!m_enableScriptExpressions)
3090 makeUnaryExpression(statement, statement->decrementToken, statement->base, Postfix);
3094 pushScriptElement(current);
3099 return m_enableScriptExpressions;
3104 if (!m_enableScriptExpressions)
3108 makeUnaryExpression(statement, statement->incrementToken, statement->base, Postfix);
3112 pushScriptElement(current);
3117 return m_enableScriptExpressions;
3122 if (!m_enableScriptExpressions)
3125 auto current = makeUnaryExpression(statement, statement->incrementToken, statement->expression,
3130 pushScriptElement(current);
3135 return m_enableScriptExpressions;
3140 if (!m_enableScriptExpressions)
3144 current->addLocation(FileLocationRegion::SemicolonTokenRegion, statement->semicolonToken);
3145 pushScriptElement(current);
3150 return m_enableScriptExpressions;
3155 if (!m_enableScriptExpressions)
3159 current->addLocation(FileLocationRegion::LeftParenthesisRegion, expression->lparenToken);
3160 current->addLocation(FileLocationRegion::RightParenthesisRegion, expression->rparenToken);
3162 if (expression->expression) {
3164 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
3165 removeCurrentScriptNode({});
3168 pushScriptElement(current);
3173 return m_enableScriptExpressions;
3178 if (!m_enableScriptExpressions)
3182 current->addLocation(FileLocationRegion::NewKeywordRegion, expression->newToken);
3184 if (expression->expression) {
3186 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
3187 removeCurrentScriptNode({});
3190 pushScriptElement(current);
3195 return m_enableScriptExpressions;
3200 if (!m_enableScriptExpressions)
3204 current->addLocation(FileLocationRegion::NewKeywordRegion, expression->newToken);
3205 current->addLocation(FileLocationRegion::LeftParenthesisRegion, expression->lparenToken);
3206 current->addLocation(FileLocationRegion::RightParenthesisRegion, expression->rparenToken);
3208 if (expression->arguments) {
3210 current->insertChild(Fields::arguments, scriptNodeStack.takeLast().takeList());
3212 if (expression->base) {
3214 current->insertChild(Fields::base, scriptNodeStack.takeLast().takeVariant());
3217 pushScriptElement(current);
3222 if (!m_enableScriptExpressions)
3227 if (ast->statement) {
3229 current->insertChild(Fields::statement, scriptNodeStack.takeLast().takeVariant());
3231 if (ast->expression) {
3233 current->insertChild(Fields::expression, scriptNodeStack.takeLast().takeVariant());
3236 pushScriptElement(current);
3241 return m_enableScriptExpressions;
3246 if (!m_enableScriptExpressions)
3249 auto current = makeUnaryExpression(statement, statement->decrementToken, statement->expression,
3254 pushScriptElement(current);
3257static const DomEnvironment *environmentFrom(
MutableDomItem &qmlFile)
3259 auto top = qmlFile
.top();
3263 auto domEnvironment = top.as<DomEnvironment>();
3264 if (!domEnvironment) {
3267 return domEnvironment;
3272 if (
auto env = environmentFrom(qmlFile))
3273 return env->qmldirFiles();
3279 QQmlJSLogger *logger,
3280 QQmlJSImporter *importer)
3291 bool QQmlDomAstCreatorWithQQmlJSScope::visit(name *node)
3293 return visitT(node);
3295 void QQmlDomAstCreatorWithQQmlJSScope::endVisit(name *node)
3299QQmlJSASTClassListToVisit
3304 const QQmlJSScope::ConstPtr scope = m_scopeCreator.m_currentScope;
3305 if (!m_domCreator.scriptNodeStack.isEmpty()) {
3306 auto topOfStack = m_domCreator.currentScriptNodeEl();
3307 switch (topOfStack.kind) {
3310 if (scope->scopeType() == QQmlJSScope::ScopeType::QMLScope)
3311 m_domCreator.currentScriptNodeEl().setSemanticScope(scope);
3314 case DomType::ScriptBlockStatement:
3315 case DomType::ScriptForStatement:
3316 case DomType::ScriptForEachStatement:
3317 case DomType::ScriptDoWhileStatement:
3318 case DomType::ScriptWhileStatement:
3320 m_domCreator.currentScriptNodeEl().setSemanticScope(scope);
3325 auto element = m_domCreator.currentScriptNodeEl().value;
3327 if (!scriptElementVariant || !scriptElementVariant->data())
3329 scriptElementVariant->visit([](
auto &&e) {
3330 using U = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
3334 if constexpr (std::is_same_v<U,
3335 ScriptElement::PointerType<
3336 ScriptElements::GenericScriptElement>>) {
3337 if (
auto bodyPtr = e->elementChild(Fields::body)) {
3338 const auto bodyScope = bodyPtr.base()->semanticScope();
3339 e->setSemanticScope(bodyScope);
3350 }
else if (!m_domCreator.nodeStack.isEmpty()) {
3352 [&scope](
auto &&e) {
3353 using U = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
3355 if constexpr (std::is_same_v<U, QmlObject>) {
3356 e.setSemanticScope(scope);
3357 }
else if constexpr (std::is_same_v<U, QmlComponent>) {
3358 e.setSemanticScope(scope);
3359 }
else if constexpr (std::is_same_v<U, MethodInfo>) {
3361 if (
auto scriptElement = e.body->scriptElement()) {
3362 scriptElement.base()->setSemanticScope(scope);
3365 e.setSemanticScope(scope);
3368 m_domCreator.currentNodeEl().item.value);
3374 const QQmlJSScope::ConstPtr scope = m_scopeCreator.m_currentScope;
3378 if (m_domCreator.nodeStack.size() > 1
3379 && m_domCreator.nodeStack.last().item.kind == DomType::Binding) {
3381 [&scope](
auto &&e) {
3382 using U = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
3383 if constexpr (std::is_same_v<U, PropertyDefinition>) {
3389 const bool usePropertyDefinitionScopeInsteadOfTheBindingScope =
3390 QQmlSA::isFunctionScope(scope->scopeType())
3391 && scope->parentScope()
3392 && scope->parentScope()->scopeType() == QQmlSA::ScopeType::QMLScope;
3393 e.setSemanticScope(usePropertyDefinitionScopeInsteadOfTheBindingScope
3394 ? scope->parentScope()
3398 m_domCreator.currentNodeEl(1).item.value);
3400 if (m_domCreator.nodeStack.size() > 0) {
3402 [&scope](
auto &&e) {
3403 using U = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
3404 if constexpr (std::is_same_v<U, PropertyDefinition>) {
3405 e.setSemanticScope(scope);
3406 Q_ASSERT(e.semanticScope());
3407 }
else if constexpr (std::is_same_v<U, MethodInfo>) {
3408 if (e.methodType == MethodInfo::Signal) {
3409 e.setSemanticScope(scope);
3413 m_domCreator.currentNodeEl().item.value);
3422 bool QQmlDomAstCreator::visit(AST::name *ast)
3424 return QQmlDomAstCreatorBase::visit(ast) && visitWithCustomListIteration(ast, this);
3432#undef Q_SCRIPTELEMENT_DISABLE
3433#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(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)