Qt 6.x
The Qt SDK
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
16#include <QtQml/private/qqmljsast_p.h>
17
18#include <QtCore/QDir>
19#include <QtCore/QFileInfo>
20#include <QtCore/QScopeGuard>
21#include <QtCore/QLoggingCategory>
22
23#include <memory>
24#include <optional>
25#include <type_traits>
26#include <variant>
27#include <vector>
28
29static Q_LOGGING_CATEGORY(creatorLog, "qt.qmldom.astcreator", QtWarningMsg);
30
31/*
32 Avoid crashing on files with JS-elements that are not implemented yet.
33 Might be removed (definition + usages) once all script elements are implemented.
34*/
35#define Q_SCRIPTELEMENT_DISABLE() \
36 do { \
37 qDebug() << "Could not construct the JS DOM at" << __FILE__ << ":" << __LINE__ \
38 << ", skipping JS elements..."; \
39 disableScriptElements(); \
40 } while (false)
41
42#define Q_SCRIPTELEMENT_EXIT_IF(check) \
43 do { \
44 if (m_enableScriptExpressions && check) { \
45 Q_SCRIPTELEMENT_DISABLE(); \
46 return; \
47 } \
48 } while (false)
49
51namespace QQmlJS {
52namespace Dom {
53
54using namespace AST;
55
56template<typename K, typename V>
58{
59 if (idx < 0)
60 return nullptr;
61 auto it = mmap.find(key);
62 auto end = mmap.end();
63 if (it == end)
64 return nullptr;
65 auto it2 = it;
66 index_type nEl = 0;
67 while (it2 != end && it2.key() == key) {
68 ++it2;
69 ++nEl;
70 }
71 if (nEl <= idx)
72 return nullptr;
73 for (index_type i = idx + 1; i < nEl; ++i)
74 ++it;
75 return &(*it);
76}
77
79{
80 static ErrorGroups errs = { { NewErrorGroup("Dom"), NewErrorGroup("QmlFile"),
81 NewErrorGroup("Parsing") } };
82 return errs;
83}
84
85static QString toString(const UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char('.'))
86{
88
89 for (const UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) {
90 if (iter != qualifiedId)
91 result += delimiter;
92
93 result += iter->name;
94 }
95
96 return result;
97}
98
100{
101 Q_ASSERT(t);
102 QString res = toString(t->typeId);
103
104 if (UiQualifiedId *arg = t->typeArgument)
105 res += u'<' + toString(arg) + u'>';
106
107 return res;
108}
109
111{
112 return combine(s1, s2);
113}
114
116{
117 return combineLocations(n->firstSourceLocation(), n->lastSourceLocation());
118}
119
120QQmlDomAstCreator::QmlStackElement &QQmlDomAstCreator::currentQmlObjectOrComponentEl(int idx)
121{
122 Q_ASSERT_X(idx < nodeStack.size() && idx >= 0, "currentQmlObjectOrComponentEl",
123 "Stack does not contain enough elements!");
124 int i = nodeStack.size() - idx;
125 while (i-- > 0) {
126 DomType k = nodeStack.at(i).item.kind;
128 return nodeStack[i];
129 }
130 Q_ASSERT_X(false, "currentQmlObjectEl", "No QmlObject or component in stack");
131 return nodeStack.last();
132}
133
134QQmlDomAstCreator::QmlStackElement &QQmlDomAstCreator::currentNodeEl(int i)
135{
136 Q_ASSERT_X(i < nodeStack.size() && i >= 0, "currentNode", "Stack does not contain element!");
137 return nodeStack[nodeStack.size() - i - 1];
138}
139
140QQmlDomAstCreator::ScriptStackElement &QQmlDomAstCreator::currentScriptNodeEl(int i)
141{
142 Q_ASSERT_X(i < scriptNodeStack.size() && i >= 0, "currentNode",
143 "Stack does not contain element!");
144 return scriptNodeStack[scriptNodeStack.size() - i - 1];
145}
146
147QQmlDomAstCreator::DomValue &QQmlDomAstCreator::currentNode(int i)
148{
149 Q_ASSERT_X(i < nodeStack.size() && i >= 0, "currentNode",
150 "Stack does not contain element!");
151 return nodeStack[nodeStack.size() - i - 1].item;
152}
153
154void QQmlDomAstCreator::removeCurrentNode(std::optional<DomType> expectedType)
155{
156 Q_ASSERT_X(!nodeStack.isEmpty(), className, "popCurrentNode() without any node");
157 if (expectedType)
158 Q_ASSERT(nodeStack.last().item.kind == *expectedType);
159 nodeStack.removeLast();
160}
161
162void QQmlDomAstCreator::removeCurrentScriptNode(std::optional<DomType> expectedType)
163{
164 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
165 Q_ASSERT_X(!scriptNodeStack.isEmpty(), className,
166 "popCurrentScriptNode() without any node");
167 if (expectedType)
168 Q_ASSERT(scriptNodeStack.last().kind == *expectedType);
169 scriptNodeStack.removeLast();
170}
171
180const ScriptElementVariant &
181QQmlDomAstCreator::finalizeScriptExpression(const ScriptElementVariant &element, Path pathFromOwner,
183{
184 auto e = element.base();
185 Q_ASSERT(e);
186
187 e->updatePathFromOwner(pathFromOwner);
188 e->createFileLocations(base);
189 return element;
190}
191
192FileLocations::Tree QQmlDomAstCreator::createMap(FileLocations::Tree base, Path p, AST::Node *n)
193{
195 if (n)
197 return res;
198}
199
200FileLocations::Tree QQmlDomAstCreator::createMap(DomType k, Path p, AST::Node *n)
201{
203 switch (k) {
205 switch (currentNode().kind) {
209 case DomType::Binding:
210 case DomType::Id:
212 break;
213 default:
214 qCWarning(domLog) << "unexpected type" << domTypeToString(currentNode().kind);
215 Q_UNREACHABLE();
216 }
217 base = currentNodeEl().fileLocations;
218 if (p.length() > 2) {
219 Path p2 = p[p.length() - 2];
220 if (p2.headKind() == Path::Kind::Field
221 && (p2.checkHeadName(Fields::children) || p2.checkHeadName(Fields::objects)
222 || p2.checkHeadName(Fields::value) || p2.checkHeadName(Fields::annotations)
223 || p2.checkHeadName(Fields::children)))
224 p = p.mid(p.length() - 2, 2);
225 else if (p.last().checkHeadName(Fields::value)
226 && p.last().headKind() == Path::Kind::Field)
227 p = p.last();
228 else {
229 qCWarning(domLog) << "unexpected path to QmlObject in createMap" << p;
230 Q_UNREACHABLE();
231 }
232 } else {
233 qCWarning(domLog) << "unexpected path to QmlObject in createMap" << p;
234 Q_UNREACHABLE();
235 }
236 break;
238 base = currentNodeEl().fileLocations;
239 break;
241 case DomType::Pragma:
242 case DomType::Import:
243 case DomType::Id:
245 base = rootMap;
246 break;
247 case DomType::Binding:
250 base = currentEl<QmlObject>().fileLocations;
251 if (p.length() > 3)
252 p = p.mid(p.length() - 3, 3);
253 break;
254
255 default:
256 qCWarning(domLog) << "Unexpected type in createMap:" << domTypeToString(k);
257 Q_UNREACHABLE();
258 break;
259 }
260 return createMap(base, p, n);
261}
262
264 : qmlFile(qmlFile),
265 qmlFilePtr(qmlFile.ownerAs<QmlFile>()),
266 rootMap(qmlFilePtr->fileLocationsTree())
267{
268}
269
271{
272 QFileInfo fInfo(qmlFile.canonicalFilePath());
273 QString componentName = fInfo.baseName();
274 QmlComponent *cPtr;
275 Path p = qmlFilePtr->addComponent(QmlComponent(componentName), AddOption::KeepExisting,
276 &cPtr);
277 MutableDomItem newC(qmlFile.item(), p);
278 Q_ASSERT_X(newC.item(), className, "could not recover component added with addComponent");
279 // QmlFile region == Component region == program span
280 // we hide the component span because the component s written after the imports
282 pushEl(p, *cPtr, program);
283 // implicit imports
284 // add implicit directory import
285 if (!fInfo.canonicalPath().isEmpty()) {
286 Import selfDirImport(QmlUri::fromDirectoryString(fInfo.canonicalPath()));
287 selfDirImport.implicit = true;
288 qmlFilePtr->addImport(selfDirImport);
289 }
290 for (Import i : qmlFile.environment().ownerAs<DomEnvironment>()->implicitImports()) {
291 i.implicit = true;
292 qmlFilePtr->addImport(i);
293 }
294 return true;
295}
296
298{
299 MutableDomItem newC = qmlFile.path(currentNodeEl().path);
300 QmlComponent &comp = current<QmlComponent>();
301 for (const Pragma &p : qmlFilePtr->pragmas()) {
302 if (p.name.compare(u"singleton", Qt::CaseInsensitive) == 0) {
303 comp.setIsSingleton(true);
304 comp.setIsCreatable(false); // correct?
305 }
306 }
307 *newC.mutableAs<QmlComponent>() = comp;
308 removeCurrentNode(DomType::QmlComponent);
309 Q_ASSERT_X(nodeStack.isEmpty(), className, "ui program did not finish node stack");
310}
311
313{
314 QStringList valueList;
315 for (auto t = el->values; t; t = t->next)
316 valueList << t->value.toString();
317
318 createMap(DomType::Pragma, qmlFilePtr->addPragma(Pragma(el->name.toString(), valueList)), el);
319 return true;
320}
321
323{
325 if (el->version && el->version->version.hasMajorVersion())
326 v.majorVersion = el->version->version.majorVersion();
327 if (el->version && el->version->version.hasMinorVersion())
328 v.minorVersion = el->version->version.minorVersion();
329 if (el->importUri != nullptr)
330 createMap(DomType::Import,
331 qmlFilePtr->addImport(Import::fromUriString(toString(el->importUri), v,
332 el->importId.toString())),
333 el);
334 else
335 createMap(DomType::Import,
336 qmlFilePtr->addImport(
337 Import::fromFileString(el->fileName.toString(), el->importId.toString())),
338 el);
339 return true;
340}
341
343{
344 switch (el->type) {
347 m.name = el->name.toString();
348 m.typeName = toString(el->memberType);
349 m.isReadonly = el->isReadonly();
350 m.access = MethodInfo::Public;
351 m.methodType = MethodInfo::Signal;
352 m.isList = el->typeModifier == QLatin1String("list");
353 MethodInfo *mPtr;
354 Path p = current<QmlObject>().addMethod(m, AddOption::KeepExisting, &mPtr);
355 pushEl(p, *mPtr, el);
356 FileLocations::addRegion(nodeStack.last().fileLocations, u"signal", el->propertyToken());
357 MethodInfo &mInfo = std::get<MethodInfo>(currentNode().value);
358 AST::UiParameterList *args = el->parameters;
359 while (args) {
361 param.name = args->name.toString();
362 param.typeName = args->type ? args->type->toString() : QString();
363 index_type idx = index_type(mInfo.parameters.size());
364 mInfo.parameters.append(param);
365 auto argLocs = FileLocations::ensure(nodeStack.last().fileLocations,
366 Path::Field(Fields::parameters).index(idx),
369 args = args->next;
370 }
371 break;
372 }
375 p.name = el->name.toString();
376 p.typeName = toString(el->memberType);
377 p.isReadonly = el->isReadonly();
378 p.isDefaultMember = el->isDefaultMember();
379 p.isRequired = el->isRequired();
380 p.isList = el->typeModifier == QLatin1String("list");
381 if (!el->typeModifier.isEmpty())
382 p.typeName = el->typeModifier.toString() + QChar(u'<') + p.typeName + QChar(u'>');
383 PropertyDefinition *pPtr;
384 Path pPathFromOwner =
385 current<QmlObject>().addPropertyDef(p, AddOption::KeepExisting, &pPtr);
386 pushEl(pPathFromOwner, *pPtr, el);
387 FileLocations::addRegion(nodeStack.last().fileLocations, u"property",
388 el->propertyToken());
389 if (p.name == u"id")
390 qmlFile.addError(astParseErrors()
391 .warning(tr("id is a special attribute, that should not be "
392 "used as property name"))
393 .withPath(currentNodeEl().path));
394 if (p.isDefaultMember)
395 FileLocations::addRegion(nodeStack.last().fileLocations, u"default",
396 el->defaultToken());
397 if (p.isRequired)
398 FileLocations::addRegion(nodeStack.last().fileLocations, u"required",
399 el->requiredToken());
400 if (el->statement) {
402 SourceLocation loc = combineLocations(el->statement);
403 QStringView code = qmlFilePtr->code();
404
405 auto script = std::make_shared<ScriptExpression>(
406 code.mid(loc.offset, loc.length), qmlFilePtr->engine(), el->statement,
408 loc);
409 Binding *bPtr;
410 Path bPathFromOwner = current<QmlObject>().addBinding(Binding(p.name, script, bType),
412 FileLocations::Tree bLoc = createMap(DomType::Binding, bPathFromOwner, el);
413 FileLocations::addRegion(bLoc, u"colon", el->colonToken);
414 FileLocations::Tree valueLoc = FileLocations::ensure(bLoc, Path::Field(Fields::value),
416 FileLocations::addRegion(valueLoc, QString(), combineLocations(el->statement));
417 // push it also: its needed in endVisit to add the scriptNode to it
418 // do not use pushEl to avoid recreating the already created "bLoc" Map
419 nodeStack.append({ bPathFromOwner, *bPtr, bLoc });
420 }
421 break;
422 }
423 }
424 return true;
425}
426
428{
429 if (auto &lastEl = currentNode(); lastEl.kind == DomType::Binding) {
430 Binding &b = std::get<Binding>(lastEl.value);
431 if (m_enableScriptExpressions && scriptNodeStack.size() != 1)
433 if (m_enableScriptExpressions) {
434 b.scriptExpressionValue()->setScriptElement(finalizeScriptExpression(
435 currentScriptNodeEl().takeVariant(), Path().field(Fields::scriptElement),
436 FileLocations::ensure(currentNodeEl().fileLocations,
437 Path().field(Fields::value))));
438 removeCurrentScriptNode({});
439 }
440
441 QmlObject &containingObject = current<QmlObject>();
442 Binding *bPtr =
443 valueFromMultimap(containingObject.m_bindings, b.name(), currentIndex());
444 Q_ASSERT(bPtr);
445 removeCurrentNode({});
446 }
447 Node::accept(el->parameters, this);
449 if ((el->binding || el->statement)
450 && nodeStack.last().item.kind == DomType::PropertyDefinition) {
451 PropertyDefinition &pDef = std::get<PropertyDefinition>(nodeStack.last().item.value);
452 if (!pDef.annotations.isEmpty()) {
453 QmlObject duplicate;
454 duplicate.setName(QLatin1String("duplicate"));
455 QmlObject &obj = current<QmlObject>();
456 auto it = obj.m_bindings.find(pDef.name);
457 if (it != obj.m_bindings.end()) {
458 for (QmlObject ann : pDef.annotations) {
459 ann.addAnnotation(duplicate);
460 it->addAnnotation(currentEl<QmlObject>()
461 .path.field(Fields::bindings)
462 .key(pDef.name)
463 .index(obj.m_bindings.values(pDef.name).size() - 1),
464 ann);
465 }
466 }
467 }
468 }
469 QmlObject &obj = current<QmlObject>();
470 QmlStackElement &sEl = nodeStack.last();
471 switch (sEl.item.kind) {
473 PropertyDefinition pDef = std::get<PropertyDefinition>(sEl.item.value);
474 PropertyDefinition *pDefPtr =
475 valueFromMultimap(obj.m_propertyDefs, pDef.name, sEl.path.last().headIndex());
476 Q_ASSERT(pDefPtr);
477 *pDefPtr = pDef;
478 } break;
479 case DomType::MethodInfo: {
480 MethodInfo m = std::get<MethodInfo>(sEl.item.value);
481 MethodInfo *mPtr = valueFromMultimap(obj.m_methods, m.name, sEl.path.last().headIndex());
482 Q_ASSERT(mPtr);
483 *mPtr = m;
484 } break;
485 default:
486 Q_UNREACHABLE();
487 }
488 removeCurrentNode({});
489}
490
492{
493 QStringView code(qmlFilePtr->code());
494 if (FunctionDeclaration *fDef = cast<FunctionDeclaration *>(el->sourceElement)) {
496 m.name = fDef->name.toString();
497 if (AST::TypeAnnotation *tAnn = fDef->typeAnnotation) {
498 if (AST::Type *t = tAnn->type)
499 m.typeName = typeToString(t);
500 }
501 m.access = MethodInfo::Public;
502 m.methodType = MethodInfo::Method;
503
504 SourceLocation bodyLoc = fDef->body
505 ? combineLocations(fDef->body)
506 : combineLocations(fDef->lbraceToken, fDef->rbraceToken);
508 QStringView preCode = code.mid(methodLoc.begin(), bodyLoc.begin() - methodLoc.begin());
509 QStringView postCode = code.mid(bodyLoc.end(), methodLoc.end() - bodyLoc.end());
510 m.body = std::make_shared<ScriptExpression>(
511 code.mid(bodyLoc.offset, bodyLoc.length), qmlFilePtr->engine(), fDef->body,
512 qmlFilePtr->astComments(), ScriptExpression::ExpressionType::FunctionBody, bodyLoc,
513 0, preCode, postCode);
514
515 if (fDef->typeAnnotation) {
516 SourceLocation typeLoc = combineLocations(fDef->typeAnnotation);
517 m.returnType = std::make_shared<ScriptExpression>(
518 code.mid(typeLoc.offset, typeLoc.length), qmlFilePtr->engine(),
519 fDef->typeAnnotation, qmlFilePtr->astComments(),
521 }
522
523 MethodInfo *mPtr;
524 Path mPathFromOwner = current<QmlObject>().addMethod(m, AddOption::KeepExisting, &mPtr);
525 pushEl(mPathFromOwner, *mPtr,
526 fDef); // add at the start and use the normal recursive visit?
527 FileLocations::Tree &fLoc = nodeStack.last().fileLocations;
528 if (fDef->identifierToken.isValid())
529 FileLocations::addRegion(fLoc, u"identifier"_s, fDef->identifierToken);
530 auto bodyTree = FileLocations::ensure(fLoc, Path::Field(Fields::body),
532 FileLocations::addRegion(bodyTree, QString(), bodyLoc);
533 if (fDef->lparenToken.length != 0)
534 FileLocations::addRegion(fLoc, u"leftParen", fDef->lparenToken);
535 if (fDef->rparenToken.length != 0)
536 FileLocations::addRegion(fLoc, u"rightParen", fDef->rparenToken);
537 if (fDef->lbraceToken.length != 0)
538 FileLocations::addRegion(fLoc, u"leftBrace", fDef->lbraceToken);
539 if (fDef->rbraceToken.length != 0)
540 FileLocations::addRegion(fLoc, u"rightBrace", fDef->rbraceToken);
542 MethodInfo &mInfo = std::get<MethodInfo>(currentNode().value);
543 AST::FormalParameterList *args = fDef->formals;
544 while (args) {
546 param.name = args->element->bindingIdentifier.toString();
547 if (AST::TypeAnnotation *tAnn = args->element->typeAnnotation) {
548 if (AST::Type *t = tAnn->type)
549 param.typeName = typeToString(t);
550 }
551 if (args->element->initializer) {
552 SourceLocation loc = combineLocations(args->element->initializer);
553 auto script = std::make_shared<ScriptExpression>(
554 code.mid(loc.offset, loc.length), qmlFilePtr->engine(),
555 args->element->initializer, qmlFilePtr->astComments(),
557 param.defaultValue = script;
558 }
559 SourceLocation parameterLoc = combineLocations(args->element);
560 param.value = std::make_shared<ScriptExpression>(
561 code.mid(parameterLoc.offset, parameterLoc.length), qmlFilePtr->engine(),
562 args->element, qmlFilePtr->astComments(),
564
565 index_type idx = index_type(mInfo.parameters.size());
566 mInfo.parameters.append(param);
567 auto argLocs = FileLocations::ensure(nodeStack.last().fileLocations,
568 Path::Field(Fields::parameters).index(idx),
571 args = args->next;
572 }
573 return true;
574 } else {
575 qCWarning(creatorLog) << "unhandled source el:" << static_cast<AST::Node *>(el);
576 Q_UNREACHABLE();
577 }
578 return true;
579}
580
582{
583 if (auto data = variant.data()) {
584 if (auto genericElement =
585 std::get_if<std::shared_ptr<ScriptElements::GenericScriptElement>>(&*data)) {
586 (*genericElement)->setKind(DomType::ScriptFormalParameter);
587 }
588 }
589}
590
592{
593 MethodInfo &m = std::get<MethodInfo>(currentNode().value);
594 if (FunctionDeclaration *fDef = cast<FunctionDeclaration *>(el->sourceElement)) {
595
596 const FileLocations::Tree bodyTree =
597 FileLocations::ensure(currentNodeEl().fileLocations, Path().field(Fields::body));
598 const Path bodyPath = Path().field(Fields::scriptElement);
599
600 if (fDef->body) {
601 if (m_enableScriptExpressions && scriptNodeStack.isEmpty())
603 if (m_enableScriptExpressions) {
604 if (currentScriptNodeEl().isList()) {
605 // It is more intuitive to have functions with a block as a body instead of a
606 // list.
607 auto body = makeScriptElement<ScriptElements::BlockStatement>(fDef->body);
608 body->setStatements(currentScriptNodeEl().takeList());
609 if (auto semanticScope = body->statements().semanticScope())
610 body->setSemanticScope(*semanticScope);
611 m.body->setScriptElement(finalizeScriptExpression(
612 ScriptElementVariant::fromElement(body), bodyPath, bodyTree));
613 } else {
614 m.body->setScriptElement(finalizeScriptExpression(
615 currentScriptNodeEl().takeVariant(), bodyPath, bodyTree));
616 }
617 removeCurrentScriptNode({});
618 }
619 }
620 if (m_enableScriptExpressions) {
621 if (fDef->typeAnnotation) {
622 auto argLoc = FileLocations::ensure(nodeStack.last().fileLocations,
623 Path().field(Fields::returnType),
625 const Path pathToReturnType = Path().field(Fields::scriptElement);
626
627 ScriptElementVariant variant = currentScriptNodeEl().takeVariant();
628 finalizeScriptExpression(variant, pathToReturnType, argLoc);
629 m.returnType->setScriptElement(variant);
630 removeCurrentScriptNode({});
631 }
632 std::vector<FormalParameterList *> reversedInitializerExpressions;
633 for (auto it = fDef->formals; it; it = it->next) {
634 reversedInitializerExpressions.push_back(it);
635 }
636 const size_t size = reversedInitializerExpressions.size();
637 for (size_t idx = size - 1; idx < size; --idx) {
638 if (m_enableScriptExpressions && scriptNodeStack.empty()) {
640 break;
641 }
642 auto argLoc = FileLocations::ensure(
643 nodeStack.last().fileLocations,
644 Path().field(Fields::parameters).index(idx).field(Fields::value),
646 const Path pathToArgument = Path().field(Fields::scriptElement);
647
648 ScriptElementVariant variant = currentScriptNodeEl().takeVariant();
650 finalizeScriptExpression(variant, pathToArgument, argLoc);
651 m.parameters[idx].value->setScriptElement(variant);
652 removeCurrentScriptNode({});
653 }
654
655 // there should be no more uncollected script elements
656 if (m_enableScriptExpressions && !scriptNodeStack.empty()) {
658 }
659 }
660 }
661 QmlObject &obj = current<QmlObject>();
662 MethodInfo *mPtr =
663 valueFromMultimap(obj.m_methods, m.name, nodeStack.last().path.last().headIndex());
664 Q_ASSERT(mPtr);
665 *mPtr = m;
666 removeCurrentNode(DomType::MethodInfo);
667}
668
670{
671 QmlObject scope;
672 scope.setName(toString(el->qualifiedTypeNameId));
674 QmlObject *sPtr = nullptr;
675 Path sPathFromOwner;
676 if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last()) {
677 if (currentNode().kind == DomType::Binding) {
678 QList<QmlObject> *vals = std::get<Binding>(currentNode().value).arrayValue();
679 if (vals) {
680 int idx = vals->size();
681 vals->append(scope);
682 sPathFromOwner = currentNodeEl().path.field(Fields::value).index(idx);
683 sPtr = &((*vals)[idx]);
684 sPtr->updatePathFromOwner(sPathFromOwner);
685 } else {
686 Q_ASSERT_X(false, className,
687 "expected an array binding with a valid QList<QmlScope> as value");
688 }
689 } else {
690 Q_ASSERT_X(false, className, "expected an array binding as last node on the stack");
691 }
692 } else {
693 DomValue &containingObject = currentQmlObjectOrComponentEl().item;
694 switch (containingObject.kind) {
696 sPathFromOwner = std::get<QmlComponent>(containingObject.value).addObject(scope, &sPtr);
697 break;
699 sPathFromOwner = std::get<QmlObject>(containingObject.value).addChild(scope, &sPtr);
700 break;
701 default:
702 Q_UNREACHABLE();
703 }
704 }
705 Q_ASSERT_X(sPtr, className, "could not recover new scope");
706 pushEl(sPathFromOwner, *sPtr, el);
708 return true;
709}
710
712{
713 QmlObject &obj = current<QmlObject>();
714 int idx = currentIndex();
715 if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last() + 1) {
716 if (currentNode(1).kind == DomType::Binding) {
717 Binding &b = std::get<Binding>(currentNode(1).value);
718 QList<QmlObject> *vals = b.arrayValue();
719 Q_ASSERT_X(vals, className,
720 "expected an array binding with a valid QList<QmlScope> as value");
721 (*vals)[idx] = obj;
722 } else {
723 Q_ASSERT_X(false, className, "expected an array binding as last node on the stack");
724 }
725 } else {
726 DomValue &containingObject = currentNodeEl(1).item;
727 Path p = currentNodeEl().path;
728 switch (containingObject.kind) {
730 if (p[p.length() - 2] == Path::Field(Fields::objects))
731 std::get<QmlComponent>(containingObject.value).m_objects[idx] = obj;
732 else
733 Q_UNREACHABLE();
734 break;
736 if (p[p.length() - 2] == Path::Field(Fields::children))
737 std::get<QmlObject>(containingObject.value).m_children[idx] = obj;
738 else
739 Q_UNREACHABLE();
740 break;
741 default:
742 Q_UNREACHABLE();
743 }
744 }
745 removeCurrentNode(DomType::QmlObject);
746}
747
749{
752 value.setName(toString(el->qualifiedTypeNameId));
753 Binding *bPtr;
754 Path bPathFromOwner = current<QmlObject>().addBinding(
755 Binding(toString(el->qualifiedId), value, bType), AddOption::KeepExisting, &bPtr);
756 if (bPtr->name() == u"id")
757 qmlFile.addError(astParseErrors()
758 .warning(tr("id attributes should only be a lower case letter "
759 "followed by letters, numbers or underscore, "
760 "assuming they refer to an id property"))
761 .withPath(bPathFromOwner));
762 pushEl(bPathFromOwner, *bPtr, el);
763 FileLocations::addRegion(nodeStack.last().fileLocations, u"colon", el->colonToken);
765 QmlObject *objValue = bPtr->objectValue();
766 Q_ASSERT_X(objValue, className, "could not recover objectValue");
767 objValue->setName(toString(el->qualifiedTypeNameId));
768 objValue->addPrototypePath(Paths::lookupTypePath(objValue->name()));
769 pushEl(bPathFromOwner.field(Fields::value), *objValue, el->initializer);
770 return true;
771}
772
774{
775 QmlObject &objValue = current<QmlObject>();
776 QmlObject &containingObj = current<QmlObject>(1);
777 Binding &b = std::get<Binding>(currentNode(1).value);
778 QmlObject *objPtr = b.objectValue();
779 Q_ASSERT(objPtr);
780 *objPtr = objValue;
781 index_type idx = currentNodeEl(1).path.last().headIndex();
782 Binding *bPtr = valueFromMultimap(containingObj.m_bindings, b.name(), idx);
783 Q_ASSERT(bPtr);
784 *bPtr = b;
785 removeCurrentNode(DomType::QmlObject);
786 removeCurrentNode(DomType::Binding);
787}
788
790{
791 QStringView code = qmlFilePtr->code();
792 SourceLocation loc = combineLocations(el->statement);
793 auto script = std::make_shared<ScriptExpression>(
794 code.mid(loc.offset, loc.length), qmlFilePtr->engine(), el->statement,
795 qmlFilePtr->astComments(), ScriptExpression::ExpressionType::BindingExpression, loc);
796 Binding bindingV(toString(el->qualifiedId), script, BindingType::Normal);
797 Binding *bindingPtr = nullptr;
798 Id *idPtr = nullptr;
799 Path pathFromOwner;
800 if (bindingV.name() == u"id") {
801 Node *exp = script->ast();
802 if (ExpressionStatement *eStat = cast<ExpressionStatement *>(script->ast()))
803 exp = eStat->expression;
804 if (IdentifierExpression *iExp = cast<IdentifierExpression *>(exp)) {
805 QmlStackElement &containingObjectEl = currentEl<QmlObject>();
806 QmlObject &containingObject = std::get<QmlObject>(containingObjectEl.item.value);
807 QString idName = iExp->name.toString();
808 Id idVal(idName, qmlFile.canonicalPath().path(containingObject.pathFromOwner()));
809 idVal.value = script;
810 containingObject.setIdStr(idName);
811 FileLocations::addRegion(containingObjectEl.fileLocations, u"idToken",
812 combineLocations(el->qualifiedId));
813 FileLocations::addRegion(containingObjectEl.fileLocations, u"idColon", el->colonToken);
814 FileLocations::addRegion(containingObjectEl.fileLocations, u"id",
815 combineLocations(el->statement));
816 QmlComponent &comp = current<QmlComponent>();
817 pathFromOwner = comp.addId(idVal, AddOption::KeepExisting, &idPtr);
819 QStringLiteral(uR"([[:lower:]][[:lower:][:upper:]0-9_]*)")));
820 auto m = idRe.matchView(iExp->name);
821 if (!m.hasMatch()) {
822 qmlFile.addError(
824 .warning(tr("id attributes should only be a lower case letter "
825 "followed by letters, numbers or underscore, not %1")
826 .arg(iExp->name))
827 .withPath(pathFromOwner));
828 }
829 } else {
830 pathFromOwner =
831 current<QmlObject>().addBinding(bindingV, AddOption::KeepExisting, &bindingPtr);
832 Q_ASSERT_X(bindingPtr, className, "binding could not be retrieved");
833 qmlFile.addError(
835 .warning(tr("id attributes should only be a lower case letter "
836 "followed by letters, numbers or underscore, not %1 "
837 "%2, assuming they refer to a property")
838 .arg(script->code(), script->astRelocatableDump()))
839 .withPath(pathFromOwner));
840 }
841 } else {
842 pathFromOwner =
843 current<QmlObject>().addBinding(bindingV, AddOption::KeepExisting, &bindingPtr);
844 Q_ASSERT_X(bindingPtr, className, "binding could not be retrieved");
845 }
846 if (bindingPtr)
847 pushEl(pathFromOwner, *bindingPtr, el);
848 else if (idPtr)
849 pushEl(pathFromOwner, *idPtr, el);
850 else
851 Q_UNREACHABLE();
853 // avoid duplicate colon location for id?
854 FileLocations::addRegion(nodeStack.last().fileLocations, u"colon", el->colonToken);
855 return true;
856}
857
858void QQmlDomAstCreator::setScriptExpression (const std::shared_ptr<ScriptExpression>& value)
859{
860 if (m_enableScriptExpressions
861 && (scriptNodeStack.size() != 1 || currentScriptNodeEl().isList()))
863 if (m_enableScriptExpressions) {
864 FileLocations::Tree valueLoc = FileLocations::ensure(currentNodeEl().fileLocations,
865 Path().field(Fields::value));
866 value->setScriptElement(finalizeScriptExpression(currentScriptNodeEl().takeVariant(),
867 Path().field(Fields::scriptElement),
868 valueLoc));
869 removeCurrentScriptNode({});
870 }
871};
872
874{
875 DomValue &lastEl = currentNode();
876 index_type idx = currentIndex();
877 if (lastEl.kind == DomType::Binding) {
878 Binding &b = std::get<Binding>(lastEl.value);
879
880 setScriptExpression(b.scriptExpressionValue());
881
882 QmlObject &containingObject = current<QmlObject>();
883 Binding *bPtr = valueFromMultimap(containingObject.m_bindings, b.name(), idx);
884 Q_ASSERT(bPtr);
885 *bPtr = b;
886 } else if (lastEl.kind == DomType::Id) {
887 Id &id = std::get<Id>(lastEl.value);
888
889 setScriptExpression(id.value);
890
891 QmlComponent &comp = current<QmlComponent>();
892 Id *idPtr = valueFromMultimap(comp.m_ids, id.name, idx);
893 *idPtr = id;
894 } else {
895 Q_UNREACHABLE();
896 }
897
898 // there should be no more uncollected script elements
899 if (m_enableScriptExpressions && !scriptNodeStack.empty()) {
901 }
902 removeCurrentNode({});
903}
904
906{
908 Binding bindingV(toString(el->qualifiedId), value, BindingType::Normal);
909 Binding *bindingPtr;
910 Path bindingPathFromOwner =
911 current<QmlObject>().addBinding(bindingV, AddOption::KeepExisting, &bindingPtr);
912 if (bindingV.name() == u"id")
913 qmlFile.addError(
915 .error(tr("id attributes should have only simple strings as values"))
916 .withPath(bindingPathFromOwner));
917 pushEl(bindingPathFromOwner, *bindingPtr, el);
918 FileLocations::addRegion(currentNodeEl().fileLocations, u"colon", el->colonToken);
920 FileLocations::Tree arrayList =
921 createMap(currentNodeEl().fileLocations, Path::Field(Fields::value), nullptr);
922 FileLocations::addRegion(arrayList, u"leftSquareBrace", el->lbracketToken);
923 FileLocations::addRegion(arrayList, u"rightSquareBrace", el->lbracketToken);
924 arrayBindingLevels.append(nodeStack.size());
925 return true;
926}
927
929{
930 index_type idx = currentIndex();
931 Binding &b = std::get<Binding>(currentNode().value);
932 Binding *bPtr = valueFromMultimap(current<QmlObject>().m_bindings, b.name(), idx);
933 *bPtr = b;
934 arrayBindingLevels.removeLast();
935 removeCurrentNode(DomType::Binding);
936}
937
939{
940 if (!m_enableScriptExpressions)
941 return false;
942
943 auto currentList = makeScriptList(list);
944
945 for (auto it = list; it; it = it->next) {
946 Node::accept(it->expression, this);
947 if (!m_enableScriptExpressions)
948 return false;
949
950 if (scriptNodeStack.empty()) {
952 return false;
953 }
954 currentList.append(scriptNodeStack.last().takeVariant());
955 scriptNodeStack.removeLast();
956 }
957
958 pushScriptElement(currentList);
959
960 return false; // return false because we already iterated over the children using the custom
961 // iteration above
962}
963
965{
966 return false; // do not create script node for Ui stuff
967}
968
970{
971 if (!m_enableScriptExpressions)
972 return false;
973
974 auto currentList = makeScriptList(list);
975
976 for (auto it = list; it; it = it->next) {
977 if (it->elision) {
978 Node::accept(it->elision, this);
979 if (scriptNodeStack.empty()) {
981 return false;
982 }
983 currentList.append(scriptNodeStack.last().takeList());
984 scriptNodeStack.removeLast();
985 }
986 if (it->element) {
987 Node::accept(it->element, this);
988 if (scriptNodeStack.empty()) {
990 return false;
991 }
992 currentList.append(scriptNodeStack.last().takeVariant());
993 scriptNodeStack.removeLast();
994 }
995 }
996
997 pushScriptElement(currentList);
998
999 return false; // return false because we already iterated over the children using the custom
1000 // iteration above
1001}
1002
1004{
1005 if (!m_enableScriptExpressions)
1006 return false;
1007
1008 auto currentList = makeScriptList(list);
1009
1010 for (auto it = list; it; it = it->next) {
1011 if (it->property) {
1012 Node::accept(it->property, this);
1013 if (!m_enableScriptExpressions)
1014 return false;
1015 if (scriptNodeStack.empty()) {
1017 return false;
1018 }
1019 currentList.append(scriptNodeStack.last().takeVariant());
1020 scriptNodeStack.removeLast();
1021 }
1022 }
1023
1024 pushScriptElement(currentList);
1025
1026 return false; // return false because we already iterated over the children using the custom
1027 // iteration above
1028}
1029
1036ScriptElementVariant QQmlDomAstCreator::scriptElementForQualifiedId(AST::UiQualifiedId *expression)
1037{
1038 auto id = std::make_shared<ScriptElements::IdentifierExpression>(
1039 expression->firstSourceLocation(), expression->lastSourceLocation());
1040 id->setName(expression->toString());
1041
1043}
1044
1046{
1047 if (!m_enableScriptExpressions)
1048 return false;
1049
1050 return false;
1051}
1052
1054{
1055 EnumDecl eDecl;
1056 eDecl.setName(el->name.toString());
1057 EnumDecl *ePtr;
1058 Path enumPathFromOwner =
1059 current<QmlComponent>().addEnumeration(eDecl, AddOption::KeepExisting, &ePtr);
1060 pushEl(enumPathFromOwner, *ePtr, el);
1062 return true;
1063}
1064
1066{
1067 EnumDecl &e = std::get<EnumDecl>(currentNode().value);
1068 EnumDecl *ePtr =
1069 valueFromMultimap(current<QmlComponent>().m_enumerations, e.name(), currentIndex());
1070 Q_ASSERT(ePtr);
1071 *ePtr = e;
1072 removeCurrentNode(DomType::EnumDecl);
1073}
1074
1076{
1077 EnumItem it(el->member.toString(), el->value);
1078 EnumDecl &eDecl = std::get<EnumDecl>(currentNode().value);
1079 Path itPathFromDecl = eDecl.addValue(it);
1080 FileLocations::addRegion(createMap(DomType::EnumItem, itPathFromDecl, nullptr), QString(),
1081 combine(el->memberToken, el->valueToken));
1082 return true;
1083}
1084
1086{
1087 Node::accept(el->next, this); // put other enum members at the same level as this one...
1088}
1089
1091{
1092 QStringList els = current<QmlComponent>().name().split(QLatin1Char('.'));
1093 els.append(el->name.toString());
1094 QString cName = els.join(QLatin1Char('.'));
1095 QmlComponent *compPtr;
1096 Path p = qmlFilePtr->addComponent(QmlComponent(cName), AddOption::KeepExisting, &compPtr);
1097 pushEl(p, *compPtr, el);
1098 FileLocations::addRegion(nodeStack.last().fileLocations, u"component", el->componentToken);
1100 return true;
1101}
1102
1104{
1105 QmlComponent &component = std::get<QmlComponent>(currentNode().value);
1106 QStringList nameEls = component.name().split(QChar::fromLatin1('.'));
1107 QString key = nameEls.mid(1).join(QChar::fromLatin1('.'));
1108 QmlComponent *cPtr = valueFromMultimap(qmlFilePtr->m_components, key, currentIndex());
1109 Q_ASSERT(cPtr);
1110 *cPtr = component;
1111 removeCurrentNode(DomType::QmlComponent);
1112}
1113
1115{
1116 PropertyDefinition pDef;
1117 pDef.name = el->name.toString();
1118 pDef.isRequired = true;
1119 PropertyDefinition *pDefPtr;
1120 Path pathFromOwner =
1121 current<QmlObject>().addPropertyDef(pDef, AddOption::KeepExisting, &pDefPtr);
1122 createMap(DomType::PropertyDefinition, pathFromOwner, el);
1123 return false;
1124}
1125
1127{
1128 QmlObject a;
1129 a.setName(QStringLiteral(u"@") + toString(el->qualifiedTypeNameId));
1130 // add annotation prototype?
1131 DomValue &containingElement = currentNode();
1132 Path pathFromOwner;
1133 QmlObject *aPtr = nullptr;
1134 switch (containingElement.kind) {
1135 case DomType::QmlObject:
1136 pathFromOwner = std::get<QmlObject>(containingElement.value).addAnnotation(a, &aPtr);
1137 break;
1138 case DomType::Binding:
1139 pathFromOwner = std::get<Binding>(containingElement.value)
1140 .addAnnotation(currentNodeEl().path, a, &aPtr);
1141 break;
1142 case DomType::Id:
1143 pathFromOwner =
1144 std::get<Id>(containingElement.value).addAnnotation(currentNodeEl().path, a, &aPtr);
1145 break;
1147 pathFromOwner = std::get<PropertyDefinition>(containingElement.value)
1148 .addAnnotation(currentNodeEl().path, a, &aPtr);
1149 break;
1151 pathFromOwner = std::get<MethodInfo>(containingElement.value)
1152 .addAnnotation(currentNodeEl().path, a, &aPtr);
1153 break;
1154 default:
1155 qCWarning(domLog) << "Unexpected container object for annotation:"
1156 << domTypeToString(containingElement.kind);
1157 Q_UNREACHABLE();
1158 }
1159 pushEl(pathFromOwner, *aPtr, el);
1160 return true;
1161}
1162
1164{
1165 DomValue &containingElement = currentNode(1);
1166 Path pathFromOwner;
1167 QmlObject &a = std::get<QmlObject>(currentNode().value);
1168 switch (containingElement.kind) {
1169 case DomType::QmlObject:
1170 std::get<QmlObject>(containingElement.value).m_annotations[currentIndex()] = a;
1171 break;
1172 case DomType::Binding:
1173 std::get<Binding>(containingElement.value).m_annotations[currentIndex()] = a;
1174 break;
1175 case DomType::Id:
1176 std::get<Id>(containingElement.value).annotations[currentIndex()] = a;
1177 break;
1179 std::get<PropertyDefinition>(containingElement.value).annotations[currentIndex()] = a;
1180 break;
1182 std::get<MethodInfo>(containingElement.value).annotations[currentIndex()] = a;
1183 break;
1184 default:
1185 Q_UNREACHABLE();
1186 }
1187 removeCurrentNode(DomType::QmlObject);
1188}
1189
1191{
1192 qmlFile.addError(astParseErrors().error(
1193 tr("Maximum statement or expression depth exceeded in QmlDomAstCreator")));
1194}
1195
1197{
1198 if (!m_enableScriptExpressions)
1199 return false;
1200
1201 return true;
1202}
1203
1205{
1206 if (!m_enableScriptExpressions)
1207 return;
1208
1209 auto current = makeScriptList(list);
1210
1211 for (auto it = list; it; it = it->next) {
1212 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1213 current.append(scriptNodeStack.takeLast().takeVariant());
1214 }
1215
1216 current.reverse();
1217 pushScriptElement(current);
1218}
1219
1221{
1222 if (!m_enableScriptExpressions)
1223 return false;
1224
1225 return true;
1226}
1227
1229{
1230 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.size() < 2);
1231
1232 if (!m_enableScriptExpressions)
1233 return;
1234
1235 auto current = makeScriptElement<ScriptElements::BinaryExpression>(exp);
1236 current->setRight(currentScriptNodeEl().takeVariant());
1237 removeCurrentScriptNode({});
1238 current->setLeft(currentScriptNodeEl().takeVariant());
1239 removeCurrentScriptNode({});
1240
1241 pushScriptElement(current);
1242}
1243
1245{
1246 if (!m_enableScriptExpressions)
1247 return false;
1248
1249 return true;
1250}
1251
1253{
1254 if (!m_enableScriptExpressions)
1255 return;
1256
1257 auto current = makeScriptElement<ScriptElements::BlockStatement>(block);
1258
1259 if (block->statements) {
1260 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1261 current->setStatements(currentScriptNodeEl().takeList());
1262 removeCurrentScriptNode(DomType::List);
1263 }
1264
1265 pushScriptElement(current);
1266}
1267
1269{
1270 if (!m_enableScriptExpressions)
1271 return false;
1272
1273 return true;
1274}
1275
1277{
1278 if (!m_enableScriptExpressions)
1279 return;
1280
1281 auto current = makeScriptElement<ScriptElements::ForStatement>(forStatement);
1282
1283 if (forStatement->statement) {
1284 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1285 current->setBody(currentScriptNodeEl().takeVariant());
1286 removeCurrentScriptNode(std::nullopt);
1287 }
1288
1289 if (forStatement->expression) {
1290 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1291 current->setExpression(currentScriptNodeEl().takeVariant());
1292 removeCurrentScriptNode(std::nullopt);
1293 }
1294
1295 if (forStatement->condition) {
1296 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1297 current->setCondition(currentScriptNodeEl().takeVariant());
1298 removeCurrentScriptNode(std::nullopt);
1299 }
1300
1301 if (forStatement->declarations) {
1302 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1303 auto variableDeclaration = makeGenericScriptElement(forStatement->declarations,
1305
1306 ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
1307 list.replaceKindForGenericChildren(DomType::ScriptPattern,
1309 variableDeclaration->insertChild(Fields::declarations, std::move(list));
1310 removeCurrentScriptNode({});
1311
1312 current->setDeclarations(ScriptElementVariant::fromElement(variableDeclaration));
1313 }
1314
1315 if (forStatement->initialiser) {
1316 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1317 current->setInitializer(currentScriptNodeEl().takeVariant());
1318 removeCurrentScriptNode(std::nullopt);
1319 }
1320 pushScriptElement(current);
1321}
1322
1324{
1325 if (!m_enableScriptExpressions)
1326 return false;
1327
1328 auto current = makeScriptElement<ScriptElements::IdentifierExpression>(expression);
1329 current->setName(expression->name);
1330 pushScriptElement(current);
1331 return true;
1332}
1333
1335{
1336 if (!m_enableScriptExpressions)
1337 return false;
1338
1339 auto current = makeScriptElement<ScriptElements::Literal>(expression);
1340 current->setLiteralValue(expression->value);
1341 pushScriptElement(current);
1342 return true;
1343}
1344
1346{
1347 if (!m_enableScriptExpressions)
1348 return false;
1349
1350 pushScriptElement(makeStringLiteral(expression->value, expression));
1351 return true;
1352}
1353
1355{
1356 if (!m_enableScriptExpressions)
1357 return false;
1358
1359 auto current = makeScriptElement<ScriptElements::Literal>(expression);
1360 current->setLiteralValue(nullptr);
1361 pushScriptElement(current);
1362 return true;
1363}
1364
1366{
1367 if (!m_enableScriptExpressions)
1368 return false;
1369
1370 auto current = makeScriptElement<ScriptElements::Literal>(expression);
1371 current->setLiteralValue(true);
1372 pushScriptElement(current);
1373 return true;
1374}
1375
1377{
1378 if (!m_enableScriptExpressions)
1379 return false;
1380
1381 auto current = makeScriptElement<ScriptElements::Literal>(expression);
1382 current->setLiteralValue(false);
1383 pushScriptElement(current);
1384 return true;
1385}
1386
1388{
1389 if (!m_enableScriptExpressions)
1390 return false;
1391
1392 auto current = makeScriptElement<ScriptElements::IdentifierExpression>(expression);
1393 current->setName(expression->id);
1394 pushScriptElement(current);
1395 return true;
1396}
1397
1399{
1400 if (!m_enableScriptExpressions)
1401 return false;
1402
1403 pushScriptElement(makeStringLiteral(expression->id, expression));
1404 return true;
1405}
1406
1408{
1409 if (!m_enableScriptExpressions)
1410 return false;
1411
1412 // do nothing: the work is done in (end)visit(AST::Type*).
1413 return true;
1414}
1415
1417{
1418 if (!m_enableScriptExpressions)
1419 return false;
1420
1421 auto current = makeScriptElement<ScriptElements::Literal>(expression);
1422 current->setLiteralValue(expression->id);
1423 pushScriptElement(current);
1424 return true;
1425}
1426
1428{
1429 if (!m_enableScriptExpressions)
1430 return false;
1431
1432 // nothing to do, just forward the underlying expression without changing/wrapping it
1433 return true;
1434}
1435
1437{
1438 if (!m_enableScriptExpressions)
1439 return false;
1440
1441 auto currentList = makeScriptList(list);
1442
1443 for (auto it = list; it; it = it->next) {
1444 if (it->declaration) {
1445 Node::accept(it->declaration, this);
1446 if (!m_enableScriptExpressions)
1447 return false;
1448 if (scriptNodeStack.empty()) {
1450 return false;
1451 }
1452 currentList.append(scriptNodeStack.last().takeVariant());
1453 scriptNodeStack.removeLast();
1454 }
1455 }
1456 pushScriptElement(currentList);
1457
1458 return false; // return false because we already iterated over the children using the custom
1459 // iteration above
1460}
1461
1463{
1464 if (!m_enableScriptExpressions)
1465 return false;
1466
1467 auto currentList = makeScriptList(list);
1468
1469 for (auto it = list; it; it = it->next) {
1470 auto current = makeGenericScriptElement(it->commaToken, DomType::ScriptElision);
1471 currentList.append(ScriptElementVariant::fromElement(current));
1472 }
1473 pushScriptElement(currentList);
1474
1475 return false; // return false because we already iterated over the children using the custom
1476 // iteration above
1477}
1478
1480{
1481 if (!m_enableScriptExpressions)
1482 return false;
1483
1484 return true;
1485}
1486
1494 const std::shared_ptr<ScriptElements::GenericScriptElement> &current)
1495{
1496 if (pe->identifierToken.isValid() && !pe->bindingIdentifier.isEmpty()) {
1497 auto identifier =
1498 std::make_shared<ScriptElements::IdentifierExpression>(pe->identifierToken);
1499 identifier->setName(pe->bindingIdentifier);
1500 current->insertChild(Fields::identifier, ScriptElementVariant::fromElement(identifier));
1501 }
1502 if (pe->initializer) {
1503 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1504 current->insertChild(Fields::initializer, scriptNodeStack.last().takeVariant());
1505 scriptNodeStack.removeLast();
1506 }
1507 if (pe->typeAnnotation) {
1508 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1509 current->insertChild(Fields::type, scriptNodeStack.last().takeVariant());
1510 scriptNodeStack.removeLast();
1511 }
1512 if (pe->bindingTarget) {
1513 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1514 current->insertChild(Fields::bindingElement, scriptNodeStack.last().takeVariant());
1515 scriptNodeStack.removeLast();
1516 }
1517}
1518
1520{
1521 if (!m_enableScriptExpressions)
1522 return;
1523
1524 auto element = makeGenericScriptElement(pe, DomType::ScriptPattern);
1525 endVisitHelper(pe, element);
1526 // check if helper disabled scriptexpressions
1527 if (!m_enableScriptExpressions)
1528 return;
1529
1530 pushScriptElement(element);
1531}
1532
1534{
1535 if (!m_enableScriptExpressions)
1536 return false;
1537
1538 return true;
1539}
1540
1542{
1543 if (!m_enableScriptExpressions)
1544 return;
1545
1546 auto current = makeScriptElement<ScriptElements::IfStatement>(ifStatement);
1547
1548 if (ifStatement->ko) {
1549 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1550 current->setAlternative(scriptNodeStack.last().takeVariant());
1551 scriptNodeStack.removeLast();
1552 }
1553
1554 if (ifStatement->ok) {
1555 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1556 current->setConsequence(scriptNodeStack.last().takeVariant());
1557 scriptNodeStack.removeLast();
1558 }
1559 if (ifStatement->expression) {
1560 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1561 current->setCondition(scriptNodeStack.last().takeVariant());
1562 scriptNodeStack.removeLast();
1563 }
1564
1565 pushScriptElement(current);
1566}
1567
1569{
1570 if (!m_enableScriptExpressions)
1571 return false;
1572
1573 return true;
1574}
1575
1577{
1578 if (!m_enableScriptExpressions)
1579 return;
1580
1581 auto current = makeScriptElement<ScriptElements::ReturnStatement>(returnStatement);
1582
1583 if (returnStatement->expression) {
1584 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1585 current->setExpression(currentScriptNodeEl().takeVariant());
1586 removeCurrentScriptNode({});
1587 }
1588
1589 pushScriptElement(current);
1590}
1591
1593{
1594 if (!m_enableScriptExpressions)
1595 return false;
1596
1597 return true;
1598}
1599
1601{
1602 if (!m_enableScriptExpressions)
1603 return;
1604
1605 auto current = makeScriptElement<ScriptElements::BinaryExpression>(expression);
1607
1608 if (expression->base) {
1609 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1610 current->setLeft(currentScriptNodeEl().takeVariant());
1611 removeCurrentScriptNode({});
1612 }
1613
1614 if (!expression->name.empty()) {
1615 auto scriptIdentifier =
1616 std::make_shared<ScriptElements::IdentifierExpression>(expression->identifierToken);
1617 scriptIdentifier->setName(expression->name);
1618 current->setRight(ScriptElementVariant::fromElement(scriptIdentifier));
1619 }
1620
1621 pushScriptElement(current);
1622}
1623
1625{
1626 if (!m_enableScriptExpressions)
1627 return false;
1628
1629 return true;
1630}
1631
1633{
1634 if (!m_enableScriptExpressions)
1635 return;
1636
1637 auto current = makeScriptElement<ScriptElements::BinaryExpression>(expression);
1639
1640 if (expression->expression) {
1641 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1642 // if scriptNodeStack.last() is fieldmember expression, add expression to it instead of
1643 // creating new one
1644 current->setRight(currentScriptNodeEl().takeVariant());
1645 removeCurrentScriptNode({});
1646 }
1647
1648 if (expression->base) {
1649 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1650 current->setLeft(currentScriptNodeEl().takeVariant());
1651 removeCurrentScriptNode({});
1652 }
1653
1654 pushScriptElement(current);
1655}
1656
1658{
1659 if (!m_enableScriptExpressions)
1660 return false;
1661
1662 return true;
1663}
1664
1666{
1667 if (!m_enableScriptExpressions)
1668 return;
1669
1670 auto current = makeGenericScriptElement(exp, DomType::ScriptCallExpression);
1671
1672 if (exp->arguments) {
1673 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1674 current->insertChild(Fields::arguments, currentScriptNodeEl().takeList());
1675 removeCurrentScriptNode({});
1676 } else {
1677 // insert empty list
1678 current->insertChild(Fields::arguments,
1680 }
1681
1682 if (exp->base) {
1683 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1684 current->insertChild(Fields::callee, currentScriptNodeEl().takeVariant());
1685 removeCurrentScriptNode({});
1686 }
1687
1688 pushScriptElement(current);
1689}
1690
1692{
1693 if (!m_enableScriptExpressions)
1694 return false;
1695
1696 return true;
1697}
1698
1700{
1701 if (!m_enableScriptExpressions)
1702 return;
1703
1704 auto current = makeGenericScriptElement(exp, DomType::ScriptArray);
1705
1706 if (exp->elements) {
1707 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1708 ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
1709 list.replaceKindForGenericChildren(DomType::ScriptPattern, DomType::ScriptArrayEntry);
1710 current->insertChild(Fields::elements, std::move(list));
1711
1712 removeCurrentScriptNode({});
1713 } else {
1714 // insert empty list
1715 current->insertChild(Fields::elements,
1717 }
1718
1719 pushScriptElement(current);
1720}
1721
1723{
1724 if (!m_enableScriptExpressions)
1725 return false;
1726
1727 return true;
1728}
1729
1731{
1732 if (!m_enableScriptExpressions)
1733 return;
1734
1735 auto current = makeGenericScriptElement(exp, DomType::ScriptObject);
1736
1737 if (exp->properties) {
1738 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1739 current->insertChild(Fields::properties, currentScriptNodeEl().takeList());
1740 removeCurrentScriptNode({});
1741 } else {
1742 // insert empty list
1743 current->insertChild(Fields::properties,
1745 }
1746
1747 pushScriptElement(current);
1748}
1749
1751{
1752 if (!m_enableScriptExpressions)
1753 return false;
1754
1755 return true;
1756}
1757
1759{
1760 if (!m_enableScriptExpressions)
1761 return;
1762
1763 auto current = makeGenericScriptElement(exp, DomType::ScriptProperty);
1764
1765 // handle the stuff from PatternProperty's base class PatternElement
1766 endVisitHelper(static_cast<PatternElement *>(exp), current);
1767
1768 // check if helper disabled scriptexpressions
1769 if (!m_enableScriptExpressions)
1770 return;
1771
1772 if (exp->name) {
1773 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1774 current->insertChild(Fields::name, currentScriptNodeEl().takeVariant());
1775 removeCurrentScriptNode({});
1776 }
1777
1778 pushScriptElement(current);
1779}
1780
1782{
1783 if (!m_enableScriptExpressions)
1784 return false;
1785
1786 return true;
1787}
1788
1790{
1791 if (!m_enableScriptExpressions)
1792 return;
1793
1794 auto current = makeGenericScriptElement(statement, DomType::ScriptVariableDeclaration);
1795
1796 if (statement->declarations) {
1797 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1798
1799 ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
1800 list.replaceKindForGenericChildren(DomType::ScriptPattern,
1802 current->insertChild(Fields::declarations, std::move(list));
1803
1804 removeCurrentScriptNode({});
1805 }
1806
1807 pushScriptElement(current);
1808}
1809
1811{
1812 if (!m_enableScriptExpressions)
1813 return false;
1814
1815 return true;
1816}
1817
1819{
1820 if (!m_enableScriptExpressions)
1821 return;
1822
1823 auto current = makeGenericScriptElement(exp, DomType::ScriptType);
1824
1825 if (exp->typeArgument) {
1826 auto currentChild = scriptElementForQualifiedId(exp->typeArgument);
1827 current->insertChild(Fields::typeArgument, currentChild);
1828 }
1829
1830 if (exp->typeId) {
1831 auto currentChild = scriptElementForQualifiedId(exp->typeId);
1832 current->insertChild(Fields::typeName, currentChild);
1833 }
1834
1835 pushScriptElement(current);
1836}
1837
1839{
1840 if (!m_enableScriptExpressions)
1841 return false;
1842
1843 return true;
1844}
1845
1847{
1848 if (!m_enableScriptExpressions)
1849 return;
1850
1851 auto current = makeGenericScriptElement(exp, DomType::ScriptDefaultClause);
1852
1853 if (exp->statements) {
1854 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1855 current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
1856 removeCurrentScriptNode({});
1857 }
1858
1859 pushScriptElement(current);
1860}
1861
1863{
1864 if (!m_enableScriptExpressions)
1865 return false;
1866
1867 return true;
1868}
1869
1871{
1872 if (!m_enableScriptExpressions)
1873 return;
1874
1875 auto current = makeGenericScriptElement(exp, DomType::ScriptCaseClause);
1876
1877 if (exp->statements) {
1878 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1879 current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
1880 removeCurrentScriptNode({});
1881 }
1882
1883 if (exp->expression) {
1884 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1885 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
1886 removeCurrentScriptNode({});
1887 }
1888
1889 pushScriptElement(current);
1890}
1891
1893{
1894 if (!m_enableScriptExpressions)
1895 return false;
1896
1897 return true;
1898}
1899
1901{
1902 if (!m_enableScriptExpressions)
1903 return;
1904
1905 auto current = makeScriptList(list);
1906
1907 for (auto it = list; it; it = it->next) {
1908 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1909 current.append(scriptNodeStack.takeLast().takeVariant());
1910 }
1911
1912 current.reverse();
1913 pushScriptElement(current);
1914}
1915
1917{
1918 if (!m_enableScriptExpressions)
1919 return false;
1920
1921 return true;
1922}
1923
1925{
1926 if (!m_enableScriptExpressions)
1927 return;
1928
1929 auto current = makeGenericScriptElement(exp, DomType::ScriptCaseBlock);
1930
1931 if (exp->moreClauses) {
1932 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1933 current->insertChild(Fields::caseClauses, currentScriptNodeEl().takeList());
1934 removeCurrentScriptNode({});
1935 }
1936
1937 if (exp->defaultClause) {
1938 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1939 current->insertChild(Fields::defaultClause, currentScriptNodeEl().takeVariant());
1940 removeCurrentScriptNode({});
1941 }
1942
1943 if (exp->clauses) {
1944 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1945 current->insertChild(Fields::caseClauses, currentScriptNodeEl().takeList());
1946 removeCurrentScriptNode({});
1947 }
1948 pushScriptElement(current);
1949}
1950
1952{
1953 if (!m_enableScriptExpressions)
1954 return false;
1955
1956 return true;
1957}
1958
1960{
1961 if (!m_enableScriptExpressions)
1962 return;
1963
1964 auto current = makeGenericScriptElement(exp, DomType::ScriptSwitchStatement);
1965
1966 if (exp->block) {
1967 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1968 current->insertChild(Fields::caseBlock, currentScriptNodeEl().takeVariant());
1969 removeCurrentScriptNode({});
1970 }
1971 if (exp->expression) {
1972 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1973 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
1974 removeCurrentScriptNode({});
1975 }
1976
1977 pushScriptElement(current);
1978}
1979
1981{
1982 if (!m_enableScriptExpressions)
1983 return false;
1984
1985 return true;
1986}
1987
1989{
1990 if (!m_enableScriptExpressions)
1991 return;
1992
1993 auto current = makeGenericScriptElement(exp, DomType::ScriptWhileStatement);
1994
1995 if (exp->statement) {
1996 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
1997 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
1998 removeCurrentScriptNode({});
1999 }
2000
2001 if (exp->expression) {
2002 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
2003 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2004 removeCurrentScriptNode({});
2005 }
2006
2007 pushScriptElement(current);
2008}
2009
2011{
2012 if (!m_enableScriptExpressions)
2013 return false;
2014
2015 return true;
2016}
2017
2019{
2020 if (!m_enableScriptExpressions)
2021 return;
2022
2023 auto current = makeGenericScriptElement(exp, DomType::ScriptDoWhileStatement);
2024
2025 if (exp->expression) {
2026 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
2027 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2028 removeCurrentScriptNode({});
2029 }
2030
2031 if (exp->statement) {
2032 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
2033 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2034 removeCurrentScriptNode({});
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::ScriptForEachStatement);
2054
2055 if (exp->statement) {
2056 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
2057 current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
2058 removeCurrentScriptNode({});
2059 }
2060 if (exp->expression) {
2061 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
2062 current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
2063 removeCurrentScriptNode({});
2064 }
2065
2066 if (exp->lhs) {
2067 Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
2068 current->insertChild(Fields::bindingElement, currentScriptNodeEl().takeVariant());
2069 removeCurrentScriptNode({});
2070 }
2071
2072 pushScriptElement(current);
2073}
2074
2076{
2077 auto top = qmlFile.top();
2078 if (!top) {
2079 return {};
2080 }
2081 auto domEnvironment = top.as<DomEnvironment>();
2082 if (!domEnvironment) {
2083 return {};
2084 }
2085 return domEnvironment;
2086}
2087
2089{
2090 if (auto env = environmentFrom(qmlFile))
2091 return env->loadPaths();
2092
2093 return {};
2094}
2095
2097{
2098 if (auto env = environmentFrom(qmlFile))
2099 return env->qmldirFiles();
2100
2101 return {};
2102}
2103
2105 QQmlJSLogger *logger)
2106 : m_root(QQmlJSScope::create()),
2107 m_logger(logger),
2108 m_importer(importPathsFrom(qmlFile), nullptr, true),
2109 m_implicitImportDirectory(QQmlJSImportVisitor::implicitImportDirectory(
2110 m_logger->fileName(), m_importer.resourceFileMapper())),
2111 m_scopeCreator(m_root, &m_importer, m_logger, m_implicitImportDirectory,
2112 qmldirFilesFrom(qmlFile)),
2113 m_domCreator(qmlFile)
2114{
2115}
2116
2117#define X(name) \
2118 bool QQmlDomAstCreatorWithQQmlJSScope::visit(name *node) \
2119 { \
2120 return visitT(node); \
2121 } \
2122 void QQmlDomAstCreatorWithQQmlJSScope::endVisit(name *node) \
2123 { \
2124 endVisitT(node); \
2125 }
2127#undef X
2128
2129 void
2130 QQmlDomAstCreatorWithQQmlJSScope::setScopeInDomAfterEndvisit()
2131{
2132 QQmlJSScope::Ptr scope = m_scopeCreator.m_currentScope;
2133 if (!m_domCreator.scriptNodeStack.isEmpty()) {
2134 auto topOfStack = m_domCreator.currentScriptNodeEl();
2135 switch (topOfStack.kind) {
2141 case DomType::List:
2142 m_domCreator.currentScriptNodeEl().setSemanticScope(scope);
2143 break;
2144 // TODO: find which script elements also have a scope and implement them here
2145 default:
2146 break;
2147 };
2148 } else if (!m_domCreator.nodeStack.isEmpty()) {
2149 std::visit(
2150 [&scope](auto &&e) {
2151 using U = std::remove_cv_t<std::remove_reference_t<decltype(e)>>;
2152 // TODO: find which dom elements also have a scope and implement them here
2153 if constexpr (std::is_same_v<U, QmlObject>) {
2154 e.setSemanticScope(scope);
2155 } else if constexpr (std::is_same_v<U, QmlComponent>) {
2156 e.setSemanticScope(scope);
2157 } else if constexpr (std::is_same_v<U, MethodInfo>) {
2158 if (e.body) {
2159 if (auto scriptElement = e.body->scriptElement())
2160 scriptElement.base()->setSemanticScope(scope);
2161 }
2162 e.setSemanticScope(scope);
2163 }
2164 },
2165 m_domCreator.currentNodeEl().item.value);
2166 }
2167}
2168
2169void QQmlDomAstCreatorWithQQmlJSScope::setScopeInDomBeforeEndvisit()
2170{
2171 QQmlJSScope::Ptr scope = m_scopeCreator.m_currentScope;
2172
2173 auto visitPropertyDefinition = [&scope](auto &&e) {
2174 using U = std::remove_cv_t<std::remove_reference_t<decltype(e)>>;
2175 if constexpr (std::is_same_v<U, PropertyDefinition>) {
2176 e.scope = scope;
2177 Q_ASSERT(e.scope);
2178 }
2179 };
2180
2181 // depending whether the property definition has a binding, the property definition might be
2182 // either at the last position in the stack or at the position before the last position.
2183 if (m_domCreator.nodeStack.size() > 1
2184 && m_domCreator.nodeStack.last().item.kind == DomType::Binding) {
2185 std::visit([&visitPropertyDefinition](auto &&e) { visitPropertyDefinition(e); },
2186 m_domCreator.currentNodeEl(1).item.value);
2187 }
2188 if (m_domCreator.nodeStack.size() > 0) {
2189 std::visit(
2190 [&visitPropertyDefinition](auto &&e) {
2191 visitPropertyDefinition(e);
2192 // TODO: find which dom elements also have a scope and implement them here
2193 },
2194 m_domCreator.currentNodeEl().item.value);
2195 }
2196}
2197
2199{
2200}
2201
2202void createDom(MutableDomItem qmlFile, DomCreationOptions options)
2203{
2204 if (std::shared_ptr<QmlFile> qmlFilePtr = qmlFile.ownerAs<QmlFile>()) {
2205 QQmlJSLogger logger; // TODO
2206 // the logger filename is used to populate the QQmlJSScope filepath.
2207 logger.setFileName(qmlFile.canonicalFilePath());
2208 if (options.testFlag(DomCreationOption::WithSemanticAnalysis)) {
2209 auto v = std::make_unique<QQmlDomAstCreatorWithQQmlJSScope>(qmlFile, &logger);
2210 v->enableScriptExpressions(options.testFlag(DomCreationOption::WithScriptExpressions));
2211
2212 AST::Node::accept(qmlFilePtr->ast(), v.get());
2214
2215 auto typeResolver = std::make_shared<QQmlJSTypeResolver>(&v->importer());
2216 typeResolver->init(&v->scopeCreator(), nullptr);
2217 qmlFilePtr->setTypeResolver(typeResolver);
2218 } else {
2219 auto v = std::make_unique<QQmlDomAstCreator>(qmlFile);
2220 v->enableScriptExpressions(options.testFlag(DomCreationOption::WithScriptExpressions));
2221
2222 AST::Node::accept(qmlFilePtr->ast(), v.get());
2224 }
2225 } else {
2226 qCWarning(creatorLog) << "createDom called on non qmlFile";
2227 }
2228}
2229
2230} // end namespace Dom
2231} // end namespace QQmlJS
2232
2233#undef Q_SCRIPTELEMENT_DISABLE
2234#undef Q_SCRIPTELEMENT_EXIT_IF
2235
\inmodule QtCore
Definition qchar.h:48
static constexpr QChar fromLatin1(char c) noexcept
Converts the Latin-1 character c to its equivalent QChar.
Definition qchar.h:461
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
QString baseName() const
Returns the base name of the file without the path.
QString canonicalPath() const
Returns the file's path canonical path (excluding the file name), i.e.
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
T & last()
Definition qlist.h:631
bool empty() const noexcept
Definition qlist.h:682
value_type takeLast()
Definition qlist.h:550
void removeLast() noexcept
Definition qlist.h:808
void append(parameter_type t)
Definition qlist.h:441
iterator end()
Definition qmap.h:1300
iterator find(const Key &key)
Definition qmap.h:1344
QQmlJSScope::Ptr m_currentScope
void setFileName(const QString &fileName)
Tracks the types for the QmlCompiler.
SourceLocation rbracketToken
PatternElementList * elements
SourceLocation lbracketToken
StatementList * statements
CaseClauses * moreClauses
DefaultClause * defaultClause
ExpressionNode * expression
StatementList * statements
ExpressionNode * expression
VariableDeclarationList * declarations
ExpressionNode * initialiser
ExpressionNode * condition
ExpressionNode * expression
void accept(BaseVisitor *visitor)
PatternPropertyList * properties
SourceLocation identifierToken
ExpressionNode * initializer
TypeAnnotation * typeAnnotation
ExpressionNode * bindingTarget
UiQualifiedId * typeArgument
UiQualifiedId * typeId
SourceLocation firstSourceLocation() const override
SourceLocation lastSourceLocation() const override
VariableDeclarationList * declarations
ExpressionNode * expression
static void collectComments(MutableDomItem &item)
QmlObject const * objectValue() const
void setIsSingleton(bool isSingleton)
void setIsCreatable(bool isCreatable)
Path pathFromOwner(DomItem &self) const override
Represents a consistent set of types organized in modules, it is the top level of the DOM.
Path addValue(EnumItem value)
void setName(QString name)
Represents a set of tags grouping a set of related error messages.
static void addRegion(Tree fLoc, QString locName, SourceLocation loc)
static Tree ensure(Tree base, Path basePath, AttachedInfo::PathType pType=AttachedInfo::PathType::Relative)
std::shared_ptr< AttachedInfoT< FileLocations > > Tree
std::shared_ptr< ScriptExpression > value
static Import fromUriString(QString importStr, Version v=Version(), QString importId=QString(), ErrorHandler handler=nullptr)
static Import fromFileString(QString importStr, QString importId=QString(), ErrorHandler handler=nullptr)
QList< MethodParameter > parameters
std::shared_ptr< T > ownerAs()
MutableDomItem path(const Path &p)
void addError(ErrorMessage msg)
Path path(Path toAdd, bool avoidToAddAsBase=false) const
Path field(QString name) const
static Path Field(QStringView s=u"")
Path index(index_type i) const
virtual QQmlJSASTClassListToVisit void throwRecursionDepthError() override
QQmlDomAstCreatorWithQQmlJSScope(MutableDomItem &qmlFile, QQmlJSLogger *logger)
void endVisit(AST::UiProgram *) override
void endVisitHelper(AST::PatternElement *pe, const std::shared_ptr< ScriptElements::GenericScriptElement > &element)
QQmlDomAstCreator(MutableDomItem qmlFile)
bool visit(AST::UiProgram *program) override
void loadAnnotations(AST::UiObjectMember *el)
Path addId(const Id &id, AddOption option=AddOption::Overwrite, Id **idPtr=nullptr)
void setName(QString name)
Path addPrototypePath(Path prototypePath)
void updatePathFromOwner(Path newPath) override
static QmlUri fromDirectoryString(const QString &importStr)
Use this to contain any script element.
static ScriptElementVariant fromElement(T element)
static constexpr qint32 Latest
\inmodule QtCore \reentrant
QRegularExpressionMatch matchView(QStringView subjectView, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
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:76
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:1014
constexpr bool empty() const noexcept
Returns whether this string view is empty - that is, whether {size() == 0}.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QString last(qsizetype n) const
Definition qstring.h:339
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
void * data()
Returns a pointer to the contained object as a generic void* that can be written to.
QPixmap p2
double e
QSet< QString >::iterator it
Path lookupTypePath(QString name)
void createDom(MutableDomItem qmlFile, DomCreationOptions options=None)
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)
qint64 index_type
static QString toString(const UiQualifiedId *qualifiedId, QChar delimiter=QLatin1Char('.'))
static QStringList importPathsFrom(MutableDomItem &qmlFile)
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,...)
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
GLuint program
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum const GLint * param
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
#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 tr(X)
QList< int > list
[14]
QObject::connect nullptr
QVariant variant
[1]
view create()
QJSValueList args
QStringView el
\inmodule QtCore \reentrant
Definition qchar.h:17