Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmldomastcreator.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6#include "qqmldomelements_p.h"
7#include "qqmldomitem_p.h"
8#include "qqmldompath_p.h"
10#include "qqmldomtop_p.h"
12#include "qqmldomastdumper_p.h"
14#include "qqmldomastcreator_p.h"
15#include "qqmldom_utils_p.h"
16
17#include <QtQml/private/qqmljsast_p.h>
18#include <QtQmlCompiler/private/qqmljsutils_p.h>
19
20#include <QtCore/QDir>
21#include <QtCore/QFileInfo>
22#include <QtCore/QScopeGuard>
23#include <QtCore/QLoggingCategory>
24
25#include <memory>
26#include <optional>
27#include <type_traits>
28#include <variant>
29#include <vector>
30
31static Q_LOGGING_CATEGORY(creatorLog, "qt.qmldom.astcreator", QtWarningMsg);
32
33/*
34 Avoid crashing on files with JS-elements that are not implemented yet.
35 Might be removed (definition + usages) once all script elements are implemented.
36*/
37#define Q_SCRIPTELEMENT_DISABLE() \
38 do { \
39 qDebug() << "Could not construct the JS DOM at" << __FILE__ << ":" << __LINE__ \
40 << ", skipping JS elements..."; \
41 disableScriptElements(); \
42 } while (false)
43
44#define Q_SCRIPTELEMENT_EXIT_IF(check) \
45 do { \
46 if (m_enableScriptExpressions && (check)) { \
47 Q_SCRIPTELEMENT_DISABLE(); \
48 return; \
49 } \
50 } while (false)
51
53namespace QQmlJS {
54namespace Dom {
55
56using namespace AST;
57
58template<typename K, typename V>
59V *valueFromMultimap(QMultiMap<K, V> &mmap, const K &key, index_type idx)
60{
61 if (idx < 0)
62 return nullptr;
63 auto it = mmap.find(key);
64 auto end = mmap.end();
65 if (it == end)
66 return nullptr;
67 auto it2 = it;
68 index_type nEl = 0;
69 while (it2 != end && it2.key() == key) {
70 ++it2;
71 ++nEl;
72 }
73 if (nEl <= idx)
74 return nullptr;
75 for (index_type i = idx + 1; i < nEl; ++i)
76 ++it;
77 return &(*it);
78}
79
81{
82 static ErrorGroups errs = { { NewErrorGroup("Dom"), NewErrorGroup("QmlFile"),
83 NewErrorGroup("Parsing") } };
84 return errs;
85}
86
87static QString toString(const UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char('.'))
88{
90
91 for (const UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) {
92 if (iter != qualifiedId)
93 result += delimiter;
94
95 result += iter->name;
96 }
97
98 return result;
99}
100
102{
103 Q_ASSERT(t);
104 QString res = toString(t->typeId);
105
106 if (UiQualifiedId *arg = t->typeArgument)
107 res += u'<' + toString(arg) + u'>';
108
109 return res;
110}
111
116
118{
119 return combineLocations(n->firstSourceLocation(), n->lastSourceLocation());
120}
121
123 const SourceLocation &dotToken,
125{
127 left.visitConst([&s1](auto &&el) { s1 = el->mainRegionLocation(); });
128 right.visitConst([&s2](auto &&el) { s2 = el->mainRegionLocation(); });
129
130 auto result = std::make_shared<ScriptElements::BinaryExpression>(s1, s2);
131 result->addLocation(OperatorTokenRegion, dotToken);
133 result->setLeft(left);
134 result->setRight(right);
136};
137
142static ScriptElementVariant
144{
145 ScriptElementVariant bindable;
146 bool first = true;
147 for (auto exp = qualifiedId; exp; exp = exp->next) {
148 const SourceLocation identifierLoc = exp->identifierToken;
149 auto id = std::make_shared<ScriptElements::IdentifierExpression>(identifierLoc);
150 id->setName(exp->name);
151 if (first) {
152 first = false;
154 continue;
155 }
156 bindable = wrapIntoFieldMemberExpression(bindable, exp->dotToken,
158 }
159
160 return bindable;
161}
162
163QQmlDomAstCreator::QmlStackElement &QQmlDomAstCreator::currentQmlObjectOrComponentEl(int idx)
164{
165 Q_ASSERT_X(idx < nodeStack.size() && idx >= 0, "currentQmlObjectOrComponentEl",
166 "Stack does not contain enough elements!");
167 int i = nodeStack.size() - idx;
168 while (i-- > 0) {
169 DomType k = nodeStack.at(i).item.kind;
171 return nodeStack[i];
172 }
173 Q_ASSERT_X(false, "currentQmlObjectEl", "No QmlObject or component in stack");
174 return nodeStack.last();
175}
176
177QQmlDomAstCreator::QmlStackElement &QQmlDomAstCreator::currentNodeEl(int i)
178{
179 Q_ASSERT_X(i < nodeStack.size() && i >= 0, "currentNode", "Stack does not contain element!");
180 return nodeStack[nodeStack.size() - i - 1];
181}
182
183QQmlDomAstCreator::ScriptStackElement &QQmlDomAstCreator::currentScriptNodeEl(int i)
184{
185 Q_ASSERT_X(i < scriptNodeStack.size() && i >= 0, "currentNode",
186 "Stack does not contain element!");
187 return scriptNodeStack[scriptNodeStack.size() - i - 1];
188}
189
190QQmlDomAstCreator::DomValue &QQmlDomAstCreator::currentNode(int i)
191{
192 Q_ASSERT_X(i < nodeStack.size() && i >= 0, "currentNode",
193 "Stack does not contain element!");
194 return nodeStack[nodeStack.size() - i - 1].item;
195}
196
197void QQmlDomAstCreator::removeCurrentNode(std::optional<DomType> expectedType)
198{
199 Q_ASSERT_X(!nodeStack.isEmpty(), className, "popCurrentNode() without any node");
200 if (expectedType)
201 Q_ASSERT(nodeStack.last().item.kind == *expectedType);
202 nodeStack.removeLast();
203}
204
205void QQmlDomAstCreator::removeCurrentScriptNode(std::optional<DomType> expectedType)
206{
207 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
208 Q_ASSERT_X(!scriptNodeStack.isEmpty(), className,
209 "popCurrentScriptNode() without any node");
210 if (expectedType)
211 Q_ASSERT(scriptNodeStack.last().kind == *expectedType);
212 scriptNodeStack.removeLast();
213}
214
227const ScriptElementVariant &
228QQmlDomAstCreator::finalizeScriptExpression(const ScriptElementVariant &element, const Path &pathFromOwner,
229 const FileLocations::Tree &ownerFileLocations)
230{
231 auto e = element.base();
232 Q_ASSERT(e);
233
234 qCDebug(creatorLog) << "Finalizing script expression with path:"
235 << ownerFileLocations->canonicalPathForTesting().append(
236 pathFromOwner.toString());
237 e->updatePathFromOwner(pathFromOwner);
238 e->createFileLocations(ownerFileLocations);
239 return element;
240}
241
242FileLocations::Tree QQmlDomAstCreator::createMap(const FileLocations::Tree &base, const Path &p, AST::Node *n)
243{
245 if (n)
247 return res;
248}
249
250FileLocations::Tree QQmlDomAstCreator::createMap(DomType k, const Path &p, AST::Node *n)
251{
252 Path relative;
254 switch (k) {
256 switch (currentNode().kind) {
260 case DomType::Binding:
261 case DomType::Id:
263 break;
264 default:
265 qCWarning(domLog) << "unexpected type" << domTypeToString(currentNode().kind);
266 Q_UNREACHABLE();
267 }
268 base = currentNodeEl().fileLocations;
269 if (p.length() > 2) {
270 Path p2 = p[p.length() - 2];
271 if (p2.headKind() == Path::Kind::Field
272 && (p2.checkHeadName(Fields::children) || p2.checkHeadName(Fields::objects)
273 || p2.checkHeadName(Fields::value) || p2.checkHeadName(Fields::annotations)
274 || p2.checkHeadName(Fields::children)))
275 relative = p.mid(p.length() - 2, 2);
276 else if (p.last().checkHeadName(Fields::value)
277 && p.last().headKind() == Path::Kind::Field)
278 relative = p.last();
279 else {
280 qCWarning(domLog) << "unexpected path to QmlObject in createMap" << p;
281 Q_UNREACHABLE();
282 }
283 } else {
284 qCWarning(domLog) << "unexpected path to QmlObject in createMap" << p;
285 Q_UNREACHABLE();
286 }
287 break;
289 relative = p;
290 base = currentNodeEl().fileLocations;
291 break;
293 case DomType::Pragma:
294 case DomType::Import:
295 case DomType::Id:
297 relative = p;
298 base = rootMap;
299 break;
300 case DomType::Binding:
303 base = currentEl<QmlObject>().fileLocations;
304 if (p.length() > 3)
305 relative = p.mid(p.length() - 3, 3);
306 else
307 relative = p;
308 break;
309
310 default:
311 qCWarning(domLog) << "Unexpected type in createMap:" << domTypeToString(k);
312 Q_UNREACHABLE();
313 break;
314 }
315 return createMap(base, relative, n);
316}
317
319 : qmlFile(qmlFile),
320 qmlFilePtr(qmlFile.ownerAs<QmlFile>()),
321 rootMap(qmlFilePtr->fileLocationsTree())
322{
323}
324
326{
327 QFileInfo fInfo(qmlFile.canonicalFilePath());
328 QString componentName = fInfo.baseName();
329 QmlComponent *cPtr;
330 Path p = qmlFilePtr->addComponent(QmlComponent(componentName), AddOption::KeepExisting,
331 &cPtr);
332 MutableDomItem newC(qmlFile.item(), p);
333 Q_ASSERT_X(newC.item(), className, "could not recover component added with addComponent");
334 // QmlFile region == Component region == program span
335 // we hide the component span because the component s written after the imports
337 pushEl(p, *cPtr, program);
338
339 auto envPtr = qmlFile.environment().ownerAs<DomEnvironment>();
340 const bool loadDependencies =
342 // add implicit directory import and load them in the Dom
343 if (!fInfo.canonicalPath().isEmpty()) {
344 Import selfDirImport(QmlUri::fromDirectoryString(fInfo.canonicalPath()));
345 selfDirImport.implicit = true;
346 qmlFilePtr->addImport(selfDirImport);
347
348 if (loadDependencies) {
349 const QString currentFileDir =
351 envPtr->loadFile(FileToLoad::fromFileSystem(
352 envPtr, selfDirImport.uri.absoluteLocalPath(currentFileDir)),
354 }
355 }
356 // add implicit imports from the environment (QML, QtQml for example) and load them in the Dom
357 for (Import i : qmlFile.environment().ownerAs<DomEnvironment>()->implicitImports()) {
358 i.implicit = true;
359 qmlFilePtr->addImport(i);
360
361 if (loadDependencies)
362 envPtr->loadModuleDependency(i.uri.moduleUri(), i.version, DomItem::Callback());
363 }
364 if (m_loadFileLazily && loadDependencies) {
365 envPtr->loadPendingDependencies();
366 envPtr->commitToBase(qmlFile.environment().item());
367 }
368
369 return true;
370}
371
373{
374 MutableDomItem newC = qmlFile.path(currentNodeEl().path);
375 QmlComponent &comp = current<QmlComponent>();
376 for (const Pragma &p : qmlFilePtr->pragmas()) {
377 if (p.name.compare(u"singleton", Qt::CaseInsensitive) == 0) {
378 comp.setIsSingleton(true);
379 comp.setIsCreatable(false); // correct?
380 }
381 }
382 *newC.mutableAs<QmlComponent>() = comp;
383 removeCurrentNode(DomType::QmlComponent);
384 Q_ASSERT_X(nodeStack.isEmpty(), className, "ui program did not finish node stack");
385}
386
388{
389 QStringList valueList;
390 for (auto t = el->values; t; t = t->next)
391 valueList << t->value.toString();
392
393 auto fileLocation = createMap(
394 DomType::Pragma, qmlFilePtr->addPragma(Pragma(el->name.toString(), valueList)), el);
395 FileLocations::addRegion(fileLocation, PragmaKeywordRegion, el->pragmaToken);
396 FileLocations::addRegion(fileLocation, IdentifierRegion, el->pragmaIdToken);
397 if (el->colonToken.isValid()) {
398 FileLocations::addRegion(fileLocation, ColonTokenRegion, el->colonToken);
399 }
400 int i = 0;
401 for (auto t = el->values; t; t = t->next) {
402 auto subMap = createMap(fileLocation, Path().field(Fields::values).index(i), t);
404 ++i;
405 }
406
407 return true;
408}
409
411{
413 if (el->version && el->version->version.hasMajorVersion())
414 v.majorVersion = el->version->version.majorVersion();
415 if (el->version && el->version->version.hasMinorVersion())
416 v.minorVersion = el->version->version.minorVersion();
417
418 auto envPtr = qmlFile.environment().ownerAs<DomEnvironment>();
419 const bool loadDependencies =
421 FileLocations::Tree fileLocation;
422 if (el->importUri != nullptr) {
423 const Import import =
424 Import::fromUriString(toString(el->importUri), v, el->importId.toString());
425 fileLocation = createMap(DomType::Import, qmlFilePtr->addImport(import), el);
426
427 if (loadDependencies) {
428 envPtr->loadModuleDependency(import.uri.moduleUri(), import.version,
430 }
432 } else {
433 const Import import =
434 Import::fromFileString(el->fileName.toString(), el->importId.toString());
435 fileLocation = createMap(DomType::Import, qmlFilePtr->addImport(import), el);
436
437 if (loadDependencies) {
438 const QString currentFileDir =
440 envPtr->loadFile(FileToLoad::fromFileSystem(
441 envPtr, import.uri.absoluteLocalPath(currentFileDir)),
443 }
444 FileLocations::addRegion(fileLocation, ImportUriRegion, el->fileNameToken);
445 }
446 if (m_loadFileLazily && loadDependencies) {
447 envPtr->loadPendingDependencies();
448 envPtr->commitToBase(qmlFile.environment().item());
449 }
450
451 if (el->importToken.isValid())
452 FileLocations::addRegion(fileLocation, ImportTokenRegion, el->importToken);
453
454 if (el->asToken.isValid())
455 FileLocations::addRegion(fileLocation, AsTokenRegion, el->asToken);
456
457 if (el->importIdToken.isValid())
458 FileLocations::addRegion(fileLocation, IdNameRegion, el->importIdToken);
459
460 if (el->version)
462
463
464 return true;
465}
466
468{
469 switch (el->type) {
472 m.name = el->name.toString();
473 m.typeName = toString(el->memberType);
474 m.isReadonly = el->isReadonly();
475 m.access = MethodInfo::Public;
476 m.methodType = MethodInfo::Signal;
477 m.isList = el->typeModifier == QLatin1String("list");
478 MethodInfo *mPtr;
479 Path p = current<QmlObject>().addMethod(m, AddOption::KeepExisting, &mPtr);
480 pushEl(p, *mPtr, el);
481 FileLocations::addRegion(nodeStack.last().fileLocations, SignalKeywordRegion,
482 el->propertyToken());
483 FileLocations::addRegion(nodeStack.last().fileLocations, IdentifierRegion,
484 el->identifierToken);
485 MethodInfo &mInfo = std::get<MethodInfo>(currentNode().value);
486 AST::UiParameterList *args = el->parameters;
487 while (args) {
489 param.name = args->name.toString();
490 param.typeName = args->type ? args->type->toString() : QString();
491 index_type idx = index_type(mInfo.parameters.size());
492 mInfo.parameters.append(param);
493 auto argLocs = FileLocations::ensure(nodeStack.last().fileLocations,
494 Path::Field(Fields::parameters).index(idx),
497 FileLocations::addRegion(argLocs, IdentifierRegion, args->identifierToken);
498 if (args->type)
499 FileLocations::addRegion(argLocs, TypeIdentifierRegion, args->propertyTypeToken);
500 args = args->next;
501 }
502 break;
503 }
506 p.name = el->name.toString();
507 p.typeName = toString(el->memberType);
508 p.isReadonly = el->isReadonly();
509 p.isDefaultMember = el->isDefaultMember();
510 p.isRequired = el->isRequired();
511 p.isList = el->typeModifier == QLatin1String("list");
512 if (!el->typeModifier.isEmpty())
513 p.typeName = el->typeModifier.toString() + QChar(u'<') + p.typeName + QChar(u'>');
514 PropertyDefinition *pPtr;
515 Path pPathFromOwner =
516 current<QmlObject>().addPropertyDef(p, AddOption::KeepExisting, &pPtr);
517 if (m_enableScriptExpressions) {
518 auto qmlObjectType = makeGenericScriptElement(el->memberType, DomType::ScriptType);
519 qmlObjectType->insertChild(Fields::typeName,
521 pPtr->setNameIdentifiers(finalizeScriptExpression(
523 pPathFromOwner.field(Fields::nameIdentifiers), rootMap));
524 // skip binding identifiers of the binding inside the property definition, if there is
525 // one
526 m_skipBindingIdentifiers = el->binding;
527 }
528 pushEl(pPathFromOwner, *pPtr, el);
529 FileLocations::addRegion(nodeStack.last().fileLocations, PropertyKeywordRegion,
530 el->propertyToken());
531 FileLocations::addRegion(nodeStack.last().fileLocations, IdentifierRegion,
532 el->identifierToken);
533 FileLocations::addRegion(nodeStack.last().fileLocations, TypeIdentifierRegion,
534 el->typeToken);
535 FileLocations::addRegion(nodeStack.last().fileLocations, ColonTokenRegion, el->colonToken);
536 if (p.name == u"id")
537 qmlFile.addError(std::move(astParseErrors()
538 .warning(tr("id is a special attribute, that should not be "
539 "used as property name"))
540 .withPath(currentNodeEl().path)));
541 if (p.isDefaultMember) {
542 FileLocations::addRegion(nodeStack.last().fileLocations, DefaultKeywordRegion,
543 el->defaultToken());
544 }
545 if (p.isRequired) {
546 FileLocations::addRegion(nodeStack.last().fileLocations, RequiredKeywordRegion,
547 el->requiredToken());
548 }
549 if (p.isReadonly) {
550 FileLocations::addRegion(nodeStack.last().fileLocations, ReadonlyKeywordRegion,
551 el->readonlyToken());
552 }
553 if (el->statement) {
555 SourceLocation loc = combineLocations(el->statement);
556 QStringView code = qmlFilePtr->code();
557
558 auto script = std::make_shared<ScriptExpression>(
559 code.mid(loc.offset, loc.length), qmlFilePtr->engine(), el->statement,
561 loc);
562 Binding *bPtr;
563 Path bPathFromOwner = current<QmlObject>().addBinding(Binding(p.name, script, bType),
565 FileLocations::Tree bLoc = createMap(DomType::Binding, bPathFromOwner, el);
566 FileLocations::addRegion(bLoc, ColonTokenRegion, el->colonToken);
567 FileLocations::Tree valueLoc = FileLocations::ensure(bLoc, Path::Field(Fields::value),
570 // push it also: its needed in endVisit to add the scriptNode to it
571 // do not use pushEl to avoid recreating the already created "bLoc" Map
572 nodeStack.append({ bPathFromOwner, *bPtr, bLoc });
573 }
574 break;
575 }
576 }
577 return true;
578}
579
581{
582 if (auto &lastEl = currentNode(); lastEl.kind == DomType::Binding) {
583 Binding &b = std::get<Binding>(lastEl.value);
584 if (m_enableScriptExpressions
585 && (scriptNodeStack.size() != 1 || scriptNodeStack.last().isList())) {
587 }
588 if (m_enableScriptExpressions) {
589 b.scriptExpressionValue()->setScriptElement(finalizeScriptExpression(
590 currentScriptNodeEl().takeVariant(), Path().field(Fields::scriptElement),
591 FileLocations::ensure(currentNodeEl().fileLocations,
592 Path().field(Fields::value))));
593 removeCurrentScriptNode({});
594 }
595
596 QmlObject &containingObject = current<QmlObject>();
597 Binding *bPtr =
598 valueFromMultimap(containingObject.m_bindings, b.name(), currentIndex());
599 Q_ASSERT(bPtr);
600 removeCurrentNode({});
601 }
602 Node::accept(el->parameters, this);
604 if ((el->binding || el->statement)
605 && nodeStack.last().item.kind == DomType::PropertyDefinition) {
606 PropertyDefinition &pDef = std::get<PropertyDefinition>(nodeStack.last().item.value);
607 if (!pDef.annotations.isEmpty()) {
608 QmlObject duplicate;
609 duplicate.setName(QLatin1String("duplicate"));
610 QmlObject &obj = current<QmlObject>();
611 auto it = obj.m_bindings.find(pDef.name);
612 if (it != obj.m_bindings.end()) {
613 for (QmlObject ann : pDef.annotations) {
614 ann.addAnnotation(duplicate);
615 it->addAnnotation(currentEl<QmlObject>()
616 .path.field(Fields::bindings)
617 .key(pDef.name)
618 .index(obj.m_bindings.values(pDef.name).size() - 1),
619 ann);
620 }
621 }
622 }
623 }
624 QmlObject &obj = current<QmlObject>();
625 QmlStackElement &sEl = nodeStack.last();
626 switch (sEl.item.kind) {
628 PropertyDefinition pDef = std::get<PropertyDefinition>(sEl.item.value);
629 PropertyDefinition *pDefPtr =
630 valueFromMultimap(obj.m_propertyDefs, pDef.name, sEl.path.last().headIndex());
631 Q_ASSERT(pDefPtr);
632 *pDefPtr = pDef;
633 } break;
634 case DomType::MethodInfo: {
635 MethodInfo m = std::get<MethodInfo>(sEl.item.value);
636 MethodInfo *mPtr = valueFromMultimap(obj.m_methods, m.name, sEl.path.last().headIndex());
637 Q_ASSERT(mPtr);
638 *mPtr = m;
639 } break;
640 default:
641 Q_UNREACHABLE();
642 }
643 removeCurrentNode({});
644}
645
647{
648 const QStringView code(qmlFilePtr->code());
650 m.name = fDef->name.toString();
651 if (AST::TypeAnnotation *tAnn = fDef->typeAnnotation) {
652 if (AST::Type *t = tAnn->type)
653 m.typeName = typeToString(t);
654 }
655 m.access = MethodInfo::Public;
656 m.methodType = MethodInfo::Method;
657
658 SourceLocation bodyLoc = fDef->body ? combineLocations(fDef->body)
659 : combineLocations(fDef->lbraceToken, fDef->rbraceToken);
660 SourceLocation methodLoc = combineLocations(fDef);
661 QStringView preCode = code.mid(methodLoc.begin(), bodyLoc.begin() - methodLoc.begin());
662 QStringView postCode = code.mid(bodyLoc.end(), methodLoc.end() - bodyLoc.end());
663 m.body = std::make_shared<ScriptExpression>(
664 code.mid(bodyLoc.offset, bodyLoc.length), qmlFilePtr->engine(), fDef->body,
665 qmlFilePtr->astComments(), ScriptExpression::ExpressionType::FunctionBody, bodyLoc, 0,
666 preCode, postCode);
667
668 if (fDef->typeAnnotation) {
669 SourceLocation typeLoc = combineLocations(fDef->typeAnnotation);
670 m.returnType = std::make_shared<ScriptExpression>(
671 code.mid(typeLoc.offset, typeLoc.length), qmlFilePtr->engine(),
672 fDef->typeAnnotation, qmlFilePtr->astComments(),
674 }
675
676 MethodInfo *mPtr;
677 Path mPathFromOwner = current<QmlObject>().addMethod(m, AddOption::KeepExisting, &mPtr);
678 pushEl(mPathFromOwner, *mPtr,
679 fDef); // add at the start and use the normal recursive visit?
680 FileLocations::Tree &fLoc = nodeStack.last().fileLocations;
681 if (fDef->identifierToken.isValid())
682 FileLocations::addRegion(fLoc, IdentifierRegion, fDef->identifierToken);
683 auto bodyTree = FileLocations::ensure(fLoc, Path::Field(Fields::body),
685 FileLocations::addRegion(bodyTree, MainRegion, bodyLoc);
686 if (fDef->functionToken.isValid())
687 FileLocations::addRegion(fLoc, FunctionKeywordRegion, fDef->functionToken);
688 if (fDef->lparenToken.length != 0)
689 FileLocations::addRegion(fLoc, LeftParenthesisRegion, fDef->lparenToken);
690 if (fDef->rparenToken.length != 0)
691 FileLocations::addRegion(fLoc, RightParenthesisRegion, fDef->rparenToken);
692 if (fDef->lbraceToken.length != 0)
693 FileLocations::addRegion(fLoc, LeftBraceRegion, fDef->lbraceToken);
694 if (fDef->rbraceToken.length != 0)
695 FileLocations::addRegion(fLoc, RightBraceRegion, fDef->rbraceToken);
696 if (fDef->typeAnnotation)
697 FileLocations::addRegion(fLoc, TypeIdentifierRegion, combineLocations(fDef->typeAnnotation->type));
698 MethodInfo &mInfo = std::get<MethodInfo>(currentNode().value);
699 AST::FormalParameterList *args = fDef->formals;
700 while (args) {
702 param.name = args->element->bindingIdentifier.toString();
703 if (AST::TypeAnnotation *tAnn = args->element->typeAnnotation) {
704 if (AST::Type *t = tAnn->type)
705 param.typeName = typeToString(t);
706 }
707 if (args->element->initializer) {
708 SourceLocation loc = combineLocations(args->element->initializer);
709 auto script = std::make_shared<ScriptExpression>(
710 code.mid(loc.offset, loc.length), qmlFilePtr->engine(),
711 args->element->initializer, qmlFilePtr->astComments(),
713 param.defaultValue = script;
714 }
715 if (args->element->type == AST::PatternElement::SpreadElement)
716 param.isRestElement = true;
717 SourceLocation parameterLoc = combineLocations(args->element);
718 param.value = std::make_shared<ScriptExpression>(
719 code.mid(parameterLoc.offset, parameterLoc.length), qmlFilePtr->engine(),
720 args->element, qmlFilePtr->astComments(),
722
723 index_type idx = index_type(mInfo.parameters.size());
724 mInfo.parameters.append(param);
725 auto argLocs = FileLocations::ensure(nodeStack.last().fileLocations,
726 Path::Field(Fields::parameters).index(idx),
729 if (args->element->identifierToken.isValid())
730 FileLocations::addRegion(argLocs, IdentifierRegion, args->element->identifierToken);
731 if (args->element->typeAnnotation)
732 FileLocations::addRegion(argLocs, TypeIdentifierRegion, combineLocations(args->element->typeAnnotation->type));
733 args = args->next;
734 }
735 return true;
736}
737
739{
740 if (!cast<FunctionDeclaration *>(el->sourceElement)) {
741 qCWarning(creatorLog) << "unhandled source el:" << static_cast<AST::Node *>(el);
742 Q_UNREACHABLE();
743 }
744 return true;
745}
746
748{
749 if (auto data = variant.data()) {
750 if (auto genericElement =
751 std::get_if<std::shared_ptr<ScriptElements::GenericScriptElement>>(&*data)) {
752 (*genericElement)->setKind(DomType::ScriptFormalParameter);
753 }
754 }
755}
756
758{
759 MethodInfo &m = std::get<MethodInfo>(currentNode().value);
760 const FileLocations::Tree bodyTree =
761 FileLocations::ensure(currentNodeEl().fileLocations, Path().field(Fields::body));
762 const Path bodyPath = Path().field(Fields::scriptElement);
763
764 if (!m_enableScriptExpressions)
765 return;
766
767 if (fDef->body) {
768 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
769 if (currentScriptNodeEl().isList()) {
770 // It is more intuitive to have functions with a block as a body instead of a
771 // list.
772 auto body = std::make_shared<ScriptElements::BlockStatement>(
773 combineLocations(fDef->lbraceToken, fDef->rbraceToken));
774 body->setStatements(currentScriptNodeEl().takeList());
775 if (auto semanticScope = body->statements().semanticScope())
776 body->setSemanticScope(semanticScope);
777 m.body->setScriptElement(finalizeScriptExpression(
778 ScriptElementVariant::fromElement(body), bodyPath, bodyTree));
779 } else {
780 m.body->setScriptElement(finalizeScriptExpression(
781 currentScriptNodeEl().takeVariant(), bodyPath, bodyTree));
782 }
783 removeCurrentScriptNode({});
784 } else {
785 // for convenience purposes: insert an empty BlockStatement
786 auto body = std::make_shared<ScriptElements::BlockStatement>(
787 combineLocations(fDef->lbraceToken, fDef->rbraceToken));
788 m.body->setScriptElement(finalizeScriptExpression(ScriptElementVariant::fromElement(body),
789 bodyPath, bodyTree));
790 }
791
792 if (fDef->typeAnnotation) {
793 auto argLoc = FileLocations::ensure(nodeStack.last().fileLocations,
794 Path().field(Fields::returnType),
796 const Path pathToReturnType = Path().field(Fields::scriptElement);
797
798 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
799 ScriptElementVariant variant = currentScriptNodeEl().takeVariant();
800 finalizeScriptExpression(variant, pathToReturnType, argLoc);
801 m.returnType->setScriptElement(variant);
802 removeCurrentScriptNode({});
803 }
804 std::vector<FormalParameterList *> reversedInitializerExpressions;
805 for (auto it = fDef->formals; it; it = it->next) {
806 reversedInitializerExpressions.push_back(it);
807 }
808 const size_t size = reversedInitializerExpressions.size();
809 for (size_t idx = size - 1; idx < size; --idx) {
810 auto argLoc = FileLocations::ensure(
811 nodeStack.last().fileLocations,
812 Path().field(Fields::parameters).index(idx).field(Fields::value),
814 const Path pathToArgument = Path().field(Fields::scriptElement);
815
816 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
817 ScriptElementVariant variant = currentScriptNodeEl().takeVariant();
819 finalizeScriptExpression(variant, pathToArgument, argLoc);
820 m.parameters[idx].value->setScriptElement(variant);
821 removeCurrentScriptNode({});
822 }
823
824 // there should be no more uncollected script elements
825 if (m_enableScriptExpressions && !scriptNodeStack.empty()) {
827 }
828}
829
831{
832 MethodInfo &m = std::get<MethodInfo>(currentNode().value);
834 QmlObject &obj = current<QmlObject>();
835 MethodInfo *mPtr =
836 valueFromMultimap(obj.m_methods, m.name, nodeStack.last().path.last().headIndex());
837 Q_ASSERT(mPtr);
838 *mPtr = m;
839 removeCurrentNode(DomType::MethodInfo);
840}
841
843{
844 QmlObject scope;
845 scope.setName(toString(el->qualifiedTypeNameId));
847 QmlObject *sPtr = nullptr;
848 Path sPathFromOwner;
849 if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last()) {
850 if (currentNode().kind == DomType::Binding) {
851 QList<QmlObject> *vals = std::get<Binding>(currentNode().value).arrayValue();
852 if (vals) {
853 int idx = vals->size();
854 vals->append(scope);
855 sPathFromOwner = currentNodeEl().path.field(Fields::value).index(idx);
856 sPtr = &((*vals)[idx]);
857 sPtr->updatePathFromOwner(sPathFromOwner);
858 } else {
859 Q_ASSERT_X(false, className,
860 "expected an array binding with a valid QList<QmlScope> as value");
861 }
862 } else {
863 Q_ASSERT_X(false, className, "expected an array binding as last node on the stack");
864 }
865 } else {
866 DomValue &containingObject = currentQmlObjectOrComponentEl().item;
867 switch (containingObject.kind) {
869 sPathFromOwner = std::get<QmlComponent>(containingObject.value).addObject(scope, &sPtr);
870 break;
872 sPathFromOwner = std::get<QmlObject>(containingObject.value).addChild(scope, &sPtr);
873 break;
874 default:
875 Q_UNREACHABLE();
876 }
877 Path pathFromContainingObject = sPathFromOwner.mid(currentNodeEl().path.length());
879 FileLocations::ensure(currentNodeEl().fileLocations, pathFromContainingObject,
882 el->qualifiedTypeNameId->identifierToken);
883 }
884 Q_ASSERT_X(sPtr, className, "could not recover new scope");
885
886 if (m_enableScriptExpressions) {
887 auto qmlObjectType = makeGenericScriptElement(el->qualifiedTypeNameId, DomType::ScriptType);
888 qmlObjectType->insertChild(Fields::typeName,
889 fieldMemberExpressionForQualifiedId(el->qualifiedTypeNameId));
890 sPtr->setNameIdentifiers(
891 finalizeScriptExpression(ScriptElementVariant::fromElement(qmlObjectType),
892 sPathFromOwner.field(Fields::nameIdentifiers), rootMap));
893 }
894 pushEl(sPathFromOwner, *sPtr, el);
895
896 if (m_enableScriptExpressions && el->initializer) {
897 FileLocations::addRegion(nodeStack.last().fileLocations, LeftBraceRegion,
898 el->initializer->lbraceToken);
899 FileLocations::addRegion(nodeStack.last().fileLocations, RightBraceRegion,
900 el->initializer->rbraceToken);
901 }
903 return true;
904}
905
907{
908 QmlObject &obj = current<QmlObject>();
909 int idx = currentIndex();
910 if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last() + 1) {
911 if (currentNode(1).kind == DomType::Binding) {
912 Binding &b = std::get<Binding>(currentNode(1).value);
913 QList<QmlObject> *vals = b.arrayValue();
914 Q_ASSERT_X(vals, className,
915 "expected an array binding with a valid QList<QmlScope> as value");
916 (*vals)[idx] = obj;
917 } else {
918 Q_ASSERT_X(false, className, "expected an array binding as last node on the stack");
919 }
920 } else {
921 DomValue &containingObject = currentNodeEl(1).item;
922 Path p = currentNodeEl().path;
923 switch (containingObject.kind) {
925 if (p[p.length() - 2] == Path::Field(Fields::objects))
926 std::get<QmlComponent>(containingObject.value).m_objects[idx] = obj;
927 else
928 Q_UNREACHABLE();
929 break;
931 if (p[p.length() - 2] == Path::Field(Fields::children))
932 std::get<QmlObject>(containingObject.value).m_children[idx] = obj;
933 else
934 Q_UNREACHABLE();
935 break;
936 default:
937 Q_UNREACHABLE();
938 }
939 }
940 removeCurrentNode(DomType::QmlObject);
941}
942
943void QQmlDomAstCreator::setBindingIdentifiers(const Path &pathFromOwner,
944 const UiQualifiedId *identifiers, Binding *bindingPtr)
945{
946 const bool skipBindingIdentifiers = std::exchange(m_skipBindingIdentifiers, false);
947 if (!m_enableScriptExpressions || skipBindingIdentifiers)
948 return;
949
951 bindingPtr->setBindingIdentifiers(finalizeScriptExpression(
952 bindable, pathFromOwner.field(Fields::bindingIdentifiers), rootMap));
953}
954
956{
959 value.setName(toString(el->qualifiedTypeNameId));
960 Binding *bPtr;
961 Path bPathFromOwner = current<QmlObject>().addBinding(
962 Binding(toString(el->qualifiedId), value, bType), AddOption::KeepExisting, &bPtr);
963 if (bPtr->name() == u"id")
964 qmlFile.addError(std::move(astParseErrors()
965 .warning(tr("id attributes should only be a lower case letter "
966 "followed by letters, numbers or underscore, "
967 "assuming they refer to an id property"))
968 .withPath(bPathFromOwner)));
969 setBindingIdentifiers(bPathFromOwner, el->qualifiedId, bPtr);
970
971 pushEl(bPathFromOwner, *bPtr, el);
972 if (el->hasOnToken)
973 FileLocations::addRegion(nodeStack.last().fileLocations, OnTokenRegion, el->colonToken);
974 else
975 FileLocations::addRegion(nodeStack.last().fileLocations, ColonTokenRegion, el->colonToken);
976 FileLocations::addRegion(nodeStack.last().fileLocations, IdentifierRegion, combineLocations(el->qualifiedId));
978 QmlObject *objValue = bPtr->objectValue();
979 Q_ASSERT_X(objValue, className, "could not recover objectValue");
980 objValue->setName(toString(el->qualifiedTypeNameId));
981
982 if (m_enableScriptExpressions) {
983 auto qmlObjectType = makeGenericScriptElement(el->qualifiedTypeNameId, DomType::ScriptType);
984 qmlObjectType->insertChild(Fields::typeName,
985 fieldMemberExpressionForQualifiedId(el->qualifiedTypeNameId));
986 objValue->setNameIdentifiers(finalizeScriptExpression(
988 bPathFromOwner.field(Fields::value).field(Fields::nameIdentifiers), rootMap));
989 }
990
991 objValue->addPrototypePath(Paths::lookupTypePath(objValue->name()));
992 pushEl(bPathFromOwner.field(Fields::value), *objValue, el->initializer);
993 if (m_enableScriptExpressions && el->initializer) {
994 FileLocations::addRegion(nodeStack.last().fileLocations, LeftBraceRegion,
995 el->initializer->lbraceToken);
996 FileLocations::addRegion(nodeStack.last().fileLocations, RightBraceRegion,
997 el->initializer->rbraceToken);
998 }
999 return true;
1000}
1001
1003{
1004 QmlObject &objValue = current<QmlObject>();
1005 QmlObject &containingObj = current<QmlObject>(1);
1006 Binding &b = std::get<Binding>(currentNode(1).value);
1007 QmlObject *objPtr = b.objectValue();
1008 Q_ASSERT(objPtr);
1009 *objPtr = objValue;
1010 index_type idx = currentNodeEl(1).path.last().headIndex();
1011 Binding *bPtr = valueFromMultimap(containingObj.m_bindings, b.name(), idx);
1012 Q_ASSERT(bPtr);
1013 *bPtr = b;
1014 removeCurrentNode(DomType::QmlObject);
1015 removeCurrentNode(DomType::Binding);
1016}
1017
1019{
1020 QStringView code = qmlFilePtr->code();
1021 SourceLocation loc = combineLocations(el->statement);
1022 auto script = std::make_shared<ScriptExpression>(
1023 code.mid(loc.offset, loc.length), qmlFilePtr->engine(), el->statement,
1024 qmlFilePtr->astComments(), ScriptExpression::ExpressionType::BindingExpression, loc);
1025 Binding bindingV(toString(el->qualifiedId), script, BindingType::Normal);
1026 Binding *bindingPtr = nullptr;
1027 Id *idPtr = nullptr;
1028 Path pathFromOwner;
1029 if (bindingV.name() == u"id") {
1030 Node *exp = script->ast();
1031 if (ExpressionStatement *eStat = cast<ExpressionStatement *>(script->ast()))
1032 exp = eStat->expression;
1033 if (IdentifierExpression *iExp = cast<IdentifierExpression *>(exp)) {
1034 QmlStackElement &containingObjectEl = currentEl<QmlObject>();
1035 QmlObject &containingObject = std::get<QmlObject>(containingObjectEl.item.value);
1036 QString idName = iExp->name.toString();
1037 Id idVal(idName, qmlFile.canonicalPath().path(containingObject.pathFromOwner()));
1038 idVal.value = script;
1039 containingObject.setIdStr(idName);
1040 FileLocations::addRegion(containingObjectEl.fileLocations, IdTokenRegion,
1041 combineLocations(el->qualifiedId));
1042 FileLocations::addRegion(containingObjectEl.fileLocations, IdColonTokenRegion,
1043 el->colonToken);
1044 FileLocations::addRegion(containingObjectEl.fileLocations, IdNameRegion,
1045 combineLocations(el->statement));
1046 QmlComponent &comp = current<QmlComponent>();
1047 pathFromOwner = comp.addId(idVal, AddOption::KeepExisting, &idPtr);
1049 QStringLiteral(uR"([[:lower:]][[:lower:][:upper:]0-9_]*)")));
1050 auto m = idRe.matchView(iExp->name);
1051 if (!m.hasMatch()) {
1052 qmlFile.addError(std::move(
1054 .warning(tr("id attributes should only be a lower case letter "
1055 "followed by letters, numbers or underscore, not %1")
1056 .arg(iExp->name))
1057 .withPath(pathFromOwner)));
1058 }
1059 } else {
1060 pathFromOwner =
1061 current<QmlObject>().addBinding(bindingV, AddOption::KeepExisting, &bindingPtr);
1062 Q_ASSERT_X(bindingPtr, className, "binding could not be retrieved");
1063 qmlFile.addError(std::move(
1065 .warning(tr("id attributes should only be a lower case letter "
1066 "followed by letters, numbers or underscore, not %1 "
1067 "%2, assuming they refer to a property")
1068 .arg(script->code(), script->astRelocatableDump()))
1069 .withPath(pathFromOwner)));
1070 }
1071 } else {
1072 pathFromOwner =
1073 current<QmlObject>().addBinding(bindingV, AddOption::KeepExisting, &bindingPtr);
1074 QmlStackElement &containingObjectEl = currentEl<QmlObject>();
1075 // remove the containingObjectEl.path prefix from pathFromOwner
1076 Path pathFromContainingObject = pathFromOwner.mid(containingObjectEl.path.length());
1077 auto bindingFileLocation =
1078 FileLocations::ensure(containingObjectEl.fileLocations, pathFromContainingObject);
1079 FileLocations::addRegion(bindingFileLocation, IdentifierRegion,
1080 el->qualifiedId->identifierToken);
1081 FileLocations::addRegion(bindingFileLocation, ColonTokenRegion, el->colonToken);
1082
1083 setBindingIdentifiers(pathFromOwner, el->qualifiedId, bindingPtr);
1084
1085 Q_ASSERT_X(bindingPtr, className, "binding could not be retrieved");
1086 }
1087 if (bindingPtr)
1088 pushEl(pathFromOwner, *bindingPtr, el);
1089 else if (idPtr)
1090 pushEl(pathFromOwner, *idPtr, el);
1091 else
1092 Q_UNREACHABLE();
1094 // avoid duplicate colon location for id?
1095 FileLocations::addRegion(nodeStack.last().fileLocations, ColonTokenRegion, el->colonToken);
1096 return true;
1097}
1098
1099void QQmlDomAstCreator::setScriptExpression (const std::shared_ptr<ScriptExpression>& value)
1100{
1101 if (m_enableScriptExpressions
1102 && (scriptNodeStack.size() != 1 || currentScriptNodeEl().isList()))
1104 if (m_enableScriptExpressions) {
1105 FileLocations::Tree valueLoc = FileLocations::ensure(currentNodeEl().fileLocations,
1106 Path().field(Fields::value));
1107 value->setScriptElement(finalizeScriptExpression(currentScriptNodeEl().takeVariant(),
1108 Path().field(Fields::scriptElement),
1109 valueLoc));
1110 removeCurrentScriptNode({});
1111 }
1112};
1113
1115{
1116 DomValue &lastEl = currentNode();
1117 index_type idx = currentIndex();
1118 if (lastEl.kind == DomType::Binding) {
1119 Binding &b = std::get<Binding>(lastEl.value);
1120
1121 setScriptExpression(b.scriptExpressionValue());
1122
1123 QmlObject &containingObject = current<QmlObject>();
1124 Binding *bPtr = valueFromMultimap(containingObject.m_bindings, b.name(), idx);
1125 Q_ASSERT(bPtr);
1126 *bPtr = b;
1127 } else if (lastEl.kind == DomType::Id) {
1128 Id &id = std::get<Id>(lastEl.value);
1129
1130 setScriptExpression(id.value);
1131
1132 QmlComponent &comp = current<QmlComponent>();
1133 Id *idPtr = valueFromMultimap(comp.m_ids, id.name, idx);
1134 *idPtr = id;
1135 } else {
1136 Q_UNREACHABLE();
1137 }
1138
1139 // there should be no more uncollected script elements
1140 if (m_enableScriptExpressions && !scriptNodeStack.empty()) {
1142 }
1143 removeCurrentNode({});
1144}
1145
1147{
1148 QList<QmlObject> value;
1149 Binding bindingV(toString(el->qualifiedId), value, BindingType::Normal);
1150 Binding *bindingPtr;
1151 Path bindingPathFromOwner =
1152 current<QmlObject>().addBinding(bindingV, AddOption::KeepExisting, &bindingPtr);
1153 if (bindingV.name() == u"id")
1154 qmlFile.addError(std::move(
1156 .error(tr("id attributes should have only simple strings as values"))
1157 .withPath(bindingPathFromOwner)));
1158
1159 setBindingIdentifiers(bindingPathFromOwner, el->qualifiedId, bindingPtr);
1160
1161 pushEl(bindingPathFromOwner, *bindingPtr, el);
1162 FileLocations::addRegion(currentNodeEl().fileLocations, ColonTokenRegion, el->colonToken);
1164 FileLocations::Tree arrayList =
1165 createMap(currentNodeEl().fileLocations, Path::Field(Fields::value), nullptr);
1166 FileLocations::addRegion(arrayList, LeftBracketRegion, el->lbracketToken);
1167 FileLocations::addRegion(arrayList, RightBracketRegion, el->rbracketToken);
1168 arrayBindingLevels.append(nodeStack.size());
1169 return true;
1170}
1171
1173{
1174 index_type idx = currentIndex();
1175 Binding &b = std::get<Binding>(currentNode().value);
1176 Binding *bPtr = valueFromMultimap(current<QmlObject>().m_bindings, b.name(), idx);
1177 *bPtr = b;
1178 arrayBindingLevels.removeLast();
1179 removeCurrentNode(DomType::Binding);
1180}
1181
1183{
1184 if (!m_enableScriptExpressions)
1185 return false;
1186
1187 auto currentList = makeScriptList(list);
1188
1189 for (auto it = list; it; it = it->next) {
1190 Node::accept(it->expression, this);
1191 if (!m_enableScriptExpressions)
1192 return false;
1193
1194 if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) {
1196 return false;
1197 }
1198 currentList.append(scriptNodeStack.last().takeVariant());
1199 scriptNodeStack.removeLast();
1200 }
1201
1202 pushScriptElement(currentList);
1203
1204 return false; // return false because we already iterated over the children using the custom
1205 // iteration above
1206}
1207
1209{
1210 return false; // do not create script node for Ui stuff
1211}
1212
1214{
1215 if (!m_enableScriptExpressions)
1216 return false;
1217
1218 auto currentList = makeScriptList(list);
1219
1220 for (auto it = list; it; it = it->next) {
1221 if (it->elision) {
1222 Node::accept(it->elision, this);
1223 if (scriptNodeStack.empty() || !scriptNodeStack.last().isList()) {
1225 return false;
1226 }
1227 currentList.append(scriptNodeStack.last().takeList());
1228 scriptNodeStack.removeLast();
1229 }
1230 if (it->element) {
1231 Node::accept(it->element, this);
1232 if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) {
1234 return false;
1235 }
1236 currentList.append(scriptNodeStack.last().takeVariant());
1237 scriptNodeStack.removeLast();
1238 }
1239 }
1240
1241 pushScriptElement(currentList);
1242
1243 return false; // return false because we already iterated over the children using the custom
1244 // iteration above
1245}
1246
1248{
1249 if (!m_enableScriptExpressions)
1250 return false;
1251
1252 auto currentList = makeScriptList(list);
1253
1254 for (auto it = list; it; it = it->next) {
1255 if (it->property) {
1256 Node::accept(it->property, this);
1257 if (!m_enableScriptExpressions)
1258 return false;
1259 if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) {
1261 return false;
1262 }
1263 currentList.append(scriptNodeStack.last().takeVariant());
1264 scriptNodeStack.removeLast();
1265 }
1266 }
1267
1268 pushScriptElement(currentList);
1269
1270 return false; // return false because we already iterated over the children using the custom
1271 // iteration above
1272}
1273
1280ScriptElementVariant QQmlDomAstCreator::scriptElementForQualifiedId(AST::UiQualifiedId *expression)
1281{
1282 auto id = std::make_shared<ScriptElements::IdentifierExpression>(
1283 expression->firstSourceLocation(), expression->lastSourceLocation());
1284 id->setName(expression->toString());
1285
1287}
1288
1290{
1291 if (!m_enableScriptExpressions)
1292 return false;
1293
1294 return false;
1295}
1296
1298{
1299 EnumDecl eDecl;
1300 eDecl.setName(el->name.toString());
1301 EnumDecl *ePtr;
1302 Path enumPathFromOwner =
1303 current<QmlComponent>().addEnumeration(eDecl, AddOption::KeepExisting, &ePtr);
1304 pushEl(enumPathFromOwner, *ePtr, el);
1305 FileLocations::addRegion(nodeStack.last().fileLocations, EnumKeywordRegion, el->enumToken);
1306 FileLocations::addRegion(nodeStack.last().fileLocations, IdentifierRegion, el->identifierToken);
1308 return true;
1309}
1310
1312{
1313 EnumDecl &e = std::get<EnumDecl>(currentNode().value);
1314 EnumDecl *ePtr =
1315 valueFromMultimap(current<QmlComponent>().m_enumerations, e.name(), currentIndex());
1316 Q_ASSERT(ePtr);
1317 *ePtr = e;
1318 removeCurrentNode(DomType::EnumDecl);
1319}
1320
1322{
1323 EnumItem it(el->member.toString(), el->value);
1324 EnumDecl &eDecl = std::get<EnumDecl>(currentNode().value);
1325 Path itPathFromDecl = eDecl.addValue(it);
1326 const auto map = createMap(DomType::EnumItem, itPathFromDecl, nullptr);
1327 FileLocations::addRegion(map, MainRegion, combine(el->memberToken, el->valueToken));
1328 if (el->memberToken.isValid())
1330 if (el->valueToken.isValid())
1332 return true;
1333}
1334
1336{
1337 Node::accept(el->next, this); // put other enum members at the same level as this one...
1338}
1339
1341{
1342 QStringList els = current<QmlComponent>().name().split(QLatin1Char('.'));
1343 els.append(el->name.toString());
1344 QString cName = els.join(QLatin1Char('.'));
1345 QmlComponent *compPtr;
1346 Path p = qmlFilePtr->addComponent(QmlComponent(cName), AddOption::KeepExisting, &compPtr);
1347
1348 if (m_enableScriptExpressions) {
1349 auto inlineComponentType =
1350 makeGenericScriptElement(el->identifierToken, DomType::ScriptType);
1351
1352 auto typeName = std::make_shared<ScriptElements::IdentifierExpression>(el->identifierToken);
1353 typeName->setName(el->name);
1354 inlineComponentType->insertChild(Fields::typeName,
1356 compPtr->setNameIdentifiers(
1357 finalizeScriptExpression(ScriptElementVariant::fromElement(inlineComponentType),
1358 p.field(Fields::nameIdentifiers), rootMap));
1359 }
1360
1361 pushEl(p, *compPtr, el);
1362 FileLocations::addRegion(nodeStack.last().fileLocations, ComponentKeywordRegion,
1363 el->componentToken);
1364 FileLocations::addRegion(nodeStack.last().fileLocations, IdentifierRegion, el->identifierToken);
1366 return true;
1367}
1368
1370{
1371 QmlComponent &component = std::get<QmlComponent>(currentNode().value);
1372 QStringList nameEls = component.name().split(QChar::fromLatin1('.'));
1373 QString key = nameEls.mid(1).join(QChar::fromLatin1('.'));
1374 QmlComponent *cPtr = valueFromMultimap(qmlFilePtr->lazyMembers().m_components, key, currentIndex());
1375 Q_ASSERT(cPtr);
1376 *cPtr = component;
1377 removeCurrentNode(DomType::QmlComponent);
1378}
1379
1381{
1382 PropertyDefinition pDef;
1383 pDef.name = el->name.toString();
1384 pDef.isRequired = true;
1385 PropertyDefinition *pDefPtr;
1386 Path pathFromOwner =
1387 current<QmlObject>().addPropertyDef(pDef, AddOption::KeepExisting, &pDefPtr);
1388 createMap(DomType::PropertyDefinition, pathFromOwner, el);
1389 return false;
1390}
1391
1393{
1394 QmlObject a;
1395 a.setName(QStringLiteral(u"@") + toString(el->qualifiedTypeNameId));
1396 // add annotation prototype?
1397 DomValue &containingElement = currentNode();
1398 Path pathFromOwner;
1399 QmlObject *aPtr = nullptr;
1400 switch (containingElement.kind) {
1401 case DomType::QmlObject:
1402 pathFromOwner = std::get<QmlObject>(containingElement.value).addAnnotation(a, &aPtr);
1403 break;
1404 case DomType::Binding:
1405 pathFromOwner = std::get<Binding>(containingElement.value)
1406 .addAnnotation(currentNodeEl().path, a, &aPtr);
1407 break;
1408 case DomType::Id:
1409 pathFromOwner =
1410 std::get<Id>(containingElement.value).addAnnotation(currentNodeEl().path, a, &aPtr);
1411 break;
1413 pathFromOwner = std::get<PropertyDefinition>(containingElement.value)
1414 .addAnnotation(currentNodeEl().path, a, &aPtr);
1415 break;
1417 pathFromOwner = std::get<MethodInfo>(containingElement.value)
1418 .addAnnotation(currentNodeEl().path, a, &aPtr);
1419 break;
1420 default:
1421 qCWarning(domLog) << "Unexpected container object for annotation:"
1422 << domTypeToString(containingElement.kind);
1423 Q_UNREACHABLE();
1424 }
1425 pushEl(pathFromOwner, *aPtr, el);
1426 return true;
1427}
1428
1430{
1431 DomValue &containingElement = currentNode(1);
1432 Path pathFromOwner;
1433 QmlObject &a = std::get<QmlObject>(currentNode().value);
1434 switch (containingElement.kind) {
1435 case DomType::QmlObject:
1436 std::get<QmlObject>(containingElement.value).m_annotations[currentIndex()] = a;
1437 break;
1438 case DomType::Binding:
1439 std::get<Binding>(containingElement.value).m_annotations[currentIndex()] = a;
1440 break;
1441 case DomType::Id:
1442 std::get<Id>(containingElement.value).annotations[currentIndex()] = a;
1443 break;
1445 std::get<PropertyDefinition>(containingElement.value).annotations[currentIndex()] = a;
1446 break;
1448 std::get<MethodInfo>(containingElement.value).annotations[currentIndex()] = a;
1449 break;
1450 default:
1451 Q_UNREACHABLE();
1452 }
1453 removeCurrentNode(DomType::QmlObject);
1454}
1455
1457{
1458 qmlFile.addError(astParseErrors().error(
1459 tr("Maximum statement or expression depth exceeded in QmlDomAstCreator")));
1460}
1461
1463{
1464 if (!m_enableScriptExpressions)
1465 return false;
1466
1467 return true;
1468}
1469
1471{
1472 if (!m_enableScriptExpressions)
1473 return;
1474
1475 auto current = makeScriptList(list);
1476
1477 for (auto it = list; it; it = it->next) {
1478 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1479 current.append(scriptNodeStack.takeLast().takeVariant());
1480 }
1481
1482 current.reverse();
1483 pushScriptElement(current);
1484}
1485
1487{
1488 if (!m_enableScriptExpressions)
1489 return false;
1490
1491 return true;
1492}
1493
1495{
1496 if (!m_enableScriptExpressions)
1497 return;
1498
1499 auto current = makeScriptElement<ScriptElements::BinaryExpression>(exp);
1500 current->addLocation(OperatorTokenRegion, exp->operatorToken);
1501 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1502 current->setRight(currentScriptNodeEl().takeVariant());
1503 removeCurrentScriptNode({});
1504 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1505 current->setLeft(currentScriptNodeEl().takeVariant());
1506 removeCurrentScriptNode({});
1507
1508 pushScriptElement(current);
1509}
1510
1512{
1513 if (!m_enableScriptExpressions)
1514 return false;
1515
1516 return true;
1517}
1518
1520{
1521 if (!m_enableScriptExpressions)
1522 return;
1523
1524 auto current = makeScriptElement<ScriptElements::BlockStatement>(block);
1525
1526 if (block->statements) {
1527 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1528 current->setStatements(currentScriptNodeEl().takeList());
1529 removeCurrentScriptNode(DomType::List);
1530 }
1531
1532 pushScriptElement(current);
1533}
1534
1536{
1537 if (!m_enableScriptExpressions)
1538 return false;
1539
1540 return true;
1541}
1542
1544{
1545 if (!m_enableScriptExpressions)
1546 return;
1547
1548 auto current = makeScriptElement<ScriptElements::ForStatement>(forStatement);
1549 current->addLocation(FileLocationRegion::ForKeywordRegion, forStatement->forToken);
1550 current->addLocation(FileLocationRegion::LeftParenthesisRegion, forStatement->lparenToken);
1552 forStatement->firstSemicolonToken);
1553 current->addLocation(FileLocationRegion::SecondSemicolonRegion,
1554 forStatement->secondSemicolonToken);
1555 current->addLocation(FileLocationRegion::RightParenthesisRegion, forStatement->rparenToken);
1556
1557 if (forStatement->statement) {
1558 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1559 current->setBody(currentScriptNodeEl().takeVariant());
1560 removeCurrentScriptNode(std::nullopt);
1561 }
1562
1563 if (forStatement->expression) {
1564 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1565 current->setExpression(currentScriptNodeEl().takeVariant());
1566 removeCurrentScriptNode(std::nullopt);
1567 }
1568
1569 if (forStatement->condition) {
1570 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1571 current->setCondition(currentScriptNodeEl().takeVariant());
1572 removeCurrentScriptNode(std::nullopt);
1573 }
1574
1575 if (forStatement->declarations) {
1576 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1577 auto variableDeclaration = makeGenericScriptElement(forStatement->declarations,
1579
1580 ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
1581 list.replaceKindForGenericChildren(DomType::ScriptPattern,
1583 variableDeclaration->insertChild(Fields::declarations, std::move(list));
1584 removeCurrentScriptNode({});
1585
1586 current->setDeclarations(ScriptElementVariant::fromElement(variableDeclaration));
1587
1588 if (auto pe = forStatement->declarations->declaration;
1589 pe && pe->declarationKindToken.isValid()) {
1590 current->addLocation(FileLocationRegion::TypeIdentifierRegion,
1591 pe->declarationKindToken);
1592 }
1593 }
1594
1595 if (forStatement->initialiser) {
1596 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1597 current->setInitializer(currentScriptNodeEl().takeVariant());
1598 removeCurrentScriptNode(std::nullopt);
1599 }
1600 pushScriptElement(current);
1601}
1602
1604{
1605 if (!m_enableScriptExpressions)
1606 return false;
1607
1608 auto current = makeScriptElement<ScriptElements::IdentifierExpression>(expression);
1609 current->setName(expression->name);
1610 pushScriptElement(current);
1611 return true;
1612}
1613
1615{
1616 if (!m_enableScriptExpressions)
1617 return false;
1618
1619 auto current = makeScriptElement<ScriptElements::Literal>(expression);
1620 current->setLiteralValue(expression->value);
1621 pushScriptElement(current);
1622 return true;
1623}
1624
1626{
1627 if (!m_enableScriptExpressions)
1628 return false;
1629
1630 pushScriptElement(makeStringLiteral(expression->value, expression));
1631 return true;
1632}
1633
1635{
1636 if (!m_enableScriptExpressions)
1637 return false;
1638
1639 auto current = makeScriptElement<ScriptElements::Literal>(expression);
1640 current->setLiteralValue(nullptr);
1641 pushScriptElement(current);
1642 return true;
1643}
1644
1646{
1647 if (!m_enableScriptExpressions)
1648 return false;
1649
1650 auto current = makeScriptElement<ScriptElements::Literal>(expression);
1651 current->setLiteralValue(true);
1652 pushScriptElement(current);
1653 return true;
1654}
1655
1657{
1658 if (!m_enableScriptExpressions)
1659 return false;
1660
1661 auto current = makeScriptElement<ScriptElements::Literal>(expression);
1662 current->setLiteralValue(false);
1663 pushScriptElement(current);
1664 return true;
1665}
1666
1668{
1669 if (!m_enableScriptExpressions)
1670 return false;
1671
1672 auto current = makeScriptElement<ScriptElements::IdentifierExpression>(expression);
1673 current->setName(expression->id);
1674 pushScriptElement(current);
1675 return true;
1676}
1677
1679{
1680 if (!m_enableScriptExpressions)
1681 return false;
1682
1683 pushScriptElement(makeStringLiteral(expression->id, expression));
1684 return true;
1685}
1686
1688{
1689 if (!m_enableScriptExpressions)
1690 return false;
1691
1692 // do nothing: the work is done in (end)visit(AST::Type*).
1693 return true;
1694}
1695
1697{
1698 if (!m_enableScriptExpressions)
1699 return false;
1700
1701 auto current = makeScriptElement<ScriptElements::Literal>(expression);
1702 current->setLiteralValue(expression->id);
1703 pushScriptElement(current);
1704 return true;
1705}
1706
1708{
1709 if (!m_enableScriptExpressions)
1710 return false;
1711
1712 // nothing to do, just forward the underlying expression without changing/wrapping it
1713 return true;
1714}
1715
1717{
1718 if (!m_enableScriptExpressions)
1719 return false;
1720
1721 auto currentList = makeScriptList(list);
1722
1723 for (auto it = list; it; it = it->next) {
1724 if (it->declaration) {
1725 Node::accept(it->declaration, this);
1726 if (!m_enableScriptExpressions)
1727 return false;
1728 if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) {
1730 return false;
1731 }
1732 currentList.append(scriptNodeStack.last().takeVariant());
1733 scriptNodeStack.removeLast();
1734 }
1735 }
1736 pushScriptElement(currentList);
1737
1738 return false; // return false because we already iterated over the children using the custom
1739 // iteration above
1740}
1741
1743{
1744 if (!m_enableScriptExpressions)
1745 return false;
1746
1747 auto currentList = makeScriptList(list);
1748
1749 for (auto it = list; it; it = it->next) {
1750 auto current = makeGenericScriptElement(it->commaToken, DomType::ScriptElision);
1751 currentList.append(ScriptElementVariant::fromElement(current));
1752 }
1753 pushScriptElement(currentList);
1754
1755 return false; // return false because we already iterated over the children using the custom
1756 // iteration above
1757}
1758
1760{
1761 if (!m_enableScriptExpressions)
1762 return false;
1763
1764 return true;
1765}
1766
1774 const std::shared_ptr<ScriptElements::GenericScriptElement> &current)
1775{
1776 if (pe->equalToken.isValid())
1777 current->addLocation(FileLocationRegion::EqualTokenRegion, pe->equalToken);
1778
1779 if (pe->identifierToken.isValid() && !pe->bindingIdentifier.isEmpty()) {
1780 auto identifier =
1781 std::make_shared<ScriptElements::IdentifierExpression>(pe->identifierToken);
1782 identifier->setName(pe->bindingIdentifier);
1783 current->insertChild(Fields::identifier, ScriptElementVariant::fromElement(identifier));
1784 }
1785 if (pe->initializer) {
1786 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1787 current->insertChild(Fields::initializer, scriptNodeStack.last().takeVariant());
1788 scriptNodeStack.removeLast();
1789 }
1790 if (pe->typeAnnotation) {
1791 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1792 current->insertChild(Fields::type, scriptNodeStack.last().takeVariant());
1793 scriptNodeStack.removeLast();
1794 }
1795 if (pe->bindingTarget) {
1796 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1797 current->insertChild(Fields::bindingElement, scriptNodeStack.last().takeVariant());
1798 scriptNodeStack.removeLast();
1799 }
1800}
1801
1803{
1804 if (!m_enableScriptExpressions)
1805 return;
1806
1807 auto element = makeGenericScriptElement(pe, DomType::ScriptPattern);
1808 endVisitHelper(pe, element);
1809 // check if helper disabled scriptexpressions
1810 if (!m_enableScriptExpressions)
1811 return;
1812
1813 pushScriptElement(element);
1814}
1815
1817{
1818 if (!m_enableScriptExpressions)
1819 return false;
1820
1821 return true;
1822}
1823
1825{
1826 if (!m_enableScriptExpressions)
1827 return;
1828
1829 auto current = makeScriptElement<ScriptElements::IfStatement>(ifStatement);
1830 current->addLocation(LeftParenthesisRegion, ifStatement->lparenToken);
1831 current->addLocation(RightParenthesisRegion, ifStatement->rparenToken);
1832 current->addLocation(ElseKeywordRegion, ifStatement->elseToken);
1833 current->addLocation(IfKeywordRegion, ifStatement->ifToken);
1834
1835 if (ifStatement->ko) {
1836 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1837 current->setAlternative(scriptNodeStack.last().takeVariant());
1838 scriptNodeStack.removeLast();
1839 }
1840
1841 if (ifStatement->ok) {
1842 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1843 current->setConsequence(scriptNodeStack.last().takeVariant());
1844 scriptNodeStack.removeLast();
1845 }
1846 if (ifStatement->expression) {
1847 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1848 current->setCondition(scriptNodeStack.last().takeVariant());
1849 scriptNodeStack.removeLast();
1850 }
1851
1852 pushScriptElement(current);
1853}
1854
1856{
1857 if (!m_enableScriptExpressions)
1858 return false;
1859
1860 return true;
1861}
1862
1864{
1865 if (!m_enableScriptExpressions)
1866 return;
1867
1868 auto current = makeScriptElement<ScriptElements::ReturnStatement>(returnStatement);
1869 current->addLocation(ReturnKeywordRegion, returnStatement->returnToken);
1870
1871 if (returnStatement->expression) {
1872 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1873 current->setExpression(currentScriptNodeEl().takeVariant());
1874 removeCurrentScriptNode({});
1875 }
1876
1877 pushScriptElement(current);
1878}
1879
1881{
1882 if (!m_enableScriptExpressions)
1883 return false;
1884
1885 return true;
1886}
1887
1889{
1890 if (!m_enableScriptExpressions)
1891 return;
1892
1893 auto current = makeScriptElement<ScriptElements::BinaryExpression>(expression);
1895 current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->dotToken);
1896
1897 if (expression->base) {
1898 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1899 current->setLeft(currentScriptNodeEl().takeVariant());
1900 removeCurrentScriptNode({});
1901 }
1902
1903 auto scriptIdentifier =
1904 std::make_shared<ScriptElements::IdentifierExpression>(expression->identifierToken);
1905 scriptIdentifier->setName(expression->name);
1906 current->setRight(ScriptElementVariant::fromElement(scriptIdentifier));
1907
1908 pushScriptElement(current);
1909}
1910
1912{
1913 if (!m_enableScriptExpressions)
1914 return false;
1915
1916 return true;
1917}
1918
1920{
1921 if (!m_enableScriptExpressions)
1922 return;
1923
1924 auto current = makeScriptElement<ScriptElements::BinaryExpression>(expression);
1926 current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->lbracketToken);
1927
1928 if (expression->expression) {
1929 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1930 // if scriptNodeStack.last() is fieldmember expression, add expression to it instead of
1931 // creating new one
1932 current->setRight(currentScriptNodeEl().takeVariant());
1933 removeCurrentScriptNode({});
1934 }
1935
1936 if (expression->base) {
1937 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1938 current->setLeft(currentScriptNodeEl().takeVariant());
1939 removeCurrentScriptNode({});
1940 }
1941
1942 pushScriptElement(current);
1943}
1944
1946{
1947 if (!m_enableScriptExpressions)
1948 return false;
1949
1950 return true;
1951}
1952
1954{
1955 if (!m_enableScriptExpressions)
1956 return;
1957
1958 auto current = makeGenericScriptElement(exp, DomType::ScriptCallExpression);
1959 current->addLocation(LeftParenthesisRegion, exp->lparenToken);
1960 current->addLocation(RightParenthesisRegion, exp->rparenToken);
1961
1962 if (exp->arguments) {
1963 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1964 current->insertChild(Fields::arguments, currentScriptNodeEl().takeList());
1965 removeCurrentScriptNode({});
1966 } else {
1967 // insert empty list
1968 current->insertChild(Fields::arguments,
1969 ScriptElements::ScriptList(exp->lparenToken, exp->rparenToken));
1970 }
1971
1972 if (exp->base) {
1973 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
1974 current->insertChild(Fields::callee, currentScriptNodeEl().takeVariant());
1975 removeCurrentScriptNode({});
1976 }
1977
1978 pushScriptElement(current);
1979}
1980
1982{
1983 if (!m_enableScriptExpressions)
1984 return false;
1985
1986 return true;
1987}
1988
1990{
1991 if (!m_enableScriptExpressions)
1992 return;
1993
1994 auto current = makeGenericScriptElement(exp, DomType::ScriptArray);
1995
1996 if (exp->elements) {
1997 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1998 ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
1999 list.replaceKindForGenericChildren(DomType::ScriptPattern, DomType::ScriptArrayEntry);
2000 current->insertChild(Fields::elements, std::move(list));
2001
2002 removeCurrentScriptNode({});
2003 } else {
2004 // insert empty list
2005 current->insertChild(Fields::elements,
2006 ScriptElements::ScriptList(exp->lbracketToken, exp->rbracketToken));
2007 }
2008
2009 pushScriptElement(current);
2010}
2011
2013{
2014 if (!m_enableScriptExpressions)
2015 return false;
2016
2017 return true;
2018}
2019
2021{
2022 if (!m_enableScriptExpressions)
2023 return;
2024
2025 auto current = makeGenericScriptElement(exp, DomType::ScriptObject);
2026
2027 if (exp->properties) {
2028 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
2029 current->insertChild(Fields::properties, currentScriptNodeEl().takeList());
2030 removeCurrentScriptNode({});
2031 } else {
2032 // insert empty list
2033 current->insertChild(Fields::properties,
2034 ScriptElements::ScriptList(exp->lbraceToken, exp->rbraceToken));
2035 }
2036
2037 pushScriptElement(current);
2038}
2039
2041{
2042 if (!m_enableScriptExpressions)
2043 return false;
2044
2045 return true;
2046}
2047
2049{
2050 if (!m_enableScriptExpressions)
2051 return;
2052
2053 auto current = makeGenericScriptElement(exp, DomType::ScriptProperty);
2054
2055 // handle the stuff from PatternProperty's base class PatternElement
2056 endVisitHelper(static_cast<PatternElement *>(exp), current);
2057
2058 // check if helper disabled scriptexpressions
2059 if (!m_enableScriptExpressions)
2060 return;
2061
2062 if (exp->name) {
2063 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2064 current->insertChild(Fields::name, currentScriptNodeEl().takeVariant());
2065 removeCurrentScriptNode({});
2066 }
2067
2068 pushScriptElement(current);
2069}
2070
2072{
2073 if (!m_enableScriptExpressions)
2074 return false;
2075
2076 return true;
2077}
2078
2080{
2081 if (!m_enableScriptExpressions)
2082 return;
2083
2084 auto current = makeGenericScriptElement(statement, DomType::ScriptVariableDeclaration);
2085 current->addLocation(FileLocationRegion::TypeIdentifierRegion, statement->declarationKindToken);
2086
2087 if (statement->declarations) {
2088 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
2089
2090 ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
2091 list.replaceKindForGenericChildren(DomType::ScriptPattern,
2093 current->insertChild(Fields::declarations, std::move(list));
2094
2095 removeCurrentScriptNode({});
2096 }
2097
2098 pushScriptElement(current);
2099}
2100
2102{
2103 if (!m_enableScriptExpressions)
2104 return false;
2105
2106 return true;
2107}
2108
2110{
2111 if (!m_enableScriptExpressions)
2112 return;
2113
2114 auto current = makeGenericScriptElement(exp, DomType::ScriptType);
2115
2116 if (exp->typeArgument) {
2117 current->insertChild(Fields::typeArgumentName,
2118 fieldMemberExpressionForQualifiedId(exp->typeArgument));
2119 current->addLocation(FileLocationRegion::IdentifierRegion, combineLocations(exp->typeArgument));
2120 }
2121
2122 if (exp->typeId) {
2123 current->insertChild(Fields::typeName, fieldMemberExpressionForQualifiedId(exp->typeId));
2124 current->addLocation(FileLocationRegion::TypeIdentifierRegion, combineLocations(exp->typeId));
2125 }
2126
2127 pushScriptElement(current);
2128}
2129
2131{
2132 if (!m_enableScriptExpressions)
2133 return false;
2134
2135 return true;
2136}
2137
2139{
2140 if (!m_enableScriptExpressions)
2141 return;
2142
2143 auto current = makeGenericScriptElement(exp, DomType::ScriptDefaultClause);
2144 current->addLocation(DefaultKeywordRegion, exp->defaultToken);
2145 current->addLocation(ColonTokenRegion, exp->colonToken);
2146
2147 if (exp->statements) {
2148 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
2149 current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
2150 removeCurrentScriptNode({});
2151 }
2152
2153 pushScriptElement(current);
2154}
2155
2157{
2158 if (!m_enableScriptExpressions)
2159 return false;
2160
2161 return true;
2162}
2163
2165{
2166 if (!m_enableScriptExpressions)
2167 return;
2168
2169 auto current = makeGenericScriptElement(exp, DomType::ScriptCaseClause);
2170 current->addLocation(FileLocationRegion::CaseKeywordRegion, exp->caseToken);
2171 current->addLocation(FileLocationRegion::ColonTokenRegion, exp->colonToken);
2172
2173 if (exp->statements) {
2174 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
2175 current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
2176 removeCurrentScriptNode({});
2177 }
2178
2179 if (exp->expression) {
2180 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2181 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2182 removeCurrentScriptNode({});
2183 }
2184
2185 pushScriptElement(current);
2186}
2187
2189{
2190 if (!m_enableScriptExpressions)
2191 return false;
2192
2193 return true;
2194}
2195
2197{
2198 if (!m_enableScriptExpressions)
2199 return;
2200
2201 auto current = makeScriptList(list);
2202
2203 for (auto it = list; it; it = it->next) {
2204 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2205 current.append(scriptNodeStack.takeLast().takeVariant());
2206 }
2207
2208 current.reverse();
2209 pushScriptElement(current);
2210}
2211
2213{
2214 if (!m_enableScriptExpressions)
2215 return false;
2216
2217 return true;
2218}
2219
2221{
2222 if (!m_enableScriptExpressions)
2223 return;
2224
2225 auto current = makeGenericScriptElement(exp, DomType::ScriptCaseBlock);
2226 current->addLocation(FileLocationRegion::LeftBraceRegion, exp->lbraceToken);
2227 current->addLocation(FileLocationRegion::RightBraceRegion, exp->rbraceToken);
2228
2229 if (exp->moreClauses) {
2230 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
2231 current->insertChild(Fields::moreCaseClauses, currentScriptNodeEl().takeList());
2232 removeCurrentScriptNode({});
2233 }
2234
2235 if (exp->defaultClause) {
2236 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2237 current->insertChild(Fields::defaultClause, currentScriptNodeEl().takeVariant());
2238 removeCurrentScriptNode({});
2239 }
2240
2241 if (exp->clauses) {
2242 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
2243 current->insertChild(Fields::caseClauses, currentScriptNodeEl().takeList());
2244 removeCurrentScriptNode({});
2245 }
2246 pushScriptElement(current);
2247}
2248
2250{
2251 if (!m_enableScriptExpressions)
2252 return false;
2253
2254 return true;
2255}
2256
2258{
2259 if (!m_enableScriptExpressions)
2260 return;
2261
2262 auto current = makeGenericScriptElement(exp, DomType::ScriptSwitchStatement);
2263 current->addLocation(FileLocationRegion::SwitchKeywordRegion, exp->switchToken);
2264 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2265 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2266
2267 if (exp->block) {
2268 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2269 current->insertChild(Fields::caseBlock, currentScriptNodeEl().takeVariant());
2270 removeCurrentScriptNode({});
2271 }
2272 if (exp->expression) {
2273 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2274 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2275 removeCurrentScriptNode({});
2276 }
2277
2278 pushScriptElement(current);
2279}
2280
2282{
2283 if (!m_enableScriptExpressions)
2284 return false;
2285
2286 return true;
2287}
2288
2290{
2291 if (!m_enableScriptExpressions)
2292 return;
2293
2294 auto current = makeGenericScriptElement(exp, DomType::ScriptWhileStatement);
2295 current->addLocation(FileLocationRegion::WhileKeywordRegion, exp->whileToken);
2296 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2297 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2298
2299 if (exp->statement) {
2300 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2301 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2302 removeCurrentScriptNode({});
2303 }
2304
2305 if (exp->expression) {
2306 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2307 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2308 removeCurrentScriptNode({});
2309 }
2310
2311 pushScriptElement(current);
2312}
2313
2315{
2316 if (!m_enableScriptExpressions)
2317 return false;
2318
2319 return true;
2320}
2321
2323{
2324 if (!m_enableScriptExpressions)
2325 return;
2326
2327 auto current = makeGenericScriptElement(exp, DomType::ScriptDoWhileStatement);
2328 current->addLocation(FileLocationRegion::DoKeywordRegion, exp->doToken);
2329 current->addLocation(FileLocationRegion::WhileKeywordRegion, exp->whileToken);
2330 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2331 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2332
2333 if (exp->expression) {
2334 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2335 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2336 removeCurrentScriptNode({});
2337 }
2338
2339 if (exp->statement) {
2340 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2341 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2342 removeCurrentScriptNode({});
2343 }
2344
2345 pushScriptElement(current);
2346}
2347
2349{
2350 if (!m_enableScriptExpressions)
2351 return false;
2352
2353 return true;
2354}
2355
2357{
2358 if (!m_enableScriptExpressions)
2359 return;
2360
2361 auto current = makeGenericScriptElement(exp, DomType::ScriptForEachStatement);
2362 current->addLocation(FileLocationRegion::ForKeywordRegion, exp->forToken);
2363 current->addLocation(FileLocationRegion::InOfTokenRegion, exp->inOfToken);
2364 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2365 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2366
2367 if (exp->statement) {
2368 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2369 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2370 removeCurrentScriptNode({});
2371 }
2372 if (exp->expression) {
2373 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2374 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2375 removeCurrentScriptNode({});
2376 }
2377
2378 if (exp->lhs) {
2379 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2380 current->insertChild(Fields::bindingElement, currentScriptNodeEl().takeVariant());
2381 removeCurrentScriptNode({});
2382
2383 if (auto pe = AST::cast<PatternElement *>(exp->lhs);
2384 pe && pe->declarationKindToken.isValid()) {
2385 current->addLocation(FileLocationRegion::TypeIdentifierRegion,
2386 pe->declarationKindToken);
2387 }
2388 }
2389
2390 pushScriptElement(current);
2391}
2392
2393
2395{
2396 // TODO: Add support for js expressions in classes
2397 // For now, turning off explicitly to avoid unwanted problems
2398 if (m_enableScriptExpressions)
2400 return true;
2401}
2402
2406
2408{
2409 // TODO: Add support for template literals
2410 // For now, turning off explicitly to avoid unwanted problems
2411 if (m_enableScriptExpressions)
2413 return true;
2414}
2415
2417{
2418 return m_enableScriptExpressions;
2419}
2420
2422{
2423 if (!m_enableScriptExpressions)
2424 return;
2425
2426 auto current = makeGenericScriptElement(statement, DomType::ScriptTryCatchStatement);
2427 current->addLocation(FileLocationRegion::TryKeywordRegion, statement->tryToken);
2428
2429 if (auto exp = statement->finallyExpression) {
2430 current->addLocation(FileLocationRegion::FinallyKeywordRegion, exp->finallyToken);
2431
2432 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2433 current->insertChild(Fields::finallyBlock, currentScriptNodeEl().takeVariant());
2434 removeCurrentScriptNode({});
2435 }
2436
2437 if (auto exp = statement->catchExpression) {
2438 current->addLocation(FileLocationRegion::CatchKeywordRegion, exp->catchToken);
2439 current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
2440 current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
2441
2442 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2443 current->insertChild(Fields::catchBlock, currentScriptNodeEl().takeVariant());
2444 removeCurrentScriptNode({});
2445 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2446 current->insertChild(Fields::catchParameter, currentScriptNodeEl().takeVariant());
2447 removeCurrentScriptNode({});
2448 }
2449
2450 if (statement->statement) {
2451 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2452 current->insertChild(Fields::block, currentScriptNodeEl().takeVariant());
2453 removeCurrentScriptNode({});
2454 }
2455
2456 pushScriptElement(current);
2457}
2458
2460{
2461 // handled in visit(AST::TryStatement* )
2462 return m_enableScriptExpressions;
2463}
2464
2466{
2467 // handled in endVisit(AST::TryStatement* )
2468}
2469
2471{
2472 // handled in visit(AST::TryStatement* )
2473 return m_enableScriptExpressions;
2474}
2475
2477{
2478 // handled in endVisit(AST::TryStatement* )
2479}
2480
2482{
2483 return m_enableScriptExpressions;
2484}
2485
2487{
2488 if (!m_enableScriptExpressions)
2489 return;
2490
2491 auto current = makeGenericScriptElement(statement, DomType::ScriptThrowStatement);
2492 current->addLocation(FileLocationRegion::ThrowKeywordRegion, statement->throwToken);
2493
2494 if (statement->expression) {
2495 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2496 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2497 removeCurrentScriptNode({});
2498 }
2499
2500 pushScriptElement(current);
2501}
2502
2504{
2505 return m_enableScriptExpressions;
2506}
2507
2509{
2510 if (!m_enableScriptExpressions)
2511 return;
2512
2513 auto current = makeGenericScriptElement(statement, DomType::ScriptLabelledStatement);
2514 current->addLocation(FileLocationRegion::ColonTokenRegion, statement->colonToken);
2515
2516 auto label = std::make_shared<ScriptElements::IdentifierExpression>(statement->identifierToken);
2517 label->setName(statement->label);
2518 current->insertChild(Fields::label, ScriptElementVariant::fromElement(label));
2519
2520
2521 if (statement->statement) {
2522 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2523 current->insertChild(Fields::statement, currentScriptNodeEl().takeVariant());
2524 removeCurrentScriptNode({});
2525 }
2526
2527 pushScriptElement(current);
2528}
2529
2531{
2532 return m_enableScriptExpressions;
2533}
2534
2536{
2537 if (!m_enableScriptExpressions)
2538 return;
2539
2540 auto current = makeGenericScriptElement(statement, DomType::ScriptBreakStatement);
2541 current->addLocation(FileLocationRegion::BreakKeywordRegion, statement->breakToken);
2542
2543 if (!statement->label.isEmpty()) {
2544 auto label =
2545 std::make_shared<ScriptElements::IdentifierExpression>(statement->identifierToken);
2546 label->setName(statement->label);
2547 current->insertChild(Fields::label, ScriptElementVariant::fromElement(label));
2548 }
2549
2550 pushScriptElement(current);
2551}
2552
2553// note: thats for comma expressions
2555{
2556 return m_enableScriptExpressions;
2557}
2558
2559// note: thats for comma expressions
2561{
2562 if (!m_enableScriptExpressions)
2563 return;
2564
2565 auto current = makeScriptElement<ScriptElements::BinaryExpression>(commaExpression);
2566 current->addLocation(OperatorTokenRegion, commaExpression->commaToken);
2567
2568 if (commaExpression->right) {
2569 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2570 current->setRight(currentScriptNodeEl().takeVariant());
2571 removeCurrentScriptNode({});
2572 }
2573
2574 if (commaExpression->left) {
2575 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2576 current->setLeft(currentScriptNodeEl().takeVariant());
2577 removeCurrentScriptNode({});
2578 }
2579
2580 pushScriptElement(current);
2581}
2582
2584{
2585 return m_enableScriptExpressions;
2586}
2587
2589{
2590 if (!m_enableScriptExpressions)
2591 return;
2592
2593 auto current = makeGenericScriptElement(expression, DomType::ScriptConditionalExpression);
2594 current->addLocation(FileLocationRegion::QuestionMarkTokenRegion, expression->questionToken);
2595 current->addLocation(FileLocationRegion::ColonTokenRegion, expression->colonToken);
2596
2597 if (expression->ko) {
2598 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2599 current->insertChild(Fields::alternative, currentScriptNodeEl().takeVariant());
2600 removeCurrentScriptNode({});
2601 }
2602
2603 if (expression->ok) {
2604 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2605 current->insertChild(Fields::consequence, currentScriptNodeEl().takeVariant());
2606 removeCurrentScriptNode({});
2607 }
2608
2609 if (expression->expression) {
2610 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2611 current->insertChild(Fields::condition, currentScriptNodeEl().takeVariant());
2612 removeCurrentScriptNode({});
2613 }
2614
2615 pushScriptElement(current);
2616}
2617
2619{
2620 return m_enableScriptExpressions;
2621}
2622
2624{
2625 if (!m_enableScriptExpressions)
2626 return;
2627
2628 auto current = makeGenericScriptElement(statement, DomType::ScriptContinueStatement);
2629 current->addLocation(FileLocationRegion::ContinueKeywordRegion, statement->continueToken);
2630
2631 if (!statement->label.isEmpty()) {
2632 auto label =
2633 std::make_shared<ScriptElements::IdentifierExpression>(statement->identifierToken);
2634 label->setName(statement->label);
2635 current->insertChild(Fields::label, ScriptElementVariant::fromElement(label));
2636 }
2637
2638 pushScriptElement(current);
2639}
2640
2646std::shared_ptr<ScriptElements::GenericScriptElement>
2647QQmlDomAstCreator::makeUnaryExpression(AST::Node *expression, QQmlJS::SourceLocation operatorToken,
2648 bool hasExpression, UnaryExpressionKind kind)
2649{
2650 const DomType type = [&kind]() {
2651 switch (kind) {
2652 case Prefix:
2654 case Postfix:
2656 }
2657 Q_UNREACHABLE_RETURN(DomType::ScriptUnaryExpression);
2658 }();
2659
2660 auto current = makeGenericScriptElement(expression, type);
2661 current->addLocation(FileLocationRegion::OperatorTokenRegion, operatorToken);
2662
2663 if (hasExpression) {
2664 if (scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()) {
2666 return {};
2667 }
2668 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2669 removeCurrentScriptNode({});
2670 }
2671
2672 return current;
2673}
2674
2676{
2677 return m_enableScriptExpressions;
2678}
2679
2681{
2682 if (!m_enableScriptExpressions)
2683 return;
2684
2685 auto current =
2686 makeUnaryExpression(statement, statement->minusToken, statement->expression, Prefix);
2687 if (!current)
2688 return;
2689
2690 pushScriptElement(current);
2691}
2692
2694{
2695 return m_enableScriptExpressions;
2696}
2697
2699{
2700 if (!m_enableScriptExpressions)
2701 return;
2702
2703 auto current =
2704 makeUnaryExpression(statement, statement->plusToken, statement->expression, Prefix);
2705 if (!current)
2706 return;
2707
2708 pushScriptElement(current);
2709}
2710
2712{
2713 return m_enableScriptExpressions;
2714}
2715
2717{
2718 if (!m_enableScriptExpressions)
2719 return;
2720
2721 auto current =
2722 makeUnaryExpression(statement, statement->tildeToken, statement->expression, Prefix);
2723 if (!current)
2724 return;
2725
2726 pushScriptElement(current);
2727}
2728
2730{
2731 return m_enableScriptExpressions;
2732}
2733
2735{
2736 if (!m_enableScriptExpressions)
2737 return;
2738
2739 auto current =
2740 makeUnaryExpression(statement, statement->notToken, statement->expression, Prefix);
2741 if (!current)
2742 return;
2743
2744 pushScriptElement(current);
2745}
2746
2748{
2749 return m_enableScriptExpressions;
2750}
2751
2753{
2754 if (!m_enableScriptExpressions)
2755 return;
2756
2757 auto current =
2758 makeUnaryExpression(statement, statement->typeofToken, statement->expression, Prefix);
2759 if (!current)
2760 return;
2761
2762 pushScriptElement(current);
2763}
2764
2766{
2767 return m_enableScriptExpressions;
2768}
2769
2771{
2772 if (!m_enableScriptExpressions)
2773 return;
2774
2775 auto current =
2776 makeUnaryExpression(statement, statement->deleteToken, statement->expression, Prefix);
2777 if (!current)
2778 return;
2779
2780 pushScriptElement(current);
2781}
2782
2784{
2785 return m_enableScriptExpressions;
2786}
2787
2789{
2790 if (!m_enableScriptExpressions)
2791 return;
2792
2793 auto current =
2794 makeUnaryExpression(statement, statement->voidToken, statement->expression, Prefix);
2795 if (!current)
2796 return;
2797
2798 pushScriptElement(current);
2799}
2800
2802{
2803 return m_enableScriptExpressions;
2804}
2805
2807{
2808 if (!m_enableScriptExpressions)
2809 return;
2810
2811 auto current =
2812 makeUnaryExpression(statement, statement->decrementToken, statement->base, Postfix);
2813 if (!current)
2814 return;
2815
2816 pushScriptElement(current);
2817}
2818
2820{
2821 return m_enableScriptExpressions;
2822}
2823
2825{
2826 if (!m_enableScriptExpressions)
2827 return;
2828
2829 auto current =
2830 makeUnaryExpression(statement, statement->incrementToken, statement->base, Postfix);
2831 if (!current)
2832 return;
2833
2834 pushScriptElement(current);
2835}
2836
2838{
2839 return m_enableScriptExpressions;
2840}
2841
2843{
2844 if (!m_enableScriptExpressions)
2845 return;
2846
2847 auto current = makeUnaryExpression(statement, statement->incrementToken, statement->expression,
2848 Prefix);
2849 if (!current)
2850 return;
2851
2852 pushScriptElement(current);
2853}
2854
2856{
2857 return m_enableScriptExpressions;
2858}
2859
2861{
2862 if (!m_enableScriptExpressions)
2863 return;
2864
2865 auto current = makeGenericScriptElement(statement, DomType::ScriptEmptyStatement);
2866 current->addLocation(FileLocationRegion::SemicolonTokenRegion, statement->semicolonToken);
2867 pushScriptElement(current);
2868}
2869
2871{
2872 return m_enableScriptExpressions;
2873}
2874
2876{
2877 if (!m_enableScriptExpressions)
2878 return;
2879
2880 auto current = makeGenericScriptElement(expression, DomType::ScriptParenthesizedExpression);
2881 current->addLocation(FileLocationRegion::LeftParenthesisRegion, expression->lparenToken);
2882 current->addLocation(FileLocationRegion::RightParenthesisRegion, expression->rparenToken);
2883
2884 if (expression->expression) {
2885 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
2886 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2887 removeCurrentScriptNode({});
2888 }
2889
2890 pushScriptElement(current);
2891}
2892
2894{
2895 return m_enableScriptExpressions;
2896}
2897
2899{
2900 if (!m_enableScriptExpressions)
2901 return;
2902
2903 auto current = makeUnaryExpression(statement, statement->decrementToken, statement->expression,
2904 Prefix);
2905 if (!current)
2906 return;
2907
2908 pushScriptElement(current);
2909}
2910
2912{
2913 auto top = qmlFile.top();
2914 if (!top) {
2915 return {};
2916 }
2917 auto domEnvironment = top.as<DomEnvironment>();
2918 if (!domEnvironment) {
2919 return {};
2920 }
2921 return domEnvironment;
2922}
2923
2925{
2926 if (auto env = environmentFrom(qmlFile))
2927 return env->qmldirFiles();
2928
2929 return {};
2930}
2931
2933 MutableDomItem &qmlFile,
2934 QQmlJSLogger *logger,
2935 QQmlJSImporter *importer)
2936 : m_root(current),
2937 m_logger(logger),
2938 m_importer(importer),
2939 m_implicitImportDirectory(QQmlJSImportVisitor::implicitImportDirectory(
2940 m_logger->fileName(), m_importer->resourceFileMapper())),
2941 m_scopeCreator(m_root, m_importer, m_logger, m_implicitImportDirectory,
2942 qmldirFilesFrom(qmlFile)),
2943 m_domCreator(qmlFile)
2944{
2945}
2946
2947#define X(name) \
2948 bool QQmlDomAstCreatorWithQQmlJSScope::visit(name *node) \
2949 { \
2950 return visitT(node); \
2951 } \
2952 void QQmlDomAstCreatorWithQQmlJSScope::endVisit(name *node) \
2953 { \
2954 endVisitT(node); \
2955 }
2957#undef X
2958
2959void QQmlDomAstCreatorWithQQmlJSScope::setScopeInDomAfterEndvisit()
2960{
2961 const QQmlJSScope::ConstPtr scope = m_scopeCreator.m_currentScope;
2962 if (!m_domCreator.scriptNodeStack.isEmpty()) {
2963 auto topOfStack = m_domCreator.currentScriptNodeEl();
2964 switch (topOfStack.kind) {
2970 case DomType::List:
2971 m_domCreator.currentScriptNodeEl().setSemanticScope(scope);
2972 break;
2973 // TODO: find which script elements also have a scope and implement them here
2974 default:
2975 break;
2976 };
2977 } else if (!m_domCreator.nodeStack.isEmpty()) {
2978 std::visit(
2979 [&scope](auto &&e) {
2980 using U = std::remove_cv_t<std::remove_reference_t<decltype(e)>>;
2981 // TODO: find which dom elements also have a scope and implement them here
2982 if constexpr (std::is_same_v<U, QmlObject>) {
2983 e.setSemanticScope(scope);
2984 } else if constexpr (std::is_same_v<U, QmlComponent>) {
2985 e.setSemanticScope(scope);
2986 } else if constexpr (std::is_same_v<U, MethodInfo>) {
2987 if (e.body) {
2988 if (auto scriptElement = e.body->scriptElement()) {
2989 scriptElement.base()->setSemanticScope(scope);
2990 }
2991 }
2992 e.setSemanticScope(scope);
2993 }
2994 },
2995 m_domCreator.currentNodeEl().item.value);
2996 }
2997}
2998
2999void QQmlDomAstCreatorWithQQmlJSScope::setScopeInDomBeforeEndvisit()
3000{
3001 const QQmlJSScope::ConstPtr scope = m_scopeCreator.m_currentScope;
3002
3003 // depending whether the property definition has a binding, the property definition might be
3004 // either at the last position in the stack or at the position before the last position.
3005 if (m_domCreator.nodeStack.size() > 1
3006 && m_domCreator.nodeStack.last().item.kind == DomType::Binding) {
3007 std::visit(
3008 [&scope](auto &&e) {
3009 using U = std::remove_cv_t<std::remove_reference_t<decltype(e)>>;
3010 if constexpr (std::is_same_v<U, PropertyDefinition>) {
3011 // Make sure to use the property definition scope instead of the binding
3012 // scope. If the current scope is a binding scope (this happens when the
3013 // property definition has a binding, like `property int i: 45` for
3014 // example), then the property definition scope is the parent of the current
3015 // scope.
3016 e.setSemanticScope(scope->scopeType() == QQmlSA::ScopeType::JSFunctionScope
3017 ? scope->parentScope()
3018 : scope);
3019 Q_ASSERT(e.semanticScope()
3020 && e.semanticScope()->scopeType() == QQmlSA::ScopeType::QMLScope);
3021 }
3022 },
3023 m_domCreator.currentNodeEl(1).item.value);
3024 }
3025 if (m_domCreator.nodeStack.size() > 0) {
3026 std::visit(
3027 [&scope](auto &&e) {
3028 using U = std::remove_cv_t<std::remove_reference_t<decltype(e)>>;
3029 if constexpr (std::is_same_v<U, PropertyDefinition>) {
3030 e.setSemanticScope(scope);
3031 Q_ASSERT(e.semanticScope());
3032 } else if constexpr (std::is_same_v<U, MethodInfo>) {
3033 if (e.methodType == MethodInfo::Signal) {
3034 e.setSemanticScope(scope);
3035 }
3036 }
3037 },
3038 m_domCreator.currentNodeEl().item.value);
3039 }
3040}
3041
3045
3046} // end namespace Dom
3047} // end namespace QQmlJS
3048
3049#undef Q_SCRIPTELEMENT_DISABLE
3050#undef Q_SCRIPTELEMENT_EXIT_IF
3051
\inmodule QtCore
QString canonicalPath() const
Returns the canonical path, i.e.
Definition qdir.cpp:692
QDir dir() const
Returns a QDir object representing the path of the parent directory of the file system entry that thi...
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
T & last()
Definition qlist.h:648
bool empty() const noexcept
Definition qlist.h:685
value_type takeLast()
Definition qlist.h:567
void removeLast() noexcept
Definition qlist.h:815
QQmlJSScope::Ptr m_currentScope
QQmlJSScope::Ptr parentScope()
ScopeType scopeType() const
StatementList * statements
void accept(BaseVisitor *visitor)
ExpressionNode * expression
ExpressionNode * expression
SourceLocation firstSourceLocation() const override
SourceLocation lastSourceLocation() const override
VariableDeclarationList * declarations
ExpressionNode * expression
Path pathFromOwner(const DomItem &self) const override
Represents a consistent set of types organized in modules, it is the top level of the DOM.
function< void(const Path &, const DomItem &, const DomItem &)> Callback
void setName(const QString &name)
Represents a set of tags grouping a set of related error messages.
static void addRegion(const Tree &fLoc, FileLocationRegion region, SourceLocation loc)
std::shared_ptr< AttachedInfoT< FileLocations > > Tree
static Tree ensure(const Tree &base, const Path &basePath, AttachedInfo::PathType pType=AttachedInfo::PathType::Relative)
static FileToLoad fromFileSystem(const std::weak_ptr< DomEnvironment > &environment, const QString &canonicalPath)
std::shared_ptr< T > ownerAs() const
QString canonicalFilePath() const
void addError(ErrorMessage &&msg)
MutableDomItem path(const Path &p)
index_type headIndex(index_type defaultValue=-1) const
Path field(const QString &name) const
Path path(const Path &toAdd, bool avoidToAddAsBase=false) const
Path mid(int offset, int length) const
Path last() const
static Path Field(QStringView s=u"")
Path index(index_type i) const
virtual QQmlJSASTClassListToVisit void throwRecursionDepthError() override
QQmlDomAstCreatorWithQQmlJSScope(const QQmlJSScope::Ptr &current, MutableDomItem &qmlFile, QQmlJSLogger *logger, QQmlJSImporter *importer)
void endVisit(AST::UiProgram *) override
void endVisitHelper(AST::PatternElement *pe, const std::shared_ptr< ScriptElements::GenericScriptElement > &element)
QQmlDomAstCreator(const MutableDomItem &qmlFile)
bool visit(AST::UiProgram *program) override
void loadAnnotations(AST::UiObjectMember *el)
A QmlFile, when loaded in a DomEnvironment that has the DomCreationOption::WithSemanticAnalysis,...
void setName(const QString &name)
void setIdStr(const QString &id)
Path addPrototypePath(const Path &prototypePath)
static QmlUri fromDirectoryString(const QString &importStr)
Use this to contain any script element.
static ScriptElementVariant fromElement(const T &element)
static constexpr qint32 Latest
\inmodule QtCore \reentrant
static QString anchoredPattern(const QString &expression)
iterator end()
Definition qset.h:140
iterator find(const T &value)
Definition qset.h:159
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
constexpr bool isEmpty() const noexcept
Returns whether this string view is empty - that is, whether {size() == 0}.
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1121
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
void * data()
Returns a pointer to the contained object as a generic void* that can be written to.
QMap< QString, QString > map
[6]
QPixmap p2
QSet< QString >::iterator it
Path lookupTypePath(const QString &name)
static ScriptElementVariant fieldMemberExpressionForQualifiedId(const AST::UiQualifiedId *qualifiedId)
static ScriptElementVariant wrapIntoFieldMemberExpression(const ScriptElementVariant &left, const SourceLocation &dotToken, const ScriptElementVariant &right)
qint64 index_type
static const DomEnvironment * environmentFrom(MutableDomItem &qmlFile)
static ErrorGroups astParseErrors()
V * valueFromMultimap(QMultiMap< K, V > &mmap, const K &key, index_type idx)
QMLDOM_EXPORT QString domTypeToString(DomType k)
static QString toString(const UiQualifiedId *qualifiedId, QChar delimiter=QLatin1Char('.'))
static QStringList qmldirFilesFrom(MutableDomItem &qmlFile)
static void setFormalParameterKind(ScriptElementVariant &variant)
static QString typeToString(AST::Type *t)
SourceLocation combineLocations(SourceLocation s1, SourceLocation s2)
Combined button and popup list for selecting options.
@ CaseInsensitive
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
@ QtWarningMsg
Definition qlogging.h:31
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
const char * typeName
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
GLenum GLuint id
[7]
GLdouble GLdouble GLdouble GLdouble top
GLdouble GLdouble right
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint left
GLenum type
GLuint GLsizei const GLchar * label
[43]
GLuint program
GLenum const GLint * param
GLint first
GLfloat n
GLhandleARB obj
[2]
GLuint res
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
static qreal component(const QPointF &point, unsigned int i)
#define Q_SCRIPTELEMENT_EXIT_IF(check)
#define Q_SCRIPTELEMENT_DISABLE()
#define NewErrorGroup(name)
#define QQmlJSASTClassListToVisit
QDebug warning(QAnyStringView fileName, int lineNumber)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
SSL_CTX int void * arg
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define s2
#define s1
#define tr(X)
static const uint base
Definition qurlidna.cpp:20
QList< int > list
[14]
QVariant variant
[1]
QJSValueList args
QStringView el
\inmodule QtCore \reentrant
Definition qchar.h:18