Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmldomelements.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// Suppress GCC 11 warning about maybe-uninitialized copy of
4// another Data. We're not sure if the compiler is actually right,
5// but in this type of warning, it often isn't.
6//#if defined(Q_CC_GNU) && Q_CC_GNU >= 1100
7//QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
8#include "qqmldompath_p.h"
9#if defined(__GNUC__) && __GNUC__ >= 11
10# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
11#endif
12
13#include "qqmldomelements_p.h"
14#include "qqmldomcomments_p.h"
15#include "qqmldomastdumper_p.h"
16#include "qqmldommock_p.h"
18#include "qqmldomoutwriter_p.h"
19#include "qqmldomlinewriter_p.h"
20#include "qqmldomtop_p.h"
22
23#include <QtQml/private/qqmljslexer_p.h>
24#include <QtQml/private/qqmljsparser_p.h>
25#include <QtQml/private/qqmljsengine_p.h>
26#include <QtQml/private/qqmljsastvisitor_p.h>
27#include <QtQml/private/qqmljsast_p.h>
28
29#include <QtCore/QScopeGuard>
30#include <QtCore/QRegularExpression>
31#include <QtCore/QDir>
32#include <QtCore/QBasicMutex>
33#include <QtCore/QUrl>
34
35#include <optional>
36#include <limits>
37
39
40using namespace Qt::StringLiterals;
41
42namespace QQmlJS {
43namespace Dom {
44
45namespace Paths {
46
47Path moduleIndexPath(QString uri, int majorVersion, ErrorHandler errorHandler)
48{
49 QString version = QString::number(majorVersion);
50 if (majorVersion == Version::Latest)
51 version = QLatin1String("Latest");
52 else if (majorVersion == Version::Undefined)
53 version = QString();
54 QRegularExpression moduleRe(QLatin1String(R"(\A\w+(?:\.\w+)*\Z)"));
55 auto m = moduleRe.match(uri);
56 if (!m.isValid())
58 .error(Path::tr("Invalid module name in import %1").arg(uri))
59 .handle(errorHandler);
60 return Path::Root(PathRoot::Env).field(Fields::moduleIndexWithUri).key(uri).key(version);
61}
62
64{
66 .field(Fields::moduleIndexWithUri)
67 .key(uri)
68 .key(version.majorSymbolicString())
69 .field(Fields::moduleScope)
70 .key(version.minorString());
71}
72
73Path moduleScopePath(QString uri, QString version, ErrorHandler errorHandler)
74{
75 Version v = Version::fromString(version);
76 if (!version.isEmpty() && !(v.isValid() || v.isLatest()))
77 Path::myErrors().error(Path::tr("Invalid Version %1").arg(version)).handle(errorHandler);
78 return moduleScopePath(uri, v, errorHandler);
79}
80
81} // end namespace Paths
82
84{
85 static ErrorGroups res = { { DomItem::domErrorGroup, NewErrorGroup("Parsing") } };
86 return res;
87}
88
90{
91 bool cont = true;
92 cont = cont && self.dvWrapField(visitor, Fields::comments, m_comments);
93 return cont;
94}
95
97{
99 updatePathFromOwnerMultiMap(m_enumerations, newPath.field(Fields::enumerations));
100 updatePathFromOwnerQList(m_objects, newPath.field(Fields::objects));
101}
102
104
105Component::Component(Path pathFromOwner) : CommentableDomElement(pathFromOwner) { }
106
108{
109 bool cont = CommentableDomElement::iterateDirectSubpaths(self, visitor);
110 cont = cont && self.dvValueField(visitor, Fields::name, name());
111 cont = cont && self.dvWrapField(visitor, Fields::enumerations, m_enumerations);
112 cont = cont && self.dvWrapField(visitor, Fields::objects, m_objects);
113 cont = cont && self.dvValueField(visitor, Fields::isSingleton, isSingleton());
114 cont = cont && self.dvValueField(visitor, Fields::isCreatable, isCreatable());
115 cont = cont && self.dvValueField(visitor, Fields::isComposite, isComposite());
116 cont = cont && self.dvValueField(visitor, Fields::attachedTypeName, attachedTypeName());
117 cont = cont && self.dvReferenceField(visitor, Fields::attachedType, attachedTypePath(self));
118 return cont;
119}
120
122{
123 switch (name.size()) {
124 case 4:
125 if (name == Fields::name)
126 return self.wrapField(Fields::name, m_name);
127 break;
128 case 7:
129 if (name == Fields::objects)
130 return self.wrapField(Fields::objects, m_objects);
131 break;
132 default:
133 break;
134 }
135 return DomBase::field(self, name);
136}
137
139{
140 return appendUpdatableElementInQList(pathFromOwner().field(Fields::objects), m_objects, object,
141 oPtr);
142}
143
145{
146 bool cont = Component::iterateDirectSubpaths(self, visitor);
147 cont = cont && self.dvWrapField(visitor, Fields::ids, m_ids);
148 cont = cont && self.dvValueLazyField(visitor, Fields::subComponents, [this, &self]() {
149 return this->subComponents(self);
150 });
151 return cont;
152}
153
155{
157 updatePathFromOwnerMultiMap(m_ids, newPath.field(Fields::annotations));
158}
159
161{
162 if (name().contains(QLatin1Char('.'))) {
163 // inline component
164 lw.ensureNewline()
165 .writeRegion(u"component")
166 .space()
167 .writeRegion(u"componentName", name().split(QLatin1Char('.')).last())
168 .writeRegion(u"colon", u":")
169 .space();
170 }
171 self.field(Fields::objects).index(0).writeOut(lw);
172}
173
175{
176 DomItem components = self.owner().field(Fields::components);
177 QSet<QString> cNames = components.keys();
178 QString myNameDot = self.pathFromOwner()[1].headName();
179 if (!myNameDot.isEmpty())
180 myNameDot += QLatin1Char('.');
181 QList<QString> subNames;
182 for (QString cName : cNames)
183 if (cName.startsWith(myNameDot)
184 && !QStringView(cName).mid(myNameDot.size()).contains(QLatin1Char('.'))
185 && !cName.isEmpty())
186 subNames.append(cName);
187 std::sort(subNames.begin(), subNames.end());
188 return subNames;
189}
190
192{
193 DomItem components = self.owner().field(Fields::components);
195 for (QString cName : subComponentsNames(self))
196 for (DomItem comp : components.key(cName).values())
197 res.append(comp);
198 return res;
199}
200
202{
203 if (v.isEmpty())
204 return Version(Latest, Latest);
206 QRegularExpression::anchoredPattern(QStringLiteral(uR"(([0-9]*)(?:\.([0-9]*))?)")));
207 auto m = r.matchView(v);
208 if (m.hasMatch()) {
209 bool ok;
210 int majorV = m.capturedView(1).toInt(&ok);
211 if (!ok)
212 majorV = Version::Undefined;
213 int minorV = m.capturedView(2).toInt(&ok);
214 if (!ok)
215 minorV = Version::Undefined;
216 return Version(majorV, minorV);
217 }
218 return {};
219}
220
221Version::Version(qint32 majorV, qint32 minorV) : majorVersion(majorV), minorVersion(minorV) { }
222
224{
225 return majorVersion == Latest && minorVersion == Latest;
226}
227
229{
230 return majorVersion >= 0 && minorVersion >= 0;
231}
232
234{
235 if (isLatest())
236 return QString();
237 if (minorVersion < 0) {
238 if (majorVersion < 0)
239 return QLatin1String(".");
240 else
242 }
243 if (majorVersion < 0)
246}
247
249{
250 bool cont = true;
251 cont = cont && self.dvWrapField(visitor, Fields::majorVersion, majorVersion);
252 cont = cont && self.dvWrapField(visitor, Fields::minorVersion, minorVersion);
253 cont = cont && self.dvValueField(visitor, Fields::isLatest, isLatest());
254 cont = cont && self.dvValueField(visitor, Fields::isValid, isValid());
255 cont = cont && self.dvValueLazyField(visitor, Fields::stringValue, [this]() {
256 return this->stringValue();
257 });
258 return cont;
259}
260
262{
264 uR"((?<uri>\w+(?:\.\w+)*)(?:\W+(?<version>[0-9]+(?:\.[0-9]*)?))?(?:\W+as\W+(?<id>\w+))?$)")));
265 return res;
266}
267
268Import Import::fromUriString(QString importStr, Version v, QString importId, ErrorHandler handler)
269{
270 auto m = importRe().match(importStr);
271 if (m.hasMatch()) {
272 if (v.majorVersion == Version::Undefined && v.minorVersion == Version::Undefined)
273 v = Version::fromString(m.captured(2));
274 else if (!m.captured(u"version").isEmpty())
276 .warning(tr("Version %1 in import string '%2' overridden by explicit "
277 "version %3")
278 .arg(m.captured(2), importStr, v.stringValue()))
279 .handle(handler);
280 if (importId.isEmpty())
281 importId = m.captured(u"importId");
282 else if (!m.captured(u"importId").isEmpty())
284 .warning(tr("namespace %1 in import string '%2' overridden by explicit "
285 "importId %3")
286 .arg(m.captured(u"importId"), importStr, importId))
287 .handle(handler);
288 return Import(QmlUri::fromUriString(m.captured(u"uri").trimmed()), v, importId);
289 }
291 .error(tr("Unexpected URI format in import '%1'").arg(importStr))
292 .handle(handler);
293 return Import();
294}
295
296Import Import::fromFileString(QString importStr, QString importId, ErrorHandler)
297{
298 return Import(QmlUri::fromDirectoryString(importStr), Version(), importId);
299}
300
302{
303 bool cont = true;
304 cont = cont && self.dvValueField(visitor, Fields::uri, uri.toString());
305 cont = cont && self.dvWrapField(visitor, Fields::version, version);
306 if (!importId.isEmpty())
307 cont = cont && self.dvValueField(visitor, Fields::importId, importId);
308 if (implicit)
309 cont = cont && self.dvValueField(visitor, Fields::implicit, implicit);
310 cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
311 return cont;
312}
313
314void Import::writeOut(DomItem &, OutWriter &ow) const
315{
316 if (implicit)
317 return;
318 ow.ensureNewline();
319 ow.writeRegion(u"import").space();
320 ow.writeRegion(u"uri", uri.toString());
321 if (uri.isModule()) {
322 QString vString = version.stringValue();
323 if (!vString.isEmpty())
324 ow.space().write(vString);
325 }
326 if (!importId.isEmpty())
327 ow.space().writeRegion(u"as").space().writeRegion(u"id", importId);
328}
329
330Id::Id(QString idName, Path referredObject) : name(idName), referredObjectPath(referredObject) { }
331
333{
334 bool cont = true;
335 cont = cont && self.dvValueField(visitor, Fields::name, name);
336 cont = cont && self.dvReferenceField(visitor, Fields::referredObject, referredObjectPath);
337 cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
338 cont = cont && self.dvWrapField(visitor, Fields::annotations, annotations);
339 cont = cont && self.dvWrapField(visitor, Fields::value, value);
340 return cont;
341}
342
343void Id::updatePathFromOwner(Path newPath)
344{
345 updatePathFromOwnerQList(annotations, newPath.field(Fields::annotations));
346}
347
348Path Id::addAnnotation(Path selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr)
349{
350 return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations), annotations,
351 annotation, aPtr);
352}
353
354QmlObject::QmlObject(Path pathFromOwner) : CommentableDomElement(pathFromOwner) { }
355
357{
358 bool cont = CommentableDomElement::iterateDirectSubpaths(self, visitor);
359 if (!idStr().isEmpty())
360 cont = cont && self.dvValueField(visitor, Fields::idStr, idStr());
361 cont = cont && self.dvValueField(visitor, Fields::name, name());
362 if (!prototypePaths().isEmpty())
363 cont = cont && self.dvReferencesField(visitor, Fields::prototypes, m_prototypePaths);
364 if (nextScopePath())
365 cont = cont && self.dvReferenceField(visitor, Fields::nextScope, nextScopePath());
366 cont = cont && self.dvWrapField(visitor, Fields::propertyDefs, m_propertyDefs);
367 cont = cont && self.dvWrapField(visitor, Fields::bindings, m_bindings);
368 cont = cont && self.dvWrapField(visitor, Fields::methods, m_methods);
369 cont = cont && self.dvWrapField(visitor, Fields::children, m_children);
370 cont = cont && self.dvWrapField(visitor, Fields::annotations, m_annotations);
371 cont = cont && self.dvItemField(visitor, Fields::propertyInfos, [this, &self]() {
372 return self.subMapItem(Map(
373 pathFromOwner().field(Fields::propertyInfos),
374 [&self](DomItem &map, QString k) {
375 auto pInfo = self.propertyInfoWithName(k);
376 return map.wrap(PathEls::Key(k), pInfo);
377 },
378 [&self](DomItem &) { return self.propertyInfoNames(); },
379 QLatin1String("PropertyInfo")));
380 });
381 return cont;
382}
383
385{
386 static QList<QString> myFields(
387 { QString::fromUtf16(Fields::comments), QString::fromUtf16(Fields::idStr),
388 QString::fromUtf16(Fields::name), QString::fromUtf16(Fields::prototypes),
389 QString::fromUtf16(Fields::nextScope), QString::fromUtf16(Fields::propertyDefs),
390 QString::fromUtf16(Fields::bindings), QString::fromUtf16(Fields::methods),
391 QString::fromUtf16(Fields::children), QString::fromUtf16(Fields::annotations),
392 QString::fromUtf16(Fields::propertyInfos) });
393 return myFields;
394}
395
397{
398 bool cont = iterateBaseDirectSubpaths(self, visitor);
399 cont = cont && self.dvValueLazyField(visitor, Fields::defaultPropertyName, [this, &self]() {
400 return defaultPropertyName(self);
401 });
402 return cont;
403}
404
406{
407 switch (name.size()) {
408 case 4:
409 if (name == Fields::name)
410 return self.subDataItem(PathEls::Field(Fields::name), this->name());
411 break;
412 case 5:
413 if (name == Fields::idStr) {
414 if (idStr().isEmpty())
415 return DomItem();
416 return self.subDataItem(PathEls::Field(Fields::idStr), idStr());
417 }
418 break;
419 case 7:
420 if (name == Fields::methods)
421 return self.wrapField(Fields::methods, m_methods);
422 break;
423 case 8:
424 switch (name.at(1).unicode()) {
425 case u'i':
426 if (name == Fields::bindings)
427 return self.wrapField(Fields::bindings, m_bindings);
428 break;
429 case u'o':
430 if (name == Fields::comments)
432 break;
433 case u'h':
434 if (name == Fields::children)
435 return self.wrapField(Fields::children, m_children);
436 break;
437 default:
438 break;
439 }
440 break;
441 case 9:
442 if (name == Fields::nextScope) {
443 if (nextScopePath())
444 return self.subReferenceItem(PathEls::Field(Fields::nextScope), nextScopePath());
445 else
446 return DomItem();
447 }
448 break;
449 case 10:
450 if (name == Fields::prototypes) {
451 if (prototypePaths().isEmpty())
452 return DomItem();
453 return self.subReferencesItem(PathEls::Field(Fields::prototypes), m_prototypePaths);
454 }
455 break;
456 case 11:
457 if (name == Fields::annotations)
458 return self.wrapField(Fields::annotations, m_annotations);
459 break;
460 case 12:
461 return self.wrapField(Fields::propertyDefs, m_propertyDefs);
462 break;
463 case 13:
464 if (name == Fields::propertyInfos)
465 return self.subMapItem(Map(
466 pathFromOwner().field(Fields::propertyInfos),
467 [self](DomItem &map, QString k) mutable {
468 auto pInfo = self.propertyInfoWithName(k);
469 return map.wrap(PathEls::Key(k), pInfo);
470 },
471 [self](DomItem &) mutable { return self.propertyInfoNames(); },
472 QLatin1String("PropertyInfo")));
473 break;
474 case 19:
475 if (name == Fields::defaultPropertyName)
476 return self.subDataItem(PathEls::Field(Fields::defaultPropertyName),
477 defaultPropertyName(self));
478 break;
479 default:
480 break;
481 }
482 static QStringList knownLookups({ QString::fromUtf16(Fields::fileLocationsTree) });
483 if (!knownLookups.contains(name))
484 qCWarning(domLog()) << "Asked non existing field " << name << " in QmlObject "
485 << pathFromOwner();
486 return DomItem();
487}
488
490{
492 updatePathFromOwnerMultiMap(m_propertyDefs, newPath.field(Fields::propertyDefs));
493 updatePathFromOwnerMultiMap(m_bindings, newPath.field(Fields::bindings));
494 updatePathFromOwnerMultiMap(m_methods, newPath.field(Fields::methods));
495 updatePathFromOwnerQList(m_children, newPath.field(Fields::children));
496 updatePathFromOwnerQList(m_annotations, newPath.field(Fields::annotations));
497}
498
500{
501 if (!m_defaultPropertyName.isEmpty())
502 return m_defaultPropertyName;
503 for (const PropertyDefinition &pDef : m_propertyDefs)
504 if (pDef.isDefaultMember)
505 return pDef.name;
506 return QString();
507}
508
510{
512 if (!dProp.isEmpty())
513 return dProp;
514 QString res = QStringLiteral(u"data");
515 self.visitPrototypeChain(
516 [&res](DomItem &obj) {
517 if (const QmlObject *objPtr = obj.as<QmlObject>()) {
518 QString dProp = objPtr->localDefaultPropertyName();
519 if (!dProp.isEmpty()) {
520 res = dProp;
521 return false;
522 }
523 }
524 return true;
525 },
527 return res;
528}
529
530bool QmlObject::iterateSubOwners(DomItem &self, function_ref<bool(DomItem &)> visitor) const
531{
532 bool cont = self.field(Fields::bindings).visitKeys([visitor](QString, DomItem &bs) {
533 return bs.visitIndexes([visitor](DomItem &b) {
534 DomItem v = b.field(Fields::value);
535 if (std::shared_ptr<ScriptExpression> vPtr = v.ownerAs<ScriptExpression>()) {
536 if (!visitor(v))
537 return false;
538 return v.iterateSubOwners(visitor); // currently not needed, avoid?
539 }
540 return true;
541 });
542 });
543 cont = cont && self.field(Fields::children).visitIndexes([visitor](DomItem &qmlObj) {
544 if (const QmlObject *qmlObjPtr = qmlObj.as<QmlObject>()) {
545 return qmlObjPtr->iterateSubOwners(qmlObj, visitor);
546 }
547 Q_ASSERT(false);
548 return true;
549 });
550 return cont;
551}
552
553static QStringList dotExpressionToList(std::shared_ptr<ScriptExpression> expr)
554{
556 AST::Node *node = (expr ? expr->ast() : nullptr);
557 while (node) {
558 switch (node->kind) {
560 AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(node);
561 res.prepend(id->name.toString());
562 return res;
563 }
565 AST::FieldMemberExpression *id = AST::cast<AST::FieldMemberExpression *>(node);
566 res.prepend(id->name.toString());
567 node = id->base;
568 break;
569 }
570 default:
571 qCDebug(writeOutLog).noquote() << "Could not convert dot expression to list for:\n"
572 << expr->astRelocatableDump();
573 return QStringList();
574 }
575 }
576 return res;
577}
578
579LocallyResolvedAlias QmlObject::resolveAlias(DomItem &self,
580 std::shared_ptr<ScriptExpression> accessSequence) const
581{
582 QStringList accessSequenceList = dotExpressionToList(accessSequence);
583 return resolveAlias(self, accessSequenceList);
584}
585
586LocallyResolvedAlias QmlObject::resolveAlias(DomItem &self, const QStringList &accessSequence) const
587{
588 LocallyResolvedAlias res;
589 QSet<QString> visitedAlias;
590 if (accessSequence.isEmpty()) {
591 return res;
592 } else if (accessSequence.size() > 3) {
593 res.status = LocallyResolvedAlias::Status::TooDeep;
594 return res;
595 }
596 QString idName = accessSequence.first();
597 DomItem idTarget = self.component()
598 .field(Fields::ids)
599 .key(idName)
600 .index(0)
601 .field(Fields::referredObject)
602 .get();
603 if (!idTarget)
604 return res;
605 res.baseObject = idTarget;
606 res.accessedPath = accessSequence.mid(1);
607 res.typeName = idTarget.name();
608 res.status = LocallyResolvedAlias::Status::ResolvedObject;
609 // check if it refers to locally defined props/objs
610 while (!res.accessedPath.isEmpty()) {
611 QString pNow = res.accessedPath.first();
612 DomItem defNow = res.baseObject.propertyDefs().key(pNow).index(0);
613 if (const PropertyDefinition *defNowPtr = defNow.as<PropertyDefinition>()) {
614 if (defNowPtr->isAlias()) {
615 res.typeName = QString();
616 ++res.nAliases;
617 QString aliasPath = defNow.canonicalPath().toString();
618 if (visitedAlias.contains(aliasPath)) {
619 res.status = LocallyResolvedAlias::Status::Loop;
620 return res;
621 }
622 visitedAlias.insert(aliasPath);
623 DomItem valNow = res.baseObject.bindings().key(pNow).index(0);
624 if (std::shared_ptr<ScriptExpression> exp =
625 valNow.field(Fields::value).ownerAs<ScriptExpression>()) {
626 QStringList expList = dotExpressionToList(exp);
627 if (expList.isEmpty()) {
628 res.status = LocallyResolvedAlias::Status::Invalid;
629 return res;
630 } else if (expList.size() > 3) {
631 res.status = LocallyResolvedAlias::Status::TooDeep;
632 return res;
633 }
634 idName = expList.first();
635 idTarget = self.component()
636 .field(Fields::ids)
637 .key(idName)
638 .index(0)
639 .field(Fields::referredObject)
640 .get();
641 res.baseObject = idTarget;
642 res.accessedPath = expList.mid(1) + res.accessedPath.mid(1);
643 if (!idTarget) {
644 res.status = LocallyResolvedAlias::Status::Invalid;
645 return res;
646 }
647 res.status = LocallyResolvedAlias::Status::ResolvedObject;
648 res.typeName = idTarget.name();
649 } else {
650 res.status = LocallyResolvedAlias::Status::Invalid;
651 return res;
652 }
653 } else {
654 res.localPropertyDef = defNow;
655 res.typeName = defNowPtr->typeName;
656 res.accessedPath = res.accessedPath.mid(1);
657 DomItem valNow = res.baseObject.bindings().key(pNow).index(0).field(Fields::value);
658 if (valNow.internalKind() == DomType::QmlObject) {
659 res.baseObject = valNow;
660 res.typeName = valNow.name();
661 res.status = LocallyResolvedAlias::Status::ResolvedObject;
662 } else {
663 res.status = LocallyResolvedAlias::Status::ResolvedProperty;
664 return res;
665 }
666 }
667 } else {
668 return res;
669 }
670 }
671 return res;
672}
673
674MutableDomItem QmlObject::addPropertyDef(MutableDomItem &self, PropertyDefinition propertyDef,
675 AddOption option)
676{
677 Path p = addPropertyDef(propertyDef, option);
678 if (p.last().headIndex(0) > 1)
679 self.owningItemPtr()->addErrorLocal(domParsingErrors().error(
680 tr("Repeated PropertyDefinition with name %1").arg(propertyDef.name)));
681 return self.owner().path(p);
682}
683
684MutableDomItem QmlObject::addBinding(MutableDomItem &self, Binding binding, AddOption option)
685{
686 Path p = addBinding(binding, option);
687 if (p && p.last().headIndex(0) > 1)
688 self.owningItemPtr()->addErrorLocal(
689 domParsingErrors().error(tr("Repeated binding with name %1").arg(binding.name())));
690 return self.owner().path(p);
691}
692
693MutableDomItem QmlObject::addMethod(MutableDomItem &self, MethodInfo functionDef, AddOption option)
694{
695 Path p = addMethod(functionDef, option);
696 if (p.last().headIndex(0) > 1)
697 self.owningItemPtr()->addErrorLocal(
698 domParsingErrors().error(tr("Repeated Method with name %1").arg(functionDef.name)));
699 return self.owner().path(p);
700}
701
702void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
703{
704 const quint32 posOfNewElements = std::numeric_limits<quint32>::max();
705 bool isRootObject = pathFromOwner().length() == 5
706 && pathFromOwner()[0] == Path::Field(Fields::components)
707 && pathFromOwner()[3] == Path::Field(Fields::objects);
709 DomItem owner = self.owner();
710 if (std::shared_ptr<QmlFile> qmlFilePtr = self.ownerAs<QmlFile>())
711 code = qmlFilePtr->code();
712 ow.writeRegion(u"name", name());
713 if (!onTarget.isEmpty())
714 ow.space().writeRegion(u"on", u"on").space().writeRegion(u"onTarget", onTarget).space();
715 ow.writeRegion(u"leftBrace", u" {").newline();
716 int baseIndent = ow.increaseIndent();
717 int spacerId = 0;
718 if (!idStr().isEmpty()) { // *always* put id first
719 DomItem myId = self.component().field(Fields::ids).key(idStr()).index(0);
720 if (myId)
721 myId.writeOutPre(ow);
722 ow.ensureNewline()
723 .writeRegion(u"idToken", u"id")
724 .writeRegion(u"idColon", u":")
725 .space()
726 .writeRegion(u"id", idStr());
727 if (ow.lineWriter.options().attributesSequence
728 == LineWriterOptions::AttributesSequence::Normalize) {
729 ow.ensureNewline(2);
730 }
731 if (myId)
732 myId.writeOutPost(ow);
733 }
734 quint32 counter = ow.counter();
736 if (isRootObject)
737 component = self.containingObject();
738 auto startLoc = [&](FileLocations::Tree l) {
739 if (l)
740 return l->info().fullRegion;
741 return SourceLocation(posOfNewElements, 0, 0, 0);
742 };
743 if (ow.lineWriter.options().attributesSequence
744 == LineWriterOptions::AttributesSequence::Preserve) {
746 AttachedInfoLookupResult<FileLocations::Tree> objLoc =
747 FileLocations::findAttachedInfo(self);
748 FileLocations::Tree componentLoc;
749 if (isRootObject && objLoc.foundTree)
750 componentLoc = objLoc.foundTree->parent()->parent();
751 auto addMMap = [&attribs, &startLoc](DomItem &base, FileLocations::Tree baseLoc) {
752 if (!base)
753 return;
754 for (auto els : base.values()) {
755 FileLocations::Tree elsLoc =
756 FileLocations::find(baseLoc, els.pathFromOwner().last());
757 for (auto el : els.values()) {
758 FileLocations::Tree elLoc =
759 FileLocations::find(elsLoc, el.pathFromOwner().last());
760 attribs.append(std::make_pair(startLoc(elLoc), el));
761 }
762 }
763 };
764 auto addMyMMap = [this, &objLoc, &self, &addMMap](QStringView fieldName) {
765 DomItem base = this->field(self, fieldName);
766 addMMap(base, FileLocations::find(objLoc.foundTree, base.pathFromOwner().last()));
767 };
768 auto addSingleLevel = [&attribs, &startLoc](DomItem &base, FileLocations::Tree baseLoc) {
769 if (!base)
770 return;
771 for (auto el : base.values()) {
772 FileLocations::Tree elLoc = FileLocations::find(baseLoc, el.pathFromOwner().last());
773 attribs.append(std::make_pair(startLoc(elLoc), el));
774 }
775 };
776 if (isRootObject) {
777 DomItem enums = component.field(Fields::enumerations);
778 addMMap(enums, FileLocations::find(componentLoc, enums.pathFromOwner().last()));
779 }
780 addMyMMap(Fields::propertyDefs);
781 addMyMMap(Fields::bindings);
782 addMyMMap(Fields::methods);
783 DomItem children = field(self, Fields::children);
784 addSingleLevel(children,
785 FileLocations::find(objLoc.foundTree, children.pathFromOwner().last()));
786 if (isRootObject) {
787 DomItem subCs = component.field(Fields::subComponents);
788 for (DomItem &c : subCs.values()) {
789 AttachedInfoLookupResult<FileLocations::Tree> subLoc =
790 FileLocations::findAttachedInfo(c);
791 Q_ASSERT(subLoc.foundTree);
792 attribs.append(std::make_pair(startLoc(subLoc.foundTree), c));
793 }
794 }
795 std::stable_sort(attribs.begin(), attribs.end(),
796 [](const std::pair<SourceLocation, DomItem> &el1,
797 const std::pair<SourceLocation, DomItem> &el2) {
798 if (el1.first.offset < el2.first.offset)
799 return true;
800 if (el1.first.offset > el2.first.offset)
801 return false;
802 int i = int(el1.second.internalKind())
803 - int(el2.second.internalKind());
804 return i < 0;
805 });
806 qsizetype iAttr = 0;
807 while (iAttr != attribs.size()) {
808 auto &el = attribs[iAttr++];
809 // check for an empty line before the current element, and preserve it
810 int preNewlines = 0;
811 quint32 start = el.first.offset;
812 if (start != posOfNewElements && size_t(code.size()) >= start) {
813 while (start != 0) {
814 QChar c = code.at(--start);
815 if (c == u'\n') {
816 if (++preNewlines == 2)
817 break;
818 } else if (!c.isSpace())
819 break;
820 }
821 }
822 if (preNewlines == 0)
823 ++preNewlines;
824 ow.ensureNewline(preNewlines);
825 if (el.second.internalKind() == DomType::PropertyDefinition && iAttr != attribs.size()
826 && el.first.offset != ~quint32(0)) {
827 DomItem b;
828 auto &bPair = attribs[iAttr];
829 if (bPair.second.internalKind() == DomType::Binding
830 && bPair.first.begin() < el.first.end()
831 && bPair.second.name() == el.second.name()) {
832 b = bPair.second;
833 ++iAttr;
834 b.writeOutPre(ow);
835 }
836 el.second.writeOut(ow);
837 if (b) {
838 ow.write(u": ");
839 if (const Binding *bPtr = b.as<Binding>())
840 bPtr->writeOutValue(b, ow);
841 else {
842 qWarning() << "Internal error casting binding to Binding in"
843 << b.canonicalPath();
844 ow.writeRegion(u"leftBrace", u"{").writeRegion(u"rightBrace", u"}");
845 }
846 b.writeOutPost(ow);
847 }
848 } else {
849 el.second.writeOut(ow);
850 }
851 }
852 ow.decreaseIndent(1, baseIndent);
853 ow.ensureNewline().write(u"}");
854
855 return;
856 }
857 DomItem bindings = field(self, Fields::bindings);
858 DomItem propertyDefs = field(self, Fields::propertyDefs);
859
860 if (isRootObject) {
861 for (auto enumDescs : component.field(Fields::enumerations).values()) {
862 for (auto enumDesc : enumDescs.values()) {
863 ow.ensureNewline(1);
864 enumDesc.writeOut(ow);
865 ow.ensureNewline(1);
866 }
867 }
868 }
869 if (counter != ow.counter() || !idStr().isEmpty())
870 spacerId = ow.addNewlinesAutospacerCallback(2);
871 QSet<QString> mergedDefBinding;
872 for (const QString &defName : propertyDefs.sortedKeys()) {
873 auto pDefs = propertyDefs.key(defName).values();
874 for (auto pDef : pDefs) {
875 const PropertyDefinition *pDefPtr = pDef.as<PropertyDefinition>();
876 Q_ASSERT(pDefPtr);
877 DomItem b;
878 bool uniqueDeclarationWithThisName = pDefs.size() == 1;
879 if (uniqueDeclarationWithThisName && !pDefPtr->isRequired)
880 bindings.key(pDef.name()).visitIndexes([&b, pDefPtr](DomItem &el) {
881 const Binding *elPtr = el.as<Binding>();
882 if (elPtr && elPtr->bindingType() == BindingType::Normal) {
883 switch (elPtr->valueKind()) {
884 case BindingValueKind::ScriptExpression:
885 b = el;
886 break;
887 case BindingValueKind::Array:
888 if (!pDefPtr->isDefaultMember
889 && pDefPtr->isParametricType())
890 b = el;
891 break;
892 case BindingValueKind::Object:
893 if (!pDefPtr->isDefaultMember
894 && !pDefPtr->isParametricType())
895 b = el;
896 break;
897 case BindingValueKind::Empty:
898 break;
899 }
900 return false;
901 }
902 return true;
903 });
904 if (b) {
905 mergedDefBinding.insert(defName);
906 b.writeOutPre(ow);
907 }
908 pDef.writeOut(ow);
909 if (b) {
910 ow.write(u": ");
911 if (const Binding *bPtr = b.as<Binding>())
912 bPtr->writeOutValue(b, ow);
913 else {
914 qWarning() << "Internal error casting binding to Binding in"
915 << b.canonicalPath();
916 ow.writeRegion(u"leftBrace", u"{").writeRegion(u"rightBrace", u"}");
917 }
918 b.writeOutPost(ow);
919 }
920 }
921 }
922 ow.removeTextAddCallback(spacerId);
923 QList<DomItem> signalList, methodList;
924 for (auto ms : field(self, Fields::methods).values()) {
925 for (auto m : ms.values()) {
926 const MethodInfo *mPtr = m.as<MethodInfo>();
927 if (mPtr && mPtr->methodType == MethodInfo::MethodType::Signal)
928 signalList.append(m);
929 else
930 methodList.append(m);
931 }
932 }
933 if (counter != ow.counter())
934 spacerId = ow.addNewlinesAutospacerCallback(2);
935 for (auto &sig : signalList) {
936 ow.ensureNewline();
937 sig.writeOut(ow);
938 ow.ensureNewline();
939 }
940 ow.removeTextAddCallback(spacerId);
941 if (counter != ow.counter())
942 spacerId = ow.addNewlinesAutospacerCallback(2);
943 bool first = true;
944 for (auto &method : methodList) {
945 if (!first && ow.lineWriter.options().functionsSpacing) {
946 ow.newline();
947 }
948 ow.ensureNewline();
949 first = false;
950 method.writeOut(ow);
951 ow.ensureNewline();
952 }
953 ow.removeTextAddCallback(spacerId);
954 QList<DomItem> normalBindings, signalHandlers, delayedBindings;
955 for (auto bName : bindings.sortedKeys()) {
956 bool skipFirstNormal = mergedDefBinding.contains(bName);
957 for (auto b : bindings.key(bName).values()) {
958 const Binding *bPtr = b.as<Binding>();
959 if (skipFirstNormal) {
960 if (bPtr && bPtr->bindingType() == BindingType::Normal) {
961 skipFirstNormal = false;
962 continue;
963 }
964 }
965 if (bPtr->valueKind() == BindingValueKind::Array
966 || bPtr->valueKind() == BindingValueKind::Object)
967 delayedBindings.append(b);
968 else if (b.field(Fields::isSignalHandler).value().toBool(false))
969 signalHandlers.append(b);
970 else
971 normalBindings.append(b);
972 }
973 }
974 if (counter != ow.counter())
975 spacerId = ow.addNewlinesAutospacerCallback(2);
976 for (auto &b : normalBindings)
977 b.writeOut(ow);
978 ow.removeTextAddCallback(spacerId);
979 if (counter != ow.counter())
980 spacerId = ow.addNewlinesAutospacerCallback(2);
981 for (auto &b : delayedBindings)
982 b.writeOut(ow);
983 ow.removeTextAddCallback(spacerId);
984 if (counter != ow.counter())
985 spacerId = ow.addNewlinesAutospacerCallback(2);
986 for (auto &b : signalHandlers)
987 b.writeOut(ow);
988 ow.removeTextAddCallback(spacerId);
989 if (counter != ow.counter())
990 spacerId = ow.addNewlinesAutospacerCallback(2);
991 first = true;
992 for (auto c : field(self, Fields::children).values()) {
993 if (!first && ow.lineWriter.options().objectsSpacing) {
994 ow.newline().newline();
995 }
996 first = false;
997 ow.ensureNewline();
998 c.writeOut(ow);
999 }
1000 ow.removeTextAddCallback(spacerId);
1001 if (isRootObject) {
1002 // we are a root object, possibly add components
1003 DomItem subComps = component.field(Fields::subComponents);
1004 if (counter != ow.counter())
1005 spacerId = ow.addNewlinesAutospacerCallback(2);
1006 for (auto subC : subComps.values()) {
1007 ow.ensureNewline();
1008 subC.writeOut(ow);
1009 }
1010 ow.removeTextAddCallback(spacerId);
1011 }
1012 ow.decreaseIndent(1, baseIndent);
1013 ow.ensureNewline().write(u"}");
1014}
1015
1016Binding::Binding(QString name, std::unique_ptr<BindingValue> value, BindingType bindingType)
1017 : m_bindingType(bindingType), m_name(name), m_value(std::move(value))
1018{
1019}
1020
1021Binding::Binding(QString name, std::shared_ptr<ScriptExpression> value, BindingType bindingType)
1022 : Binding(name, std::make_unique<BindingValue>(value), bindingType)
1023{
1024}
1025
1026Binding::Binding(QString name, QString scriptCode, BindingType bindingType)
1027 : Binding(name,
1028 std::make_unique<BindingValue>(std::make_shared<ScriptExpression>(
1029 scriptCode, ScriptExpression::ExpressionType::BindingExpression, 0,
1030 Binding::preCodeForName(name), Binding::postCodeForName(name))),
1031 bindingType)
1032{
1033}
1034
1035Binding::Binding(QString name, QmlObject value, BindingType bindingType)
1036 : Binding(name, std::make_unique<BindingValue>(value), bindingType)
1037{
1038}
1039
1041 : Binding(name, std::make_unique<BindingValue>(value), bindingType)
1042{
1043}
1044
1045Binding::Binding(const Binding &o)
1046 : m_bindingType(o.m_bindingType),
1047 m_name(o.m_name),
1048 m_annotations(o.m_annotations),
1049 m_comments(o.m_comments)
1050{
1051 if (o.m_value) {
1052 m_value = std::make_unique<BindingValue>(*o.m_value);
1053 }
1054}
1055
1057
1058Binding &Binding::operator=(const Binding &o)
1059{
1060 m_name = o.m_name;
1061 m_bindingType = o.m_bindingType;
1062 m_annotations = o.m_annotations;
1063 m_comments = o.m_comments;
1064 if (o.m_value) {
1065 if (!m_value)
1066 m_value = std::make_unique<BindingValue>(*o.m_value);
1067 else
1068 *m_value = *o.m_value;
1069 } else {
1070 m_value.reset();
1071 }
1072 return *this;
1073}
1074
1076{
1077 bool cont = true;
1078 cont = cont && self.dvValueField(visitor, Fields::name, m_name);
1079 cont = cont && self.dvValueField(visitor, Fields::isSignalHandler, isSignalHandler());
1080 if (!m_value)
1081 cont = cont && visitor(PathEls::Field(Fields::value), []() { return DomItem(); });
1082 else
1083 cont = cont && self.dvItemField(visitor, Fields::value, [this, &self]() {
1084 return m_value->value(self);
1085 });
1086 cont = cont && self.dvValueField(visitor, Fields::bindingType, int(m_bindingType));
1087 cont = cont && self.dvWrapField(visitor, Fields::comments, m_comments);
1088 cont = cont && self.dvValueLazyField(visitor, Fields::preCode, [this]() {
1089 return this->preCode();
1090 });
1091 cont = cont && self.dvValueLazyField(visitor, Fields::postCode, [this]() {
1092 return this->postCode();
1093 });
1094 cont = cont && self.dvWrapField(visitor, Fields::annotations, m_annotations);
1095 return cont;
1096}
1097
1099{
1100 if (!m_value)
1101 return DomItem();
1102 return m_value->value(self);
1103}
1104
1106{
1107 if (!m_value)
1109 return m_value->kind;
1110}
1111
1112QmlObject const *Binding::objectValue() const
1113{
1115 return &(m_value->object);
1116 return nullptr;
1117}
1118
1120{
1122 return &(m_value->object);
1123 return nullptr;
1124}
1125
1127{
1129 return &(m_value->array);
1130 return nullptr;
1131}
1132
1134{
1136 return &(m_value->array);
1137 return nullptr;
1138}
1139
1140std::shared_ptr<ScriptExpression> Binding::scriptExpressionValue() const
1141{
1143 return m_value->scriptExpression;
1144 return nullptr;
1145}
1146
1147std::shared_ptr<ScriptExpression> Binding::scriptExpressionValue()
1148{
1150 return m_value->scriptExpression;
1151 return nullptr;
1152}
1153
1154Path Binding::addAnnotation(Path selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr)
1155{
1156 return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations),
1157 m_annotations, annotation, aPtr);
1158}
1159
1161{
1162 Path base = newPath.field(Fields::annotations);
1163 if (m_value)
1164 m_value->updatePathFromOwner(newPath.field(Fields::value));
1165 updatePathFromOwnerQList(m_annotations, newPath.field(Fields::annotations));
1166}
1167
1168void Binding::writeOut(DomItem &self, OutWriter &lw) const
1169{
1170 lw.ensureNewline();
1171 if (m_bindingType == BindingType::Normal) {
1172 lw.writeRegion(u"name", name());
1173 lw.writeRegion(u"colon", u":").space();
1174 writeOutValue(self, lw);
1175 } else {
1176 DomItem v = valueItem(self);
1177 if (const QmlObject *vPtr = v.as<QmlObject>()) {
1178 v.writeOutPre(lw);
1179 vPtr->writeOut(v, lw, name());
1180 v.writeOutPost(lw);
1181 } else {
1182 qCWarning(writeOutLog()) << "On Binding requires an QmlObject Value, not "
1183 << v.internalKindStr() << " at " << self.canonicalPath();
1184 }
1185 }
1186}
1187
1188void Binding::writeOutValue(DomItem &self, OutWriter &lw) const
1189{
1190 DomItem v = valueItem(self);
1191 switch (valueKind()) {
1193 qCWarning(writeOutLog()) << "Writing of empty binding " << name();
1194 lw.write(u"{}");
1195 break;
1197 if (const List *vPtr = v.as<List>()) {
1198 v.writeOutPre(lw);
1199 vPtr->writeOut(v, lw, false);
1200 v.writeOutPost(lw);
1201 }
1202 break;
1205 v.writeOut(lw);
1206 break;
1207 }
1208}
1209
1211{
1212 bool cont = Component::iterateDirectSubpaths(self, visitor);
1213 cont = cont && self.dvWrapField(visitor, Fields::exports, m_exports);
1214 cont = cont && self.dvValueField(visitor, Fields::metaRevisions, m_metaRevisions);
1215 if (!fileName().isEmpty())
1216 cont = cont && self.dvValueField(visitor, Fields::fileName, fileName()); // remove?
1217 cont = cont && self.dvValueField(visitor, Fields::interfaceNames, m_interfaceNames);
1218 cont = cont && self.dvValueField(visitor, Fields::hasCustomParser, m_hasCustomParser);
1219 cont = cont && self.dvValueField(visitor, Fields::valueTypeName, m_valueTypeName);
1220 cont = cont && self.dvValueField(visitor, Fields::extensionTypeName, m_extensionTypeName);
1221 cont = cont && self.dvValueField(visitor, Fields::accessSemantics, int(m_accessSemantics));
1222 return cont;
1223}
1224
1226{
1227 Export res;
1228 res.exportSourcePath = source;
1229 res.typePath = typePath;
1230 int slashIdx = exp.indexOf(QLatin1Char('/'));
1231 int spaceIdx = exp.indexOf(QLatin1Char(' '));
1232 if (spaceIdx == -1)
1233 spaceIdx = exp.size();
1234 else
1235 res.version = Version::fromString(exp.mid(spaceIdx + 1));
1236 if (!res.version.isValid())
1238 .error(tr("Expected string literal to contain 'Package/Name major.minor' "
1239 "or 'Name major.minor' not '%1'.")
1240 .arg(exp))
1241 .handle(h);
1242 QString package;
1243 if (slashIdx != -1)
1244 res.uri = exp.left(slashIdx).toString();
1245 res.typeName = exp.mid(slashIdx + 1, spaceIdx - (slashIdx + 1)).toString();
1246 return res;
1247}
1248
1250{
1251 bool cont = true;
1252 cont = cont && self.dvValueField(visitor, Fields::name, name);
1253 cont = cont && self.dvValueField(visitor, Fields::access, int(access));
1254 cont = cont && self.dvValueField(visitor, Fields::typeName, typeName);
1255 cont = cont && self.dvValueField(visitor, Fields::isReadonly, isReadonly);
1256 cont = cont && self.dvValueField(visitor, Fields::isList, isList);
1257 cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
1258 cont = cont && self.dvWrapField(visitor, Fields::annotations, annotations);
1259 return cont;
1260}
1261
1262Path AttributeInfo::addAnnotation(Path selfPathFromOwner, const QmlObject &annotation,
1263 QmlObject **aPtr)
1264{
1265 return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations), annotations,
1266 annotation, aPtr);
1267}
1268
1270{
1271 Path base = newPath.field(Fields::annotations);
1272 updatePathFromOwnerQList(annotations, newPath.field(Fields::annotations));
1273}
1274
1276{
1277 bool cont = CommentableDomElement::iterateDirectSubpaths(self, visitor);
1278 cont = cont && self.dvValueField(visitor, Fields::name, name());
1279 cont = cont && self.dvWrapField(visitor, Fields::values, m_values);
1280 cont = cont && self.dvWrapField(visitor, Fields::annotations, m_annotations);
1281 return cont;
1282}
1283
1285{
1287 updatePathFromOwnerQList(m_annotations, newPath.field(Fields::annotations));
1288}
1289
1291{
1292 m_annotations = annotations;
1293}
1294
1295Path EnumDecl::addAnnotation(const QmlObject &annotation, QmlObject **aPtr)
1296{
1297 return appendUpdatableElementInQList(pathFromOwner().field(Fields::annotations), m_annotations,
1298 annotation, aPtr);
1299}
1300
1301void EnumDecl::writeOut(DomItem &self, OutWriter &ow) const
1302{
1303 ow.writeRegion(u"enum", u"enum")
1304 .space()
1305 .writeRegion(u"name", name())
1306 .space()
1307 .writeRegion(u"lbrace", u"{");
1308 int iLevel = ow.increaseIndent(1);
1309 for (auto value : self.field(Fields::values).values()) {
1310 ow.ensureNewline();
1311 value.writeOut(ow);
1312 }
1313 ow.decreaseIndent(1, iLevel);
1314 ow.ensureNewline().writeRegion(u"rbrace", u"}");
1315}
1316
1318{
1319 DomItem top = self.top();
1320 DomItem env = top.environment();
1321 Path selfPath = self.canonicalPath().field(Fields::allSources);
1322 RefCacheEntry cached = (env ? RefCacheEntry::forPath(env, selfPath) : RefCacheEntry());
1323 if (cached.cached == RefCacheEntry::Cached::All)
1324 return cached.canonicalPaths;
1326 QSet<Path> knownPaths;
1327 QList<Path> toDo(m_importSourcePaths.rbegin(), m_importSourcePaths.rend());
1328 while (!toDo.isEmpty()) {
1329 Path pNow = toDo.takeLast();
1330 if (knownPaths.contains(pNow))
1331 continue;
1332 knownPaths.insert(pNow);
1333 res.append(pNow);
1334 DomItem sourceBase = top.path(pNow);
1335 for (DomItem autoExp : sourceBase.field(Fields::autoExports).values()) {
1336 if (const ModuleAutoExport *autoExpPtr = autoExp.as<ModuleAutoExport>()) {
1337 Path newSource;
1338 if (autoExpPtr->inheritVersion) {
1339 Version v = autoExpPtr->import.version;
1340 DomItem sourceVersion = sourceBase.field(Fields::version);
1341 if (const Version *sourceVersionPtr = sourceVersion.as<Version>()) {
1342 if (v.majorVersion < 0)
1343 v.majorVersion = sourceVersionPtr->majorVersion;
1344 if (v.minorVersion < 0)
1345 v.minorVersion = sourceVersionPtr->minorVersion;
1346 } else {
1347 qWarning() << "autoExport with inherited version " << autoExp
1348 << " but missing version in source" << pNow;
1349 }
1350 Import toImport(autoExpPtr->import.uri, v);
1351 newSource = toImport.importedPath();
1352 } else {
1353 newSource = autoExpPtr->import.importedPath();
1354 }
1355 if (newSource && !knownPaths.contains(newSource))
1356 toDo.append(newSource);
1357 } else {
1358 qWarning() << "expected ModuleAutoExport not " << autoExp.internalKindStr()
1359 << "looking up autoExports of" << sourceBase;
1360 Q_ASSERT(false);
1361 }
1362 }
1363 }
1364 if (env)
1365 RefCacheEntry::addForPath(env, selfPath, RefCacheEntry { RefCacheEntry::Cached::All, res });
1366 return res;
1367}
1368
1370{
1371 bool cont = true;
1372 cont = cont && self.dvReferencesField(visitor, Fields::importSources, m_importSourcePaths);
1373 cont = cont && self.dvItemField(visitor, Fields::allSources, [this, &self]() -> DomItem {
1374 return self.subListItem(List::fromQList<Path>(
1375 self.pathFromOwner().field(Fields::allSources), allSources(self),
1376 [](DomItem &list, const PathEls::PathComponent &p, const Path &el) {
1377 return list.subDataItem(p, el.toString());
1378 }));
1379 });
1380 cont = cont && self.dvWrapField(visitor, Fields::qualifiedImports, m_subImports);
1381 cont = cont && self.dvItemField(visitor, Fields::imported, [this, &self]() -> DomItem {
1382 return self.subMapItem(Map(
1383 self.pathFromOwner().field(Fields::imported),
1384 [this, &self](DomItem &map, QString key) {
1385 return map.subListItem(List::fromQList<DomItem>(
1386 map.pathFromOwner().key(key), importedItemsWithName(self, key),
1387 [](DomItem &, const PathEls::PathComponent &, DomItem &el) {
1388 return el;
1389 }));
1390 },
1391 [this, &self](DomItem &) { return this->importedNames(self); },
1392 QLatin1String("List<Export>")));
1393 });
1394 return cont;
1395}
1396
1398{
1399 bool cont = true;
1400 cont = cont && self.dvValueField(visitor, Fields::propertyDefs, propertyDefs);
1401 cont = cont && self.dvValueField(visitor, Fields::bindings, bindings);
1402 return cont;
1403}
1404
1406
1407BindingValue::BindingValue(const QmlObject &o) : kind(BindingValueKind::Object)
1408{
1409 new (&object) QmlObject(o);
1410}
1411
1412BindingValue::BindingValue(std::shared_ptr<ScriptExpression> o)
1414{
1415 new (&scriptExpression) std::shared_ptr<ScriptExpression>(o);
1416}
1417
1419{
1420 new (&array) QList<QmlObject>(l);
1421}
1422
1424{
1425 clearValue();
1426}
1427
1428BindingValue::BindingValue(const BindingValue &o) : kind(o.kind)
1429{
1430 switch (o.kind) {
1432 break;
1434 new (&object) QmlObject(o.object);
1435 break;
1437 new (&scriptExpression) std::shared_ptr<ScriptExpression>(o.scriptExpression);
1438 break;
1440 new (&array) QList<QmlObject>(o.array);
1441 }
1442}
1443
1444BindingValue &BindingValue::operator=(const BindingValue &o)
1445{
1446 clearValue();
1447 kind = o.kind;
1448 switch (o.kind) {
1450 break;
1452 new (&object) QmlObject(o.object);
1453 break;
1455 new (&scriptExpression) std::shared_ptr<ScriptExpression>(o.scriptExpression);
1456 break;
1458 new (&array) QList<QmlObject>(o.array);
1459 }
1460 return *this;
1461}
1462
1464{
1465 switch (kind) {
1467 break;
1469 return binding.copy(&object);
1471 return binding.subOwnerItem(PathEls::Field(Fields::value), scriptExpression);
1473 return binding.subListItem(List::fromQListRef<QmlObject>(
1474 binding.pathFromOwner().field(u"value"), array,
1475 [binding](DomItem &self, const PathEls::PathComponent &, QmlObject &obj) {
1476 return self.copy(&obj);
1477 }));
1478 }
1479 return DomItem();
1480}
1481
1483{
1484 switch (kind) {
1486 break;
1488 object.updatePathFromOwner(newPath);
1489 break;
1491 break;
1494 break;
1495 }
1496}
1497
1498void BindingValue::clearValue()
1499{
1500 switch (kind) {
1502 break;
1504 object.~QmlObject();
1505 break;
1507 scriptExpression.~shared_ptr();
1508 break;
1510 array.~QList<QmlObject>();
1511 break;
1512 }
1514}
1515
1516ScriptExpression::ScriptExpression(QStringView code, std::shared_ptr<QQmlJS::Engine> engine,
1517 AST::Node *ast, std::shared_ptr<AstComments> comments,
1518 ExpressionType expressionType, SourceLocation localOffset,
1519 int derivedFrom, QStringView preCode, QStringView postCode)
1520 : OwningItem(derivedFrom),
1521 m_expressionType(expressionType),
1522 m_code(code),
1523 m_preCode(preCode),
1524 m_postCode(postCode),
1525 m_engine(engine),
1526 m_ast(ast),
1527 m_astComments(comments),
1528 m_localOffset(localOffset)
1529{
1530 if (m_expressionType == ExpressionType::BindingExpression)
1531 if (AST::ExpressionStatement *exp = AST::cast<AST::ExpressionStatement *>(m_ast))
1532 m_ast = exp->expression;
1533 Q_ASSERT(m_astComments);
1534}
1535
1536ScriptExpression::ScriptExpression(const ScriptExpression &e) : OwningItem(e)
1537{
1538 QMutexLocker l(mutex());
1539 m_expressionType = e.m_expressionType;
1540 m_engine = e.m_engine;
1541 m_ast = e.m_ast;
1542 if (m_codeStr.isEmpty()) {
1543 m_code = e.m_code;
1544 } else {
1545 m_codeStr = e.m_codeStr;
1546 m_code = m_codeStr;
1547 }
1548 m_localOffset = e.m_localOffset;
1549 m_astComments = e.m_astComments;
1550}
1551
1552std::shared_ptr<ScriptExpression> ScriptExpression::copyWithUpdatedCode(DomItem &self,
1553 QString code) const
1554{
1555 std::shared_ptr<ScriptExpression> copy = makeCopy(self);
1556 DomItem container = self.containingObject();
1557 QString preCodeStr = container.field(Fields::preCode).value().toString(m_preCode.toString());
1558 QString postCodeStr = container.field(Fields::postCode).value().toString(m_postCode.toString());
1559 copy->setCode(code, preCodeStr, postCodeStr);
1560 return copy;
1561}
1562
1564{
1565 bool cont = OwningItem::iterateDirectSubpaths(self, visitor);
1566 cont = cont && self.dvValueField(visitor, Fields::code, code());
1567 if (!preCode().isEmpty())
1568 cont = cont
1569 && self.dvValueField(visitor, Fields::preCode, preCode(),
1571 if (!postCode().isEmpty())
1572 cont = cont
1573 && self.dvValueField(visitor, Fields::postCode, postCode(),
1575 cont = cont
1576 && self.dvValueLazyField(
1577 visitor, Fields::localOffset,
1578 [this]() { return locationToData(localOffset()); },
1580 cont = cont && self.dvValueLazyField(visitor, Fields::astRelocatableDump, [this]() {
1581 return astRelocatableDump();
1582 });
1583 cont = cont && self.dvValueField(visitor, Fields::expressionType, int(expressionType()));
1584 if (m_element) {
1585 cont = cont && self.dvItemField(visitor, Fields::scriptElement, [this, &self]() {
1586 return self.subScriptElementWrapperItem(m_element);
1587 });
1588 }
1589 return cont;
1590}
1591
1592class FirstNodeVisitor : public VisitAll
1593{
1594public:
1595 quint32 minStart = 0;
1596 quint32 maxEnd = std::numeric_limits<quint32>::max();
1597 AST::Node *firstNodeInRange = nullptr;
1598
1599 FirstNodeVisitor(quint32 minStart = 0, quint32 maxEnd = std::numeric_limits<quint32>::max())
1600 : minStart(minStart), maxEnd(maxEnd)
1601 {
1602 }
1603
1604 bool preVisit(AST::Node *n) override
1605 {
1606 if (!VisitAll::uiKinds().contains(n->kind)) {
1607 quint32 start = n->firstSourceLocation().begin();
1608 quint32 end = n->lastSourceLocation().end();
1609 if (!firstNodeInRange && minStart <= start && end <= maxEnd && start < end)
1610 firstNodeInRange = n;
1611 }
1612 return !firstNodeInRange;
1613 }
1614};
1615
1616AST::Node *firstNodeInRange(AST::Node *n, quint32 minStart = 0, quint32 maxEnd = ~quint32(0))
1617{
1618 FirstNodeVisitor visitor(minStart, maxEnd);
1619 AST::Node::accept(n, &visitor);
1620 return visitor.firstNodeInRange;
1621}
1622
1623void ScriptExpression::setCode(QString code, QString preCode, QString postCode)
1624{
1625 m_codeStr = code;
1626 const bool qmlMode = (m_expressionType == ExpressionType::BindingExpression);
1627 if (qmlMode && preCode.isEmpty()) {
1628 preCode = Binding::preCodeForName(u"binding");
1629 postCode = Binding::postCodeForName(u"binding");
1630 }
1631 if (!preCode.isEmpty() || !postCode.isEmpty())
1632 m_codeStr = preCode + code + postCode;
1633 m_code = QStringView(m_codeStr).mid(preCode.size(), code.size());
1634 m_preCode = QStringView(m_codeStr).mid(0, preCode.size());
1635 m_postCode = QStringView(m_codeStr).mid(preCode.size() + code.size(), postCode.size());
1636 m_engine = nullptr;
1637 m_ast = nullptr;
1638 m_localOffset = SourceLocation();
1639 if (!m_code.isEmpty()) {
1640 IndentInfo preChange(m_preCode, 4);
1641 m_localOffset.offset = m_preCode.size();
1642 m_localOffset.length = m_code.size();
1643 m_localOffset.startColumn = preChange.trailingString.size();
1644 m_localOffset.startLine = preChange.nNewlines;
1645 m_engine = std::make_shared<QQmlJS::Engine>();
1646 m_astComments = std::make_shared<AstComments>(m_engine);
1647 QQmlJS::Lexer lexer(m_engine.get());
1648 lexer.setCode(m_codeStr, /*lineno = */ 1, /*qmlMode=*/true);
1649 QQmlJS::Parser parser(m_engine.get());
1650 if ((qmlMode && !parser.parse()) || (!qmlMode && !parser.parseScript()))
1651 addErrorLocal(domParsingErrors().error(tr("Parsing of code failed")));
1652 for (DiagnosticMessage msg : parser.diagnosticMessages()) {
1654 err.location.offset -= m_localOffset.offset;
1655 err.location.startLine -= m_localOffset.startLine;
1656 if (err.location.startLine == 1)
1657 err.location.startColumn -= m_localOffset.startColumn;
1658 addErrorLocal(err);
1659 }
1660 m_ast = parser.rootNode();
1661 if (AST::Program *programPtr = AST::cast<AST::Program *>(m_ast)) {
1662 m_ast = programPtr->statements;
1663 }
1664 if (!m_preCode.isEmpty())
1665 m_ast = firstNodeInRange(m_ast, m_preCode.size(),
1666 m_preCode.size() + m_code.size());
1667 if (m_expressionType != ExpressionType::FunctionBody) {
1668 if (AST::StatementList *sList = AST::cast<AST::StatementList *>(m_ast)) {
1669 if (!sList->next)
1670 m_ast = sList->statement;
1671 }
1672 }
1673 if (m_expressionType == ExpressionType::BindingExpression)
1674 if (AST::ExpressionStatement *exp = AST::cast<AST::ExpressionStatement *>(m_ast))
1675 m_ast = exp->expression;
1676 AstComments::collectComments(m_engine, m_ast, m_astComments, MutableDomItem(), nullptr);
1677 }
1678}
1679
1680void ScriptExpression::astDumper(Sink s, AstDumperOptions options) const
1681{
1682 astNodeDumper(s, ast(), options, 1, 0, [this](SourceLocation astL) {
1683 SourceLocation l = this->locationToLocal(astL);
1684 return this->code().mid(l.offset, l.length);
1685 });
1686}
1687
1689{
1690 return dumperToString([this](Sink s) {
1692 });
1693}
1694
1695void ScriptExpression::writeOut(DomItem &self, OutWriter &lw) const
1696{
1697 OutWriter *ow = &lw;
1698
1699 std::optional<PendingSourceLocationId> codeLoc;
1700 if (lw.lineWriter.options().updateOptions & LineWriterOptions::Update::Expressions)
1701 codeLoc = lw.lineWriter.startSourceLocation([this, self, ow](SourceLocation myLoc) mutable {
1702 QStringView reformattedCode =
1703 QStringView(ow->writtenStr).mid(myLoc.offset, myLoc.length);
1704 if (reformattedCode != code()) {
1705 std::shared_ptr<ScriptExpression> copy =
1706 copyWithUpdatedCode(self, reformattedCode.toString());
1707 ow->addReformattedScriptExpression(self.canonicalPath(), copy);
1708 }
1709 });
1711 lw, m_astComments,
1712 [this](SourceLocation astL) {
1713 SourceLocation l = this->locationToLocal(astL); // use engine->code() instead?
1714 return this->code().mid(l.offset, l.length);
1715 },
1716 ast());
1717 if (codeLoc)
1718 lw.lineWriter.endSourceLocation(*codeLoc);
1719}
1720
1721SourceLocation ScriptExpression::globalLocation(DomItem &self) const
1722{
1723 if (const FileLocations *fLocPtr = FileLocations::fileLocationsOf(self)) {
1724 return fLocPtr->regions.value(QString(), fLocPtr->fullRegion);
1725 }
1726 return SourceLocation();
1727}
1728
1730{
1731 return typeName.contains(QChar(u'<'));
1732}
1733
1734void PropertyDefinition::writeOut(DomItem &, OutWriter &lw) const
1735{
1736 lw.ensureNewline();
1737 if (isDefaultMember)
1738 lw.writeRegion(u"default").space();
1739 if (isRequired)
1740 lw.writeRegion(u"required").space();
1741 if (isReadonly)
1742 lw.writeRegion(u"readonly").space();
1743 if (!typeName.isEmpty()) {
1744 lw.writeRegion(u"property").space();
1745 lw.writeRegion(u"type", typeName).space();
1746 }
1747 lw.writeRegion(u"name", name);
1748}
1749
1751{
1752 bool cont = AttributeInfo::iterateDirectSubpaths(self, visitor);
1753 cont = cont && self.dvWrapField(visitor, Fields::parameters, parameters);
1754 cont = cont && self.dvValueField(visitor, Fields::methodType, int(methodType));
1755 if (!typeName.isEmpty())
1756 cont = cont && self.dvReferenceField(visitor, Fields::type, typePath(self));
1758 cont = cont && self.dvValueField(visitor, Fields::preCode, preCode(self));
1759 cont = cont && self.dvValueField(visitor, Fields::postCode, postCode(self));
1760 cont = cont && self.dvValueField(visitor, Fields::isConstructor, isConstructor);
1761 }
1762 if (returnType)
1763 cont = cont && self.dvItemField(visitor, Fields::returnType, [this, &self]() {
1764 return self.subOwnerItem(PathEls::Field(Fields::returnType), returnType);
1765 });
1766 if (body)
1767 cont = cont && self.dvItemField(visitor, Fields::body, [this, &self]() {
1768 return self.subOwnerItem(PathEls::Field(Fields::body), body);
1769 });
1770 return cont;
1771}
1772
1774{
1775 QString res;
1776 LineWriter lw([&res](QStringView s) { res.append(s); }, QLatin1String("*preCode*"));
1777 OutWriter ow(lw);
1778 ow.indentNextlines = true;
1779 ow.skipComments = true;
1780 MockObject standinObj(self.pathFromOwner());
1781 DomItem standin = self.copy(&standinObj);
1782 ow.itemStart(standin);
1783 ow.writeRegion(u"function").space().writeRegion(u"name", name);
1784 bool first = true;
1785 ow.writeRegion(u"leftParen", u"(");
1786 for (const MethodParameter &mp : parameters) {
1787 if (first)
1788 first = false;
1789 else
1790 ow.write(u", ");
1791 ow.write(mp.name);
1792 }
1793 ow.writeRegion(u"rightParen", u")");
1794 ow.ensureSpace().writeRegion(u"leftBrace", u"{");
1795 ow.itemEnd(standin);
1796 ow.eof();
1797 return res;
1798}
1799
1801{
1802 return QLatin1String("\n}\n");
1803}
1804
1805void MethodInfo::writeOut(DomItem &self, OutWriter &ow) const
1806{
1807 switch (methodType) {
1808 case MethodType::Signal: {
1809 if (body)
1810 qCWarning(domLog) << "signal should not have a body in" << self.canonicalPath();
1811 ow.writeRegion(u"signal").space().writeRegion(u"name", name);
1812 if (parameters.isEmpty())
1813 return;
1814 bool first = true;
1815 ow.writeRegion(u"leftParen", u"(");
1816 int baseIndent = ow.increaseIndent();
1817 for (DomItem arg : self.field(Fields::parameters).values()) {
1818 if (first)
1819 first = false;
1820 else
1821 ow.write(u", ");
1822 if (const MethodParameter *argPtr = arg.as<MethodParameter>())
1823 argPtr->writeOutSignal(arg, ow);
1824 else
1825 qCWarning(domLog) << "failed to cast to MethodParameter";
1826 }
1827 ow.writeRegion(u"rightParen", u")");
1828 ow.decreaseIndent(1, baseIndent);
1829 return;
1830 } break;
1831 case MethodType::Method: {
1832 ow.writeRegion(u"function").space().writeRegion(u"name", name);
1833 bool first = true;
1834 ow.writeRegion(u"leftParen", u"(");
1835 for (DomItem arg : self.field(Fields::parameters).values()) {
1836 if (first)
1837 first = false;
1838 else
1839 ow.write(u", ");
1840 arg.writeOut(ow);
1841 }
1842 ow.writeRegion(u"rightParen", u")");
1843 if (!typeName.isEmpty()) {
1844 ow.writeRegion(u"colon", u":");
1845 ow.space();
1846 ow.writeRegion(u"returnType", typeName);
1847 }
1848 ow.ensureSpace().writeRegion(u"leftBrace", u"{");
1849 int baseIndent = ow.increaseIndent();
1850 if (DomItem b = self.field(Fields::body)) {
1851 ow.ensureNewline();
1852 b.writeOut(ow);
1853 }
1854 ow.decreaseIndent(1, baseIndent);
1855 ow.ensureNewline().writeRegion(u"rightBrace", u"}");
1856 } break;
1857 }
1858}
1859
1861{
1862 bool cont = true;
1863 cont = cont && self.dvValueField(visitor, Fields::name, name);
1864 if (!typeName.isEmpty()) {
1865 cont = cont
1866 && self.dvReferenceField(visitor, Fields::type, Paths::lookupTypePath(typeName));
1867 cont = cont && self.dvValueField(visitor, Fields::typeName, typeName);
1868 }
1869 cont = cont && self.dvValueField(visitor, Fields::isPointer, isPointer);
1870 cont = cont && self.dvValueField(visitor, Fields::isReadonly, isReadonly);
1871 cont = cont && self.dvValueField(visitor, Fields::isList, isList);
1872 cont = cont && self.dvWrapField(visitor, Fields::defaultValue, defaultValue);
1873 cont = cont && self.dvWrapField(visitor, Fields::value, value);
1874
1875 if (!annotations.isEmpty())
1876 cont = cont && self.dvWrapField(visitor, Fields::annotations, annotations);
1877 cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
1878 return cont;
1879}
1880
1881void MethodParameter::writeOut(DomItem &self, OutWriter &ow) const
1882{
1883 ow.writeRegion(u"name", name);
1884 if (!typeName.isEmpty())
1885 ow.writeRegion(u"colon", u":").space().writeRegion(u"type", typeName);
1886 if (defaultValue) {
1887 ow.space().writeRegion(u"equal", u"=").space();
1888 self.subOwnerItem(PathEls::Field(Fields::defaultValue), defaultValue).writeOut(ow);
1889 }
1890}
1891
1892void MethodParameter::writeOutSignal(DomItem &self, OutWriter &ow) const
1893{
1894 self.writeOutPre(ow);
1895 if (!typeName.isEmpty())
1896 ow.writeRegion(u"type", typeName).space();
1897 ow.writeRegion(u"name", name);
1898 self.writeOutPost(ow);
1899}
1900
1901void Pragma::writeOut(DomItem &, OutWriter &ow) const
1902{
1903 ow.ensureNewline();
1904 ow.writeRegion(u"pragma").space().writeRegion(u"name", name);
1905
1906 bool isFirst = true;
1907 for (const auto &value : values) {
1908 if (isFirst) {
1909 isFirst = false;
1910 ow.writeRegion(u"colon", u": ");
1911 ow.writeRegion(u"values", value);
1912 continue;
1913 }
1914
1915 ow.writeRegion(u"comma", u", ");
1916 ow.writeRegion(u"values", value);
1917 }
1918 ow.ensureNewline();
1919}
1920
1922{
1923 bool cont = true;
1924 cont = cont && self.dvValueField(visitor, Fields::name, name());
1925 cont = cont && self.dvValueField(visitor, Fields::value, value());
1926 cont = cont && self.dvWrapField(visitor, Fields::comments, m_comments);
1927 return cont;
1928}
1929
1930void EnumItem::writeOut(DomItem &self, OutWriter &ow) const
1931{
1932 ow.ensureNewline();
1933 ow.writeRegion(u"name", name());
1934 bool hasDefaultValue = false;
1935 index_type myIndex = self.pathFromOwner().last().headIndex();
1936 if (myIndex == 0)
1937 hasDefaultValue = value() == 0;
1938 else if (myIndex > 0)
1939 hasDefaultValue = value()
1940 == self.container()
1941 .index(myIndex - 1)
1942 .field(Fields::value)
1943 .value()
1944 .toDouble(value())
1945 + 1;
1946 if (!hasDefaultValue) {
1947 QString v = QString::number(value(), 'f', 0);
1948 if (abs(value() - v.toDouble()) > 1.e-10)
1949 v = QString::number(value());
1950 ow.space().writeRegion(u"equal", u"=").space().writeRegion(u"value", v);
1951 }
1952 if (myIndex >= 0 && self.container().indexes() != myIndex + 1)
1953 ow.writeRegion(u"comma", u",");
1954}
1955
1956QmlUri QmlUri::fromString(const QString &str)
1957{
1958 if (str.startsWith(u'"'))
1959 return fromDirectoryString(str.mid(1, str.size() - 2)
1960 .replace(u"\\\""_s, u"\""_s)
1961 .replace(u"\\\\"_s, u"\\"_s));
1962 else
1963 return fromUriString(str);
1964}
1965
1966QmlUri QmlUri::fromUriString(const QString &str)
1967{
1968 QRegularExpression moduleUriRe(QLatin1String(R"(\A\w+(?:\.\w+)*\Z)"));
1969 return QmlUri((moduleUriRe.match(str).hasMatch() ? Kind::ModuleUri : Kind::Invalid), str);
1970}
1971
1973{
1974 QUrl url(str);
1975 if (url.isValid() && url.scheme().size() > 1)
1976 return QmlUri(url);
1977 if (!str.isEmpty()) {
1979 return QmlUri((path.isRelative() ? Kind::RelativePath : Kind::AbsolutePath), str);
1980 }
1981 return {};
1982}
1983
1984bool QmlUri::isValid() const
1985{
1986 return m_kind != Kind::Invalid;
1987}
1988
1989bool QmlUri::isDirectory() const
1990{
1991 switch (m_kind) {
1992 case Kind::Invalid:
1993 case Kind::ModuleUri:
1994 break;
1995 case Kind::DirectoryUrl:
1996 case Kind::RelativePath:
1997 case Kind::AbsolutePath:
1998 return true;
1999 }
2000 return false;
2001}
2002
2003bool QmlUri::isModule() const
2004{
2005 return m_kind == Kind::ModuleUri;
2006}
2007
2009{
2010 if (m_kind == Kind::ModuleUri)
2011 return std::get<QString>(m_value);
2012 return QString();
2013}
2014
2016{
2017 switch (m_kind) {
2018 case Kind::Invalid:
2019 case Kind::ModuleUri:
2020 break;
2021 case Kind::DirectoryUrl: {
2022 const QUrl &url = std::get<QUrl>(m_value);
2023 if (url.scheme().compare(u"file", Qt::CaseInsensitive) == 0)
2024 return url.path();
2025 break;
2026 }
2027 case Kind::RelativePath:
2028 case Kind::AbsolutePath:
2029 return std::get<QString>(m_value);
2030 }
2031 return QString();
2032}
2033
2034QString QmlUri::absoluteLocalPath(const QString &basePath) const
2035{
2036 switch (m_kind) {
2037 case Kind::Invalid:
2038 case Kind::ModuleUri:
2039 break;
2040 case Kind::DirectoryUrl: {
2041 const QUrl &url = std::get<QUrl>(m_value);
2042 if (url.scheme().compare(u"file", Qt::CaseInsensitive) == 0)
2043 return url.path();
2044 break;
2045 }
2046 case Kind::RelativePath: {
2047 if (!basePath.isEmpty())
2048 return QDir(basePath).filePath(std::get<QString>(m_value));
2049 break;
2050 }
2051 case Kind::AbsolutePath:
2052 return std::get<QString>(m_value);
2053 }
2054 return QString();
2055}
2056
2058{
2059 if (m_kind == Kind::DirectoryUrl)
2060 return std::get<QUrl>(m_value);
2061 return QUrl {};
2062}
2063
2065{
2066 switch (m_kind) {
2067 case Kind::Invalid:
2068 case Kind::ModuleUri:
2069 break;
2070 case Kind::DirectoryUrl:
2071 return std::get<QUrl>(m_value).toString(); // set formatting? options?
2072 case Kind::RelativePath:
2073 case Kind::AbsolutePath:
2074 return std::get<QString>(m_value);
2075 }
2076 return QString();
2077}
2078
2080{
2081 switch (m_kind) {
2082 case Kind::Invalid:
2083 break;
2084 case Kind::ModuleUri:
2085 return std::get<QString>(m_value);
2086 case Kind::DirectoryUrl:
2087 case Kind::RelativePath:
2088 case Kind::AbsolutePath:
2089 return u"\""_s + directoryString().replace(u'\\', u"\\\\"_s).replace(u'"', u"\\\""_s)
2090 + u"\""_s;
2091 }
2092 return QString();
2093}
2094
2096{
2097 return m_kind;
2098}
2099
2100void ScriptExpression::setScriptElement(const ScriptElementVariant &p)
2101{
2102 m_element = p;
2103}
2104
2105} // end namespace Dom
2106} // end namespace QQmlJS
2107
2109
2110#include "moc_qqmldomelements_p.cpp"
static JNINativeMethod methods[]
Definition main.cpp:8
\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
Definition qdir.h:19
QString filePath(const QString &fileName) const
Returns the path name of a file in the directory.
Definition qdir.cpp:778
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
Definition qlist.h:74
iterator end()
Definition qlist.h:609
iterator begin()
Definition qlist.h:608
void append(parameter_type t)
Definition qlist.h:441
Key key(const T &value, const Key &defaultKey=Key()) const
Definition qmap.h:348
\inmodule QtCore
Definition qmutex.h:317
void accept(BaseVisitor *visitor)
static void collectComments(MutableDomItem &item)
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
void updatePathFromOwner(Path newPath)
Path addAnnotation(Path selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr=nullptr)
DomItem value(DomItem &binding)
void updatePathFromOwner(Path newPath)
BindingValue & operator=(const BindingValue &o)
std::shared_ptr< ScriptExpression > scriptExpression
std::shared_ptr< ScriptExpression > scriptExpressionValue() const
Binding & operator=(const Binding &)
Path addAnnotation(Path selfPathFromOwner, const QmlObject &a, QmlObject **aPtr=nullptr)
static QString preCodeForName(QStringView n)
Binding(QString m_name=QString(), std::unique_ptr< BindingValue > value=std::unique_ptr< BindingValue >(), BindingType bindingType=BindingType::Normal)
QmlObject const * objectValue() const
QList< QmlObject > const * arrayValue() const
static QString postCodeForName(QStringView)
void writeOutValue(DomItem &self, OutWriter &lw) const
DomItem valueItem(DomItem &self) const
BindingValueKind valueKind() const
void updatePathFromOwner(Path newPath)
bool iterateDirectSubpaths(DomItem &self, DirectVisitor)
void writeOut(DomItem &self, OutWriter &lw) const
bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override
Path addObject(const QmlObject &object, QmlObject **oPtr=nullptr)
bool iterateDirectSubpaths(DomItem &, DirectVisitor) override
Path attachedTypePath(DomItem &) const
DomItem field(DomItem &self, QStringView name) const override
void updatePathFromOwner(Path newPath) override
QString attachedTypeName() const
virtual DomItem field(DomItem &self, QStringView name) const
virtual void updatePathFromOwner(Path newPath)
static ErrorGroup domErrorGroup
const QList< QmlObject > & annotations() const &
void setAnnotations(QList< QmlObject > annotations)
void updatePathFromOwner(Path newP) override
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override
Path addAnnotation(const QmlObject &child, QmlObject **cPtr=nullptr)
void writeOut(DomItem &self, OutWriter &lw) const override
void writeOut(DomItem &self, OutWriter &lw) const
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
Represents a set of tags grouping a set of related error messages.
ErrorMessage warning(QString message) const
ErrorMessage errorMessage(Dumper msg, ErrorLevel level, Path element=Path(), QString canonicalFilePath=QString(), SourceLocation location=SourceLocation()) const
ErrorMessage error(QString message) const
ErrorMessage handle(const ErrorHandler &errorHandler=nullptr)
static Export fromString(Path source, QStringView exp, Path typePath, ErrorHandler h)
static const FileLocations * fileLocationsOf(DomItem &)
RegionComments comments
Path addAnnotation(Path selfPathFromOwner, const QmlObject &ann, QmlObject **aPtr=nullptr)
bool iterateDirectSubpaths(DomItem &self, DirectVisitor)
void updatePathFromOwner(Path pathFromOwner)
Id(QString idName=QString(), Path referredObject=Path())
QList< QmlObject > annotations
QList< Path > allSources(DomItem &self) const
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
QList< DomItem > importedItemsWithName(DomItem &self, QString name) const
QSet< QString > importedNames(DomItem &self) const
bool iterateDirectSubpaths(DomItem &self, DirectVisitor)
static Import fromUriString(QString importStr, Version v=Version(), QString importId=QString(), ErrorHandler handler=nullptr)
static QRegularExpression importRe()
void writeOut(DomItem &self, OutWriter &ow) const
static Import fromFileString(QString importStr, QString importId=QString(), ErrorHandler handler=nullptr)
std::shared_ptr< ScriptExpression > body
void writeOut(DomItem &self, OutWriter &ow) const
QList< MethodParameter > parameters
QString postCode(DomItem &) const
std::shared_ptr< ScriptExpression > returnType
Path typePath(DomItem &) const
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
QString preCode(DomItem &) const
void writeOut(DomItem &self, OutWriter &ow) const
std::shared_ptr< ScriptExpression > defaultValue
void writeOutSignal(DomItem &self, OutWriter &ow) const
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
OutWriter & ensureNewline(int nNewlines=1)
OutWriter & writeRegion(QString rName, QStringView toWrite)
void addErrorLocal(ErrorMessage msg)
bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override
static Path Root(PathRoot r)
Path key(QString name) const
static ErrorGroups myErrors()
Path field(QString name) const
void writeOut(DomItem &self, OutWriter &ow) const
void writeOut(DomItem &self, OutWriter &lw) const
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
void writeOut(DomItem &self, OutWriter &) const override
bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override
void updatePathFromOwner(Path newPath) override
QList< QString > subComponentsNames(DomItem &self) const
QList< DomItem > subComponents(DomItem &self) const
QmlObject(Path pathFromOwner=Path())
const QList< Path > & prototypePaths() const &
DomItem field(DomItem &self, QStringView name)
QString localDefaultPropertyName() const
bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override
bool iterateBaseDirectSubpaths(DomItem &self, DirectVisitor)
QList< QString > fields() const
void updatePathFromOwner(Path newPath) override
QString defaultPropertyName(DomItem &self) const
Kind kind() const
QString absoluteLocalPath(const QString &basePath=QString()) const
static QmlUri fromDirectoryString(const QString &importStr)
QUrl directoryUrl() const
QString directoryString() const
static QmlUri fromUriString(const QString &importStr)
bool isValid() const
QString toString() const
bool isDirectory() const
QString localPath() const
bool isModule() const
static QmlUri fromString(const QString &importStr)
QString moduleUri() const
bool iterateDirectSubpaths(DomItem &, DirectVisitor) override
static bool addForPath(DomItem &el, Path canonicalPath, const RefCacheEntry &entry, AddOption addOption=AddOption::KeepExisting)
static RefCacheEntry forPath(DomItem &el, Path canonicalPath)
std::shared_ptr< ScriptExpression > makeCopy(DomItem &self) const
std::shared_ptr< ScriptExpression > copyWithUpdatedCode(DomItem &self, QString code) const
ExpressionType expressionType() const
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override
QString astRelocatableDump() const
void setScriptElement(const ScriptElementVariant &p)
void astDumper(Sink s, AstDumperOptions options) const
SourceLocation locationToLocal(SourceLocation x) const
SourceLocation localOffset() const
SourceLocation globalLocation(DomItem &self) const
void writeOut(DomItem &self, OutWriter &lw) const override
Version(qint32 majorVersion=Undefined, qint32 minorVersion=Undefined)
bool iterateDirectSubpaths(DomItem &self, DirectVisitor)
QString minorString() const
static Version fromString(QStringView v)
QString stringValue() const
static constexpr qint32 Undefined
static constexpr qint32 Latest
QString majorSymbolicString() const
Represents an immutable JsonPath like path in the Qml code model (from a DomItem to another DomItem)
\inmodule QtCore \reentrant
QRegularExpressionMatch match(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
Attempts to match the regular expression against the given subject string, starting at the position o...
static QString anchoredPattern(const QString &expression)
Definition qset.h:18
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
constexpr bool isEmpty() const noexcept
Returns whether this string view is empty - that is, whether {size() == 0}.
constexpr qsizetype size() const noexcept
Returns the size of this string view, in UTF-16 code units (that is, surrogate pairs count as two for...
constexpr QStringView first(qsizetype n) const noexcept
constexpr QStringView left(qsizetype n) const noexcept
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1014
constexpr QStringView last(qsizetype n) const noexcept
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
const_iterator end() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary character after...
qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
double toDouble(bool *ok=nullptr) const
Returns the string converted to a double value.
Definition qstring.cpp:7642
QString last(qsizetype n) const
Definition qstring.h:339
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
static QString fromUtf16(const char16_t *, qsizetype size=-1)
Definition qstring.cpp:5883
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
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
QString first(qsizetype n) const
Definition qstring.h:337
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.cpp:6498
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1217
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
\inmodule QtCore
Definition qurl.h:94
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
Definition qurl.cpp:1874
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1983
QString path(ComponentFormattingOptions options=FullyDecoded) const
Returns the path of the URL.
Definition qurl.cpp:2465
QString str
[2]
QMap< QString, QString > map
[6]
double e
Path moduleScopePath(QString uri, Version version, ErrorHandler)
Path lookupTypePath(QString name)
Path moduleIndexPath(QString uri, int majorVersion, ErrorHandler errorHandler)
void astNodeDumper(Sink s, Node *n, AstDumperOptions opt, int indent, int baseIndent, function_ref< QStringView(SourceLocation)>loc2str)
static ErrorGroups domParsingErrors()
function_ref< void(QStringView)> Sink
std::function< void(const ErrorMessage &)> ErrorHandler
qint64 index_type
void reformatAst(OutWriter &lw, std::shared_ptr< AstComments > comments, const std::function< QStringView(SourceLocation)> loc2Str, AST::Node *n)
function_ref< bool(const PathEls::PathComponent &, function_ref< DomItem()>)> DirectVisitor
QMLDOM_EXPORT QCborValue locationToData(SourceLocation loc, QStringView strValue=u"")
void updatePathFromOwnerQList(QList< T > &list, Path newPath)
QString dumperToString(Dumper writer)
Converts a dumper to a string.
void updatePathFromOwnerMultiMap(QMultiMap< K, T > &mmap, Path newPath)
Path appendUpdatableElementInQList(Path listPathFromOwner, QList< T > &list, const T &value, T **vPtr=nullptr)
Combined button and popup list for selecting options.
@ CaseInsensitive
QString self
Definition language.cpp:57
static jboolean copy(JNIEnv *, jobject)
DBusConnection const char DBusError * error
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 int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qWarning
Definition qlogging.h:162
#define qCWarning(category,...)
#define qCDebug(category,...)
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLenum GLsizei GLsizei GLint * values
[15]
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLuint64 key
GLint GLenum GLint components
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint id
[7]
GLdouble GLdouble GLdouble GLdouble top
GLuint object
[3]
GLenum access
GLuint start
GLuint name
GLint first
GLfloat n
GLfloat GLfloat GLfloat GLfloat h
GLuint counter
GLsizei GLsizei GLchar * source
GLhandleARB obj
[2]
GLuint res
const GLubyte * c
GLenum array
GLsizei const GLchar *const * path
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLuint GLenum option
const GLint * attribs
static qreal component(const QPointF &point, unsigned int i)
#define NewErrorGroup(name)
static QQmlJSUtils::ResolvedAlias resolveAlias(ScopeForId scopeForId, const QQmlJSMetaProperty &property, const QQmlJSScope::ConstPtr &owner, const QQmlJSUtils::AliasResolutionVisitor &visitor)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static void split(QT_FT_Vector *b)
BindingType
SSL_CTX int(*) void arg)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define tr(X)
unsigned int quint32
Definition qtypes.h:45
int qint32
Definition qtypes.h:44
ptrdiff_t qsizetype
Definition qtypes.h:70
QList< int > list
[14]
if(qFloatDistance(a, b)<(1<< 7))
[0]
QUrl url("example.com")
[constructor-url-reference]
QMutex mutex
[2]
QJSEngine engine
[0]
QStringView el
\inmodule QtCore \reentrant
Definition qchar.h:17
IUIAutomation __RPC__in_opt IUIAutomationElement * el2