20#include <qqmldomlinewriterfactory_p.h>
22#include <QtQml/private/qqmljslexer_p.h>
23#include <QtQml/private/qqmljsparser_p.h>
24#include <QtQml/private/qqmljsengine_p.h>
25#include <QtQml/private/qqmljsastvisitor_p.h>
26#include <QtQml/private/qqmljsast_p.h>
28#include <QtCore/QCborArray>
29#include <QtCore/QCborMap>
30#include <QtCore/QDebug>
32#include <QtCore/QFile>
33#include <QtCore/QFileInfo>
34#include <QtCore/QJsonDocument>
35#include <QtCore/QJsonValue>
36#include <QtCore/QMutexLocker>
37#include <QtCore/QRegularExpression>
38#include <QtCore/QScopeGuard>
39#include <QtCore/QtGlobal>
40#include <QtCore/QTimeZone>
47Q_LOGGING_CATEGORY(writeOutLog,
"qt.qmldom.writeOut", QtWarningMsg);
53template<
class... TypeList>
62
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
80 "Types in ElementT must either be a pointer to a class inheriting "
81 "from DomBase or (for internal Dom structures) implement a smart "
82 "pointer pointing to a class inheriting from DomBase");
86
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
138 static QMap<DomType,QString> map = [](){
139 QMetaEnum metaEnum = QMetaEnum::fromType<DomType>();
140 QMap<DomType,QString> res;
141 for (
int i = 0; i < metaEnum.keyCount(); ++ i) {
142 res[DomType(metaEnum.value(i))] = QString::fromUtf8(metaEnum.key(i));
151 QString res = domTypeToStringMap().value(k);
153 return QString::number(
int(k));
160 static QMap<DomKind, QString> map = []() {
161 QMetaEnum metaEnum = QMetaEnum::fromType<DomKind>();
162 QMap<DomKind, QString> res;
163 for (
int i = 0; i < metaEnum.keyCount(); ++i) {
164 res[DomKind(metaEnum.value(i))] = QString::fromUtf8(metaEnum.key(i));
173 return domKindToStringMap().value(k, QString::number(
int(k)));
231 return parent.canonicalFilePath();
237 qCWarning(writeOutLog) <<
"Ignoring unsupported writeOut for " << domTypeToString(kind()) <<
":"
238 << self.canonicalPath();
247 static QHash<QString, QString> knownFields;
248 static QBasicMutex m;
249 auto toField = [](
const QString &f) -> QStringView {
251 if (!knownFields.contains(f))
253 return knownFields[f];
255 if (m_value.isMap()) {
256 QCborMap map = m_value.toMap();
257 auto it = map.cbegin();
258 auto end = map.cend();
260 QString key = it.key().toString();
267 comp =
PathEls::Field(toField(key));
270 auto val = it.value();
271 if (!self.invokeVisitorOnValue(visitor, comp, val))
276 }
else if (m_value.isArray()){
277 QCborArray array = m_value.toArray();
278 auto it = array.cbegin();
279 auto end = array.cend();
282 if (!self.invokeVisitorOnValue(visitor,
PathEls::Index(i++), *it++))
298 if (m_value.isMap()) {
300 case ConstantData::Options::MapIsMap:
302 case ConstantData::Options::FirstMapIsFields:
303 return DomKind::Object;
306 if (m_value.isArray())
307 return DomKind::List;
308 return DomKind::Value;
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
347 const QString &canonicalPath,
const QString &logicalPath,
357 const QString &path,
const QString &code)
359 const QString canonicalPath = QFileInfo(path).canonicalFilePath();
364 canonicalPath.isEmpty() ? path : canonicalPath,
374 const QString canonicalPath = QFileInfo(path).canonicalFilePath();
400 Path res = visitEl([
this](
auto &&el) {
return el->canonicalPath(*
this); });
402 qCWarning(domLog) <<
"non anchored canonical path:" << res.toString();
411 return visitEl([
this](
auto &&el) {
return el->containingObject(*
this); });
415
416
417
418
419
422 if (
DomItem res = filterUp([](DomType k,
const DomItem &) {
return k == DomType::QmlObject; },
425 if (options == GoTo::MostLikely) {
426 if (
DomItem comp = component(options))
427 return comp.field(Fields::objects).index(0);
440 if (k == DomType::ExternalItemInfo || (options == GoTo::MostLikely && k == DomType::ExternalItemPair))
441 return field(Fields::currentItem);
456 return qmlObject(options, FilterUpOptions::ReturnInner);
465 if (s.pathFromSource.length() > 1)
471
472
473
478 return std::visit([
this](
auto &&el) {
479 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
482 return DomItem(
this->m_top, el,
this->m_ownerPath, el.get());
490 return std::visit([](
auto &&el) {
491 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
512 return res.field(Fields::universe);
517
518
519
520
521
524 if (
DomItem res = filterUp([](DomType k,
const DomItem &) {
return k == DomType::ScriptExpression; },
525 FilterUpOptions::ReturnOuter))
531
532
533
534
535
538 if (
DomItem res = filterUp([](DomType k,
const DomItem &) {
return k == DomType::QmlFile; },
539 FilterUpOptions::ReturnOuter))
545
546
547
548
551 Q_UNUSED(canonicalPath);
553 top().field(Fields::qmlFileWithPath).key(canonicalPath).field(Fields::currentItem);
558
559
560
573
574
575
582
583
584
585
607 current = current
.path(currentPath
);
619 DomItem res = filterUp([](DomType,
const DomItem &el) {
return el.isScope(); }, options);
625 QQmlJSScope::ConstPtr scope;
626 visitUp([&scope](
const DomItem &item) {
627 scope = item.semanticScope();
635 QQmlJSScope::ConstPtr scope = std::visit(
636 [](
auto &&e) -> QQmlJSScope::ConstPtr {
637 using T = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
638 if constexpr (std::is_same_v<T,
const QmlObject *>) {
639 return e->semanticScope();
640 }
else if constexpr (std::is_same_v<T,
const QmlComponent *>) {
641 return e->semanticScope();
642 }
else if constexpr (std::is_same_v<T, SimpleObjectWrap>) {
643 if (
const MethodInfo *mi = e->
template as<MethodInfo>()) {
644 return mi->semanticScope();
646 if (
const auto *propertyDefinition = e->
template as<PropertyDefinition>()) {
647 return propertyDefinition->semanticScope();
649 }
else if constexpr (std::is_same_v<T, ScriptElementDomWrapper>) {
650 return e.element().base()->semanticScope();
661 return refPtr->get(*
this, h, visitedRefs);
668 return refPtr->getAll(*
this, h, visitedRefs);
675 visitPrototypeChain([&pInfo, name](
const DomItem &obj) {
676 return obj.visitLocalSymbolsNamed(name, [&pInfo, name](
const DomItem &el) {
677 switch (el.internalKind()) {
678 case DomType::Binding:
679 pInfo.bindings.append(el);
681 case DomType::PropertyDefinition:
682 pInfo.propertyDefs.append(el);
696 visitPrototypeChain([&res](
const DomItem &obj) {
697 res += obj.propertyDefs().keys();
698 res += obj.bindings().keys();
707 [](DomType kind,
const DomItem &) {
708 return kind == DomType::QmlComponent || kind == DomType::GlobalComponent;
710 FilterUpOptions::ReturnInner))
712 if (options == GoTo::MostLikely) {
720 case DomType::ExternalItemPair:
721 case DomType::ExternalItemInfo:
722 item = fileObject(options);
725 return item.field(Fields::components).key(QString()).index(0);
740 static auto map = []() {
741 QMetaEnum metaEnum = QMetaEnum::fromType<LookupType>();
742 QMap<QString, LookupType> res;
743 for (
int i = 0; i < metaEnum.keyCount(); ++i) {
744 res[QString::fromUtf8(metaEnum.key(i)).toLower()] = LookupType(metaEnum.value(i));
770
771
772
773
774
778 if (visitedRefs->contains(refRef)) {
780 .error([visitedRefs, refRef](
const Sink &sink) {
781 const QString msg = DomItem::tr(
"Circular reference:") + QLatin1Char(
'\n');
782 sink(QStringView{ msg });
783 for (
const Path &vPath : *visitedRefs) {
796 visitedRefs->append(refRef);
799 ref->referredObjectPath,
810 LookupOptions opt = LookupOption::Normal;
811 if (current == PathCurrent::LookupStrict)
812 return opt | LookupOption::Strict;
816 DomItem strict = comp.field(u"~strictLookup~");
819 strict = env.field(u"defaultStrictLookup");
821 if (strict && strict.value().toBool())
822 opt = opt | LookupOption::Strict;
829 const auto &map = stringToLookupTypeMap();
830 auto it = map.find(expectedType.toLower());
837 ResolveOptions options,
const Path &fullPath, QList<Path> *visitedRefs)
const
840 Path fPath = fullPath;
844 return visitor(fPath, *
this);
845 QList<QSet<quintptr>> visited(path.length() + 1);
847 QList<ResolveToDo> toDos(1);
852 .error(tr(
"Root context %1 is not known").arg(path.headName())
)
853 .handle(errorHandler);
856 toDos[0] = {std::move(root), 1};
858 toDos[0] = {*
this, 0};
860 while (!toDos.isEmpty()) {
863 auto idNow = toDo.item.id();
864 if (idNow == quintptr(0) && toDo.item == *
this)
865 idNow = quintptr(
this);
866 if (idNow != quintptr(0) && visited[0].contains(idNow))
871 bool branchExhausted =
false;
872 while (iPath < path
.length() && it && !branchExhausted) {
873 auto idNow = it.id();
874 if (idNow == quintptr() && toDo.item == *
this)
875 idNow = quintptr(
this);
876 if (idNow != quintptr(0)) {
877 auto vPair = std::make_pair(idNow, iPath);
878 if (visited[vPair.second].contains(vPair.first))
880 visited[vPair.second].insert(vPair.first);
884 auto cNow = path
[iPath++
];
887 it = it.key(cNow.headName());
891 it = resolveReference(it, it.canonicalPath(),
892 visitedRefs ==
nullptr ? &vRefs : visitedRefs,
893 errorHandler, myResolveErrors());
895 it = it.field(cNow.headName());
899 it = it.index(cNow.headIndex());
903 .error(tr(
"Empty is not supported inside paths")
)
904 .handle(errorHandler);
908 .arg(cNow.toString()).arg(iPath -1).arg(path.toString())
).handle(errorHandler);
917 if (domKind() != DomKind::Object)
925 it = it.component().ids();
928 it = it.component()[Fields::exports];
933 const LookupOptions opt = resolveLookupOptions(current, it);
936 .error(tr(
"Javascript lookups not yet implemented")
)
937 .handle(errorHandler);
941 auto idNow = it.id();
942 if (idNow == quintptr(0) && toDo.item == *
this)
943 idNow = quintptr(
this);
944 if (idNow != quintptr(0)) {
945 auto vPair = std::make_pair(idNow, iPath);
946 if (visited[vPair.second].contains(vPair.first))
948 visited[vPair.second].insert(vPair.first);
954 .error(tr(
"Premature end of path, expected a field specifying the "
955 "type, and a key specifying the name to search after a "
956 "lookup directive in %2")
957 .arg(path.toString())
)
958 .handle(errorHandler);
961 Path cNow = path
[iPath++
];
964 .error(tr(
"Expected a key path specifying the type to search after "
965 "a lookup directive, not %1 at component %2 of %3")
966 .arg(cNow.toString())
968 .arg(path.toString())
)
969 .handle(errorHandler);
972 QString expectedType = cNow.headName();
973 auto lookupType = lookupTypeFromString(expectedType);
976 .error(tr(
"Type for lookup was expected to be one of '%1', not "
978 .arg(stringToLookupTypeMap().keys().join(
", "_L1),
980 .handle(errorHandler);
983 cNow = path
[iPath++
];
986 .error(tr(
"Expected a key specifying the path to search after the "
987 "@lookup directive and type, not %1 at component %2 of "
989 .arg(cNow.toString())
991 .arg(path.toString())
)
992 .handle(errorHandler);
995 QString target = cNow.headName();
996 if (target.isEmpty()) {
998 .warning(tr(
"Path with empty lookup at component %1 of %2 will "
999 "match nothing in %3.")
1001 .arg(path.toString())
1003 .handle(errorHandler);
1008 [&toDos, iPath](
const DomItem &subEl) {
1009 toDos.append({ subEl, iPath });
1012 *(
std::move(lookupType)), opt, errorHandler, &(visited[iPath]),
1014 branchExhausted =
true;
1020 case Path::Kind::Any:
1023 [&toDos, iPath](Path,
const DomItem &item,
bool) {
1024 toDos.append({ item, iPath });
1027 VisitOption::VisitSelf | VisitOption::Recurse | VisitOption::VisitAdopted);
1028 branchExhausted =
true;
1032 branchExhausted =
true;
1037 if (!branchExhausted && iPath == path
.length() && !visitor(fPath, it))
1048 resolve(p, [&res](
const Path &,
const DomItem &it) {
1067 return visitEl([
this](
auto &&el) {
return el->fields(*
this); });
1072 return visitEl([
this, name](
auto &&el) {
return el->field(*
this, name); });
1077 return visitEl([
this](
auto &&el) {
return el->indexes(*
this); });
1082 return visitEl([
this, i](
auto &&el) {
return el->index(*
this, i); });
1088 int nIndexes = indexes();
1089 for (
int i = 0; i < nIndexes; ++i) {
1099 return visitEl([
this](
auto &&el) {
return el->keys(*
this); });
1104 QSet<QString> ks = keys();
1105 QStringList sortedKs(ks.begin(), ks.end());
1106 std::sort(sortedKs.begin(), sortedKs.end());
1112 return visitEl([
this, name](
auto &&el) {
return el->key(*
this, name); });
1118 const QStringList keys = sortedKeys();
1119 for (
const QString &k : keys) {
1130 iterateDirectSubpaths([&res](
const PathEls::PathComponent &, function_ref<DomItem()> item) {
1140 DomItem anns = field(Fields::annotations);
1141 for (
const auto &ann : anns.values()) {
1142 if (ann.annotations().indexes() == 0) {
1147 DomItem annAnn = ann.annotations();
1148 Q_ASSERT_X(annAnn.indexes() == 1 && annAnn.index(0).name() == u"duplicate",
1149 "DomItem::writeOutPre",
"Unexpected annotation of annotation");
1153 ow.itemStart(*
this);
1159 visitEl([
this, &ow](
auto &&el) { el->writeOut(*
this, ow); });
1170 WriteOutChecks extraChecks)
const
1172 auto compare = [
this](
const DomItem &obj1,
const DomItem &obj2, QStringView obj2Name,
1174 const auto diffList = domCompareStrList(obj1, obj2, filter, DomCompareStrList::AllDiffs);
1175 if (!diffList.isEmpty()) {
1176 qCWarning(writeOutLog).noquote().nospace()
1177 << obj2Name <<
" writeOut of " <<
this->canonicalFilePath() <<
" has changes:\n"
1178 << diffList.join(QString());
1183 auto checkStability = [&ow,
this](
const QString &expected,
const DomItem &obj,
1184 QStringView objName) {
1187 ow2.indentNextlines =
true;
1190 if (ow2.writtenStr != expected) {
1191 qCWarning(writeOutLog).noquote().nospace()
1192 << objName <<
" non stable writeOut of " <<
this->canonicalFilePath() <<
":"
1193 << lineDiff(expected, ow2.writtenStr, 2);
1202 std::shared_ptr<DomEnvironment> newEnvPtr = newEnv.ownerAs<DomEnvironment>();
1204 return WriteOutCheckResult::Failed;
1206 auto newFilePtr =
std::make_shared<QmlFile>(canonicalFilePath(), ow.writtenStr);
1210 if (newFilePtr->isValid()) {
1212 newEnvPtr->populateFromQmlFile(newFile);
1214 && !compare(reformatted, newFile, u"reparsed",
1216 return WriteOutCheckResult::Failed;
1218 checkStability(ow.writtenStr, newFile, u"reparsed");
1221 const auto iterateErrors = [&newFile](
const Sink &s) {
1222 newFile.iterateErrors(
1231 qCWarning(writeOutLog).noquote().nospace()
1232 <<
"writeOut of " << canonicalFilePath()
1233 <<
" created invalid code:\n----------\n"
1234 << ow.writtenStr <<
"\n----------" << iterateErrors;
1235 return WriteOutCheckResult::Failed;
1238 return WriteOutCheckResult::Success;
1242
1243
1244
1245
1246
1247
1248
1249
1250
1253 ow.indentNextlines =
true;
1254 auto currentFileItem = fileObject();
1257 WriteOutCheckResult result = WriteOutCheckResult::Success;
1259 result = performWriteOutChecks(currentFileItem, ow, extraChecks);
1260 return result == WriteOutCheckResult::Success ?
bool(currentFileItem) :
false;
1264 WriteOutChecks extraChecks)
const
1269 auto status = fw->write(path, [
this, path, &options, extraChecks](QTextStream &ts) {
1270 auto lw = createLineWriter([&ts](QStringView s) { ts << s; }, path, options);
1271 OutWriter ow(getFileItemOwner(fileObject()), *lw);
1272 return writeOutForFile(ow, extraChecks);
1275 case FileWriter::Status::DidWrite:
1276 case FileWriter::Status::SkippedEqual:
1278 case FileWriter::Status::ShouldWrite:
1279 case FileWriter::Status::SkippedDueToFailure:
1280 qCWarning(writeOutLog) <<
"failure reformatting " << path;
1283 qCWarning(writeOutLog) <<
"Unknown FileWriter::Status ";
1291 bool isChild =
false;
1304 bool hasAnnotations =
false;
1308 if (
const Id *myPtr = as<
Id>())
1309 hasAnnotations = !myPtr->annotations.isEmpty();
1313 hasAnnotations = !myPtr->annotations.isEmpty();
1317 hasAnnotations = !myPtr->annotations.isEmpty();
1321 hasAnnotations = !myPtr->annotations().isEmpty();
1325 hasAnnotations = !myPtr->annotations().isEmpty();
1330 return hasAnnotations;
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1356 VisitOptions options, DomItem::ChildrenVisitor openingVisitor,
1357 DomItem::ChildrenVisitor closingVisitor,
const FieldFilter &filter)
const
1361 if (options & VisitOption::VisitSelf && !visitor(basePath, *
this,
true))
1363 if (options & VisitOption::VisitSelf && !openingVisitor(basePath, *
this,
true))
1365 auto atEnd = qScopeGuard([closingVisitor, basePath,
this, options]() {
1366 if (options & VisitOption::VisitSelf) {
1367 closingVisitor(basePath, *
this,
true);
1370 return iterateDirectSubpaths(
1371 [
this, basePath, visitor, openingVisitor, closingVisitor, options,
1372 &filter](
const PathEls::PathComponent &c, function_ref<DomItem()> itemF) {
1374 if (!(options & VisitOption::NoPath)) {
1376 pNow = pNow.withComponent(c);
1378 if (!filter(*
this, c, DomItem{}))
1380 DomItem item = itemF();
1381 bool directChild = isCanonicalChild(item);
1382 if (!directChild && !(options & VisitOption::VisitAdopted))
1384 if (!directChild || !(options & VisitOption::Recurse)) {
1385 if (!visitor(pNow, item, directChild))
1390 if (!openingVisitor(pNow, item, directChild))
1392 closingVisitor(pNow, item, directChild);
1394 return item.visitTree(pNow, visitor, options | VisitOption::VisitSelf,
1395 openingVisitor, closingVisitor, filter);
1402 QList<Path> *visitedRefs, VisitPrototypesOptions options,
1406 if (visitedRefs->contains(elId))
1409 visitedRefs->append(elId);
1410 QList<DomItem> protos = prototype.getAll(h, visitedRefs);
1411 if (protos.isEmpty()) {
1412 if (std::shared_ptr<DomEnvironment> envPtr =
1413 derivedFromPrototype.environment().ownerAs<DomEnvironment>())
1416 .warning(derivedFromPrototype.tr(
"could not resolve prototype %1 (%2)")
1418 prototype.field(Fields::referredObjectPath)
1421 .withItem(derivedFromPrototype)
1424 if (protos.size() > 1) {
1425 QStringList protoPaths;
1426 for (
const DomItem &p : protos)
1427 protoPaths.append(p.canonicalPath().toString());
1430 .tr(
"Multiple definitions found, using first only, resolving "
1431 "prototype %1 (%2): %3")
1433 prototype.field(Fields::referredObjectPath)
1436 protoPaths.join(QLatin1String(
", ")))
)
1437 .withItem(derivedFromPrototype)
1442 for (
int i = nProtos; i != 0;) {
1443 DomItem proto = protos.at(--i);
1446 proto = proto.proceedToScope(h, visitedRefs);
1453 .warning(derivedFromPrototype.tr(
"Unexpected prototype type %1 (%2)")
1455 prototype.field(Fields::referredObjectPath)
1458 .withItem(derivedFromPrototype)
1468 QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1470 QSet<quintptr> visitedLocal;
1472 visited = &visitedLocal;
1473 QList<Path> refsLocal;
1475 visitedRefs = &refsLocal;
1477 DomItem current = qmlObject();
1482 QList<DomItem> toDo({ current });
1483 while (!toDo.isEmpty()) {
1484 current = toDo.takeLast();
1485 current = current.proceedToScope(h, visitedRefs);
1486 if (visited->contains(current.id())) {
1492 .warning(tr(
"Detected multiple visit of %1 visiting prototypes of %2")
1499 visited->insert(current.id());
1500 if (shouldVisit && !visitor(current))
1503 current.field(Fields::prototypes)
1504 .visitIndexes([&toDo, ¤t,
this, &h, visitedRefs, options](
const DomItem &el) {
1505 return visitPrototypeIndex(toDo, current, *
this, h, visitedRefs, options, el);
1512 function_ref<
bool(
const DomItem &)> visitor, VisitPrototypesOptions options,
1513 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1518 if (k == DomType::QmlObject)
1519 return visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1520 if (visited && id() != 0) {
1521 if (visited->contains(id()))
1523 visited->insert(id());
1527 DomItem v = proceedToScope(h, visitedRefs);
1529 return v.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1533 DomItem v = field(Fields::value);
1535 return v.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1539 DomItem t = field(Fields::type).proceedToScope(h, visitedRefs);
1541 return t.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1549
1550
1551
1552
1553
1554
1555
1556
1557
1559 function_ref<
bool(
const DomItem &)> visitor, VisitPrototypesOptions options,
1560 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1562 QSet<quintptr> visitedLocal;
1564 visited = &visitedLocal;
1565 DomItem current = qmlObject();
1566 DomItem comp = current.component();
1567 if (comp.field(Fields::isSingleton).value().toBool(
false)
1568 && !current.visitPrototypeChain(visitor, options, h, visited, visitedRefs))
1570 if (
DomItem attachedT = current.component().field(Fields::attachedType).field(Fields::get))
1571 if (!attachedT.visitPrototypeChain(
1573 visited, visitedRefs))
1579
1580
1586 if (!visitor(current))
1594
1595
1597 function_ref<
bool(
const DomItem &)> visitor, LookupOptions options,
const ErrorHandler &h,
1598 QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1600 QSet<quintptr> visitedLocal;
1602 visited = &visitedLocal;
1603 QList<Path> visitedRefsLocal;
1605 visitedRefs = &visitedRefsLocal;
1611 QList<DomItem> toDo { current };
1612 bool visitFirst = !(options & LookupOption::SkipFirstScope);
1613 bool visitCurrent = visitFirst;
1615 QSet<quintptr> alreadyAddedComponentMaps;
1616 while (!toDo.isEmpty()) {
1617 DomItem current = toDo.takeLast();
1618 if (visited->contains(current.id()))
1620 visited->insert(current.id());
1621 if (visitCurrent && !visitor(current))
1623 visitCurrent =
true;
1629 DomItem root = current.rootQmlObject();
1630 if (root && root
!= current) {
1644 if ((options & LookupOption::Strict) == 0) {
1645 if (
DomItem comp = current.field(Fields::nextComponent))
1648 if (first && visitFirst && (options & LookupOption::VisitTopClassType)
1649 && *
this == current) {
1650 if (
DomItem attachedT = current.field(Fields::attachedType).field(Fields::get))
1651 toDo.append(attachedT);
1659 if (alreadyAddedComponentMaps.contains(componentMap.id()))
1661 alreadyAddedComponentMaps.insert(componentMap.id());
1662 const auto keys = componentMap.keys();
1663 for (
const QString &x : keys) {
1664 DomItem componentList = componentMap.key(x);
1665 for (
int i = 0; i < componentList.indexes(); ++i) {
1666 DomItem component = componentList.index(i);
1667 if (component != current && !visited->contains(component.id()))
1668 toDo.append(component);
1676 current.field(Fields::importScope))
1677 toDo.append(iScope);
1688 if (
DomItem next = current.field(Fields::objects).index(0))
1694 .error(tr(
"Unexpected non scope object %1 (%2) reached in visitScopeChain")
1695 .arg(domTypeToString(current.internalKind()),
1706 const QString &symbolName, function_ref<
bool(
const DomItem &)> visitor, LookupOptions opts,
1707 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1709 return visitScopeChain(
1710 [symbolName, visitor](
const DomItem &obj) {
1711 return obj.visitLocalSymbolsNamed(symbolName,
1712 [visitor](
const DomItem &el) {
return visitor(el); });
1714 opts, h, visited, visitedRefs);
1726 QRegularExpression reTarget = QRegularExpression(QRegularExpression::anchoredPattern(
1727 uR"(QList<(?<list>[a-zA-Z_0-9:]+) *(?<listPtr>\*?)>|QMap< *(?<mapKey>[a-zA-Z_0-9:]+) *, *(?<mapValue>[a-zA-Z_0-9:]+) *(?<mapPtr>\*?)>|(?<baseType>[a-zA-Z_0-9:]+) *(?<ptr>\*?))"));
1729 QRegularExpressionMatch m = reTarget.matchView(target);
1730 if (!m.hasMatch()) {
1732 .error(tr(
"Unexpected complex CppType %1").arg(target)
)
1735 res.baseType = m.captured(u"baseType");
1736 res
.isPointer = !m.captured(u"ptr").isEmpty();
1737 if (!m.captured(u"list").isEmpty()) {
1739 res.baseType = m.captured(u"list");
1740 res
.isPointer = !m.captured(u"listPtr").isEmpty();
1742 if (!m.captured(u"mapValue").isEmpty()) {
1744 if (m.captured(u"mapKey") != u"QString") {
1746 .error(tr(
"Unexpected complex CppType %1 (map with non QString key)")
1750 res.baseType = m.captured(u"mapValue");
1751 res
.isPointer = !m.captured(u"mapPtr").isEmpty();
1763 function_ref<
bool(
const DomItem &)> visitor)
1765 bool correctType =
false;
1767 switch (lookupType) {
1768 case LookupType::Binding:
1771 case LookupType::Method:
1774 case LookupType::Property:
1777 case LookupType::PropertyDef:
1780 case LookupType::Type:
1793 const DomItem &newIt,
const QStringList &subpath,
1794 function_ref<
bool(
const DomItem &)> visitor, LookupType lookupType,
1795 const ErrorHandler &errorHandler, QList<Path> *visitedRefs)
1797 QList<ResolveToDo> lookupToDos(
1798 { ResolveToDo{ newIt, 1 } });
1800 QList<QSet<quintptr>> lookupVisited(subpath.size() + 1);
1801 while (!lookupToDos.isEmpty()) {
1803 auto vNow = std::make_pair(tNow.item.id(), tNow.pathIndex);
1806 Q_ASSERT(iSubPath < subpath.size());
1807 QString subPathNow = subpath[iSubPath++];
1808 DomItem scope = subNow.proceedToScope();
1809 if (iSubPath < subpath.size()) {
1810 if (vNow.first != 0) {
1811 if (lookupVisited[vNow.second].contains(vNow.first))
1814 lookupVisited[vNow.second].insert(vNow.first);
1817 scope.visitDirectAccessibleScopes(
1818 [&lookupToDos, &subPathNow, iSubPath](
const DomItem &el) {
1819 return el.visitLocalSymbolsNamed(
1820 subPathNow, [&lookupToDos, iSubPath](
const DomItem &subEl) {
1821 lookupToDos.append({ subEl, iSubPath });
1828 bool cont = scope.visitDirectAccessibleScopes(
1829 [&visitor, &subPathNow, lookupType](
const DomItem &el) ->
bool {
1830 if (lookupType == LookupType::Symbol)
1831 return el.visitLocalSymbolsNamed(subPathNow, visitor);
1833 return el.visitLocalSymbolsNamed(
1834 subPathNow, [lookupType, &visitor](
const DomItem &el) ->
bool {
1835 return visitForLookupType(el, lookupType, visitor);
1848 const QString &target, function_ref<
bool(
const DomItem &)> visitor, LookupType lookupType,
1849 LookupOptions opts,
const ErrorHandler &errorHandler, QSet<quintptr> *visited,
1850 QList<Path> *visitedRefs)
const
1852 if (target.isEmpty())
1854 switch (lookupType) {
1855 case LookupType::Binding:
1856 case LookupType::Method:
1857 case LookupType::Property:
1858 case LookupType::PropertyDef:
1859 case LookupType::Symbol:
1860 case LookupType::Type: {
1861 QStringList subpath = target.split(QChar::fromLatin1(
'.'));
1862 if (subpath.size() == 1) {
1863 return visitLookup1(subpath.first(), visitor, opts, errorHandler, visited, visitedRefs);
1865 return visitLookup1(
1867 [&subpath, visitor, lookupType, &errorHandler,
1868 visitedRefs](
const DomItem &newIt) ->
bool {
1869 return visitQualifiedNameLookup(newIt, subpath, visitor, lookupType,
1870 errorHandler, visitedRefs);
1872 opts, errorHandler, visited, visitedRefs);
1876 case LookupType::CppType:
1884
1885
1886
1887
1888
1889
1890
1899 current = current.get(h, visitedRefs);
1903 current = current.field(Fields::type);
1906 current = current.field(Fields::referredObject);
1922 [&res](
const DomItem &el) {
1926 type, opts, errorHandler);
1936 [&res](
const DomItem &el) {
1940 type, opts, errorHandler);
1946 return visitEl([](
auto &&b) {
return b->id(); });
1951 return visitEl([](
auto &&e) {
return e->pathFromOwner(); });
1956 return visitEl([
this](
auto &&e) {
return e->canonicalFilePath(*
this); });
1965 DomItem newItem =
std::visit([
this, &o](
auto &&el) {
1966 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>) {
1969 auto copyPtr = el->makeCopy(o);
1970 return DomItem(m_top, copyPtr, m_ownerPath, copyPtr.get());
1976 std::shared_ptr<DomEnvironment> newEnvPtr;
1977 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
1978 newEnvPtr =
std::make_shared<DomEnvironment>(envPtr, envPtr->loadPaths(), envPtr->options(),
1979 envPtr->domCreationOption());
1980 DomBase *eBase = envPtr.get();
1981 if (
std::holds_alternative<
const DomEnvironment *>(m_element) && eBase
1982 &&
std::get<
const DomEnvironment *>(m_element) == eBase)
1984 }
else if (std::shared_ptr<DomUniverse> univPtr = top().ownerAs<DomUniverse>()) {
1985 newEnvPtr =
std::make_shared<DomEnvironment>(
1994 [
this, newEnvPtr, &o](
auto &&el) {
1995 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>) {
1998 auto copyPtr = el->makeCopy(o);
1999 return DomItem(newEnvPtr, copyPtr, m_ownerPath, copyPtr.get());
2011 case DomType::MockOwner:
2012 case DomType::ScriptExpression:
2013 case DomType::AstComments:
2014 case DomType::LoadInfo:
2015 case DomType::FileLocationsNode:
2016 case DomType::DomEnvironment:
2017 case DomType::DomUniverse:
2018 qCWarning(domLog) <<
"DomItem::makeCopy " << internalKindStr()
2019 <<
" does not support binding to environment";
2023 qCWarning(domLog) <<
"DomItem::makeCopy(" << internalKindStr()
2024 <<
") is not an known OwningItem";
2036 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
2037 return envPtr->commitToBase(env, validEnvPtr);
2052 case DomType::QmlObject:
2053 f = field(Fields::propertyDefs);
2055 if (!v.visitIndexes(visitor))
2057 f = field(Fields::bindings);
2059 if (!v.visitIndexes(visitor))
2061 f = field(Fields::methods);
2063 if (!v.visitIndexes(visitor))
2069 case DomType::QmlComponent:
2070 f = field(Fields::ids);
2072 if (!v.visitIndexes(visitor))
2078 DomItem params = field(Fields::parameters);
2079 if (!params.visitIndexes([name, visitor](
const DomItem &p) {
2081 if (pPtr->name == name && !visitor(p))
2089 f = field(Fields::components);
2091 if (!v.visitIndexes(visitor))
2104 if (internalKind() == DomType::Map)
2106 return field(cName);
2111 if (internalKind() == DomType::Map)
2112 return key(cName.toString());
2113 return field(cName);
2123 return base()->value();
2128 sink(u"DomItem{ topPtr:");
2129 sink(QString::number((quintptr)topPtr().get(), 16));
2130 sink(u", ownerPtr:");
2131 sink(QString::number((quintptr)owningItemPtr().get(), 16));
2132 sink(u", ownerPath:");
2133 m_ownerPath.dump(sink);
2135 sink(QString::number((quintptr)base(),16));
2140 const Sink &s,
int indent,
2141 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2143 visitEl([
this, s, indent, filter](
auto &&e) { e->dump(*
this, s, indent, filter); });
2147 const QString &path,
2148 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter,
2154 switch (fw->write(path, [
this, indent, filter](QTextStream &ts) {
2155 this->dump([&ts](QStringView s) { ts << s; }, indent, filter);
2158 case FileWriter::Status::ShouldWrite:
2159 case FileWriter::Status::SkippedDueToFailure:
2160 qWarning() <<
"Failure dumping " <<
canonicalPath() <<
" to " << path;
2162 case FileWriter::Status::DidWrite:
2163 case FileWriter::Status::SkippedEqual:
2171 return dumperToString([
this](
const Sink &s){ dump(s); });
2176 return std::visit([](
auto &&ow) {
2177 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2180 return ow->derivedFrom();
2186 return std::visit([](
auto &&ow) {
2187 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2190 return ow->revision();
2196 return std::visit([](
auto &&ow) {
2197 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2198 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2200 return ow->createdAt();
2206 return std::visit([](
auto &&ow) {
2207 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2208 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2210 return ow->frozenAt();
2216 return std::visit([](
auto &&ow) {
2217 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2218 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2220 return ow->lastDataUpdateAt();
2226 std::visit([
this, &msg](
auto &&ow) {
2227 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2242 std::visit([&groups](
auto &&ow) {
2243 if constexpr (!std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2244 ow->clearErrors(groups);
2248 iterateSubOwners([groups](
const DomItem &i){
2249 i.clearErrors(groups,
true);
2256 function_ref<
bool(
const DomItem &,
const ErrorMessage &)> visitor,
bool iterate,
2259 if (!
std::visit([
this, visitor, inPath](
auto &&el) {
2260 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2263 return el->iterateErrors(
owner(), visitor, inPath);
2268 if (iterate && !iterateSubOwners([inPath, visitor](
const DomItem &i) {
2269 return i.iterateErrors(visitor,
true, inPath);
2279 return std::visit([
this, visitor](
auto &&o) {
2280 if constexpr (std::is_same_v<std::decay_t<
decltype(o)>, std::monostate>)
2283 return o->iterateSubOwners(
owner(), visitor);
2290 [
this, v](
auto &&el) {
return el->iterateDirectSubpaths(*
this, v); });
2296 List::fromQList<Path>(pathFromOwner().withComponent(c), paths,
2297 [](
const DomItem &list,
const PathEls::PathComponent &p,
const Path &el) {
2298 return list.subReferenceItem(p, el);
2305 return DomItem(m_top, m_owner, m_ownerPath, Reference(referencedObject, Path(c)));
2307 return DomItem(m_top, m_owner, m_ownerPath,
2308 Reference(referencedObject, pathFromOwner().withComponent(c)));
2314 return std::visit([](
auto &&el) -> shared_ptr<
DomTop> {
2315 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2325 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2333
2334
2335
2338 return visitEl([](
auto &&el) ->
const DomBase * {
return el->domBase(); });
2347 DomItem(universePtr, universePtr,
Path(), universePtr.get())
2352
2353
2354
2355
2356
2357
2358
2367 FileToLoad::fromMemory(env, QString(), code),
2369 std::make_optional(fileType));
2370 return tFile.fileObject();
2397 const DomItem &,
const Sink &s,
int,
2404 const Keys &keys,
const QString &targetType)
2415 QSet<QString> ksSet = keys(self);
2416 QStringList ksList = QStringList(ksSet.begin(), ksSet.end());
2417 std::sort(ksList.begin(), ksList.end());
2418 for (
const QString &k : std::as_const(ksList)) {
2419 if (!visitor(PathEls::Key(k), [&self,
this, k]() {
return key(self, k); }))
2427 return m_keys(self);
2432 return m_lookup(self, name);
2436 const DomItem &self,
const Sink &sink,
int indent,
2437 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2440 DomKind dK = self.domKind();
2442 case DomKind::Object:
2443 sink(u"{ \"~type~\":");
2444 sinkEscaped(sink, typeName());
2447 case DomKind::Value:
2449 sink(QString::fromUtf8(value().toJsonValue().toJson()));
2452 case DomKind::Empty:
2461 case DomKind::ScriptElement:
2465 auto closeParens = qScopeGuard(
2468 case DomKind::Object:
2469 sinkNewline(sink, indent);
2472 case DomKind::Value:
2474 case DomKind::Empty:
2477 sinkNewline(sink, indent);
2481 sinkNewline(sink, indent);
2484 case DomKind::ScriptElement:
2490 self.iterateDirectSubpaths(
2492 function_ref<DomItem()> itemF) {
2494 if (!filter(self, c, i))
2502 sinkNewline(sink, indent + 2);
2503 if (dK != DomKind::Object)
2504 sink(u"UNEXPECTED ENTRY ERROR:");
2505 sinkEscaped(sink, c.name());
2509 sinkNewline(sink, indent + 2);
2510 if (dK != DomKind::Map)
2511 sink(u"UNEXPECTED ENTRY ERROR:");
2512 sinkEscaped(sink, c.name());
2516 sinkNewline(sink, indent + 2);
2517 if (dK != DomKind::List)
2518 sink(u"UNEXPECTED ENTRY ERROR:");
2519 else if (idx++ != c.index())
2520 sink(u"OUT OF ORDER ARRAY:");
2523 sinkNewline(sink, indent + 2);
2524 sink(u"UNEXPECTED PATH KIND ERROR (ignored)");
2528 i.dump(sink, indent + 2, filter);
2530 sink(uR"({ "~type~": "Reference", "immediate": true, "referredObjectPath":")");
2542 const QString &elType):
2553 const DomItem &self,
const Sink &sink,
int indent,
2554 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2558 iterateDirectSubpaths(
2560 [&self, indent, &first, sink, filter](
const PathEls::PathComponent &c,
2561 function_ref<DomItem()> itemF) {
2562 DomItem item = itemF();
2563 if (!filter(self, c, item))
2569 sinkNewline(sink, indent + 2);
2570 item.dump(sink, indent + 2, filter);
2579 return m_iterator(self, [visitor](index_type i, function_ref<DomItem()> itemF) {
2580 return visitor(PathEls::Index(i), itemF);
2583 index_type len = indexes(self);
2584 for (index_type i = 0; i < len; ++i) {
2585 if (!visitor(
PathEls::Index(i), [
this, &self, i]() {
return index(self, i); }))
2593 return m_length(self);
2598 return m_lookup(self, index);
2604 ow.writeRegion(fLoc, LeftBracketRegion);
2606 iterateDirectSubpaths(self,
2607 [&ow, &first, &fLoc, compact](
const PathEls::PathComponent &,
2608 function_ref<DomItem()> elF) {
2612 ow.writeRegion(fLoc, CommaTokenRegion).ensureSpace();
2614 ow.ensureNewline(1);
2619 if (!compact && !first)
2621 ow.writeRegion(fLoc, RightBracketRegion);
2628 Q_ASSERT(m_pathFromOwner &&
"uninitialized DomElement");
2634 Q_ASSERT(m_pathFromOwner &&
"uninitialized DomElement");
2641 m_pathFromOwner = newPath;
2646 for (
const Path &p : referredObjectPath) {
2647 switch (p.headKind()) {
2648 case Path::Kind::Current:
2649 switch (p.headCurrent()) {
2650 case PathCurrent::Lookup:
2651 case PathCurrent::LookupDynamic:
2652 case PathCurrent::LookupStrict:
2658 case Path::Kind::Empty:
2659 case Path::Kind::Any:
2660 case Path::Kind::Filter:
2682 cont = cont && self.invokeVisitorOnLazyField(visitor, Fields::referredObjectPath, [
this]() {
2683 return referredObjectPath.toString();
2685 cont = cont && visitor(
PathEls::Field(Fields::get), [
this, &self]() {
return this->get(self); });
2691 if (
Fields::referredObjectPath == name) {
2692 return self.subDataItem(
PathEls::Field(Fields::referredObjectPath),
2693 referredObjectPath.toString());
2695 if (Fields::get == name)
2702 return QList<QString>({Fields::referredObjectPath.toString(), Fields::get.toString()});
2718 if (referredObjectPath) {
2726 RefCacheEntry cached = RefCacheEntry::forPath(self, selfPath);
2727 switch (cached.cached) {
2728 case RefCacheEntry::Cached::None:
2730 case RefCacheEntry::Cached::First:
2731 case RefCacheEntry::Cached::All:
2732 if (!cached.canonicalPaths.isEmpty())
2733 cachedPath = cached.canonicalPaths.first();
2741 qCWarning(refLog) <<
"referenceCache outdated, reference at " << selfPath
2742 <<
" leads to invalid path " << cachedPath;
2748 QList<Path> visitedRefsLocal;
2756 (visitedRefs ? visitedRefs : &visitedRefsLocal));
2759 env, selfPath, RefCacheEntry { RefCacheEntry::Cached::First, { cachedPath } });
2768 if (referredObjectPath) {
2771 QList<Path> cachedPaths;
2775 RefCacheEntry cached = RefCacheEntry::forPath(env, selfPath);
2776 switch (cached.cached) {
2777 case RefCacheEntry::Cached::None:
2778 case RefCacheEntry::Cached::First:
2780 case RefCacheEntry::Cached::All:
2781 cachedPaths += cached.canonicalPaths;
2782 if (cachedPaths.isEmpty())
2786 if (!cachedPaths.isEmpty()) {
2787 bool outdated =
false;
2788 for (
const Path &p : cachedPaths) {
2789 DomItem newEl = env.path(p);
2792 qCWarning(refLog) <<
"referenceCache outdated, reference at " << selfPath
2793 <<
" leads to invalid path " << p;
2813 QList<Path> canonicalPaths;
2814 for (
const DomItem &i : res) {
2816 canonicalPaths.append(i.canonicalPath());
2819 <<
"getAll of reference at " << selfPath <<
" visits empty items.";
2823 RefCacheEntry { RefCacheEntry::Cached::All, std::move(canonicalPaths) });
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2847 : m_derivedFrom(derivedFrom),
2855 : m_derivedFrom(derivedFrom),
2869 QMultiMap<Path, ErrorMessage> my_errors;
2871 QMutexLocker l1(o.mutex());
2872 my_errors = o.m_errors;
2876 QMutexLocker l2(mutex());
2877 m_errors = my_errors;
2884 static QAtomicInt nextRev(0);
2891 cont = cont && visitor(
PathEls::Field(Fields::errors), [&self,
this]() {
2892 QMultiMap<Path, ErrorMessage> myErrors = localErrors();
2893 return self.subMapItem(Map(
2894 self.pathFromOwner().withField(Fields::errors),
2895 [myErrors](
const DomItem &map,
const QString &key) {
2896 auto it = myErrors.find(Path::fromString(key));
2897 if (it != myErrors.end())
2898 return map.subDataItem(PathEls::Key(key), it->toCbor(),
2899 ConstantData::Options::FirstMapIsFields);
2903 [myErrors](
const DomItem &) {
2905 auto it = myErrors.keyBegin();
2906 auto end = myErrors.keyEnd();
2908 res.insert(it++->toString());
2911 QLatin1String(
"ErrorMessages")));
2919 if (s.pathFromSource) {
2920 if (!s.pathToSource)
2922 return self
.path(s.pathToSource
);
2929 return m_derivedFrom;
2939 return m_frozenAt > m_createdAt;
2945 m_frozenAt = QDateTime::currentDateTimeUtc();
2946 if (m_frozenAt <= m_createdAt)
2947 m_frozenAt = m_createdAt.addSecs(1);
2960 return m_lastDataUpdateAt;
2970 if (m_lastDataUpdateAt < tNew)
2971 m_lastDataUpdateAt = tNew;
2981 QMutexLocker l(mutex());
2982 quint32 &c = m_errorsCounts[msg];
2985 m_errors.insert(msg.path, msg);
2990 QMutexLocker l(mutex());
2991 auto it = m_errors.begin();
2992 while (it != m_errors.end()) {
2993 if (it->errorGroups == groups)
2994 it = m_errors.erase(it);
3001 const DomItem &self, function_ref<
bool(
const DomItem &,
const ErrorMessage &)> visitor,
3004 QMultiMap<Path, ErrorMessage> myErrors;
3006 QMutexLocker l(mutex());
3007 myErrors = m_errors;
3009 auto it = myErrors.lowerBound(inPath);
3010 auto end = myErrors.end();
3011 while (it != end && it.key().mid(0, inPath
.length()) == inPath) {
3012 if (!visitor(self, *it++))
3020 return self.iterateDirectSubpaths(
3023 if (i.owningItemPtr() != self.owningItemPtr()) {
3025 if (container.id() == self.id())
3034 if (o1.m_kind != o2.m_kind)
3036 return o1.visitEl([&o1, &o2](
auto &&el1) {
3037 auto &&el2 = std::get<std::decay_t<
decltype(el1)>>(o2.m_element);
3038 auto id1 = el1->id();
3039 auto id2 = el2->id();
3042 if (id1 != quintptr(0))
3044 if (o1.m_owner != o2.m_owner)
3046 Path p1 = el1->pathFromOwner();
3047 Path p2 = el2->pathFromOwner();
3066 Q_ASSERT(
false &&
"addPropertyDef on non qml scope");
3075 Q_ASSERT(
false &&
"addBinding on non qml scope");
3084 Q_ASSERT(
false &&
"addMethod on non qml scope");
3092 }
else if (QmlComponent *el = mutableAs<QmlComponent>()) {
3096 Q_ASSERT(
false &&
"addChild on non qml scope");
3104 dumperToQDebug([&c](
const Sink &s) { c.dump(s); }, debug);
3111 return debug.noquote().nospace() <<
"MutableDomItem(" << domTypeToString(cc.internalKind())
3112 <<
", " << cc.canonicalPath().toString() <<
")";
3117 index_type len = index_type(m_pList.size());
3118 for (index_type i = 0; i < len; ++i) {
3119 if (!v(
PathEls::Index(i), [
this, &self, i] {
return this->index(self, i); }))
3128 ow.writeRegion(fLoc, LeftBracketRegion);
3130 index_type len = index_type(m_pList.size());
3131 for (index_type i = 0; i < len; ++i) {
3135 ow.writeRegion(fLoc, CommaTokenRegion).ensureSpace();
3137 ow.ensureNewline(1);
3141 if (!compact && !first)
3143 ow.writeRegion(fLoc, RightBracketRegion);
3156
3157
3158
3159
3160
3179 return fileItem.ownerAs<JsFile>();
3181 return fileItem.ownerAs<QmlFile>();
3183 Q_UNREACHABLE_RETURN({});
3192#include "moc_qqmldomitem_p.cpp"
Path addObject(const QmlObject &object, QmlObject **oPtr=nullptr)
DomKind domKind() const override
ConstantData(const Path &pathFromOwner, const QCborValue &value, Options options=Options::MapIsMap)
quintptr id() const override
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override
static CppTypeInfo fromString(QStringView target, const ErrorHandler &h=nullptr)
virtual DomItem containingObject(const DomItem &self) const
virtual void writeOut(const DomItem &self, OutWriter &lw) const
virtual QString canonicalFilePath(const DomItem &self) const
virtual void dump(const DomItem &, const Sink &sink, int indent, FilterT filter) const
virtual void updatePathFromOwner(const Path &newPath)
Path canonicalPath(const DomItem &self) const override
DomElement(const Path &pathFromOwner=Path())
DomItem containingObject(const DomItem &self) const override
A value type that references any element of the Dom.
QDateTime createdAt() const
bool resolve(const Path &path, Visitor visitor, const ErrorHandler &errorHandler, ResolveOptions options=ResolveOption::None, const Path &fullPath=Path(), QList< Path > *visitedRefs=nullptr) const
std::shared_ptr< OwningItem > owningItemPtr() const
DomItem operator[](const QString &component) const
void writeOutPost(OutWriter &lw) const
bool visitTree(const Path &basePath, ChildrenVisitor visitor, VisitOptions options=VisitOption::Default, ChildrenVisitor openingVisitor=emptyChildrenVisitor, ChildrenVisitor closingVisitor=emptyChildrenVisitor, const FieldFilter &filter=FieldFilter::noFilter()) const
Visits recursively all the children of this item using the given visitors.
DomItem path(const Path &p, const ErrorHandler &h=&defaultErrorHandler) const
DomItem containingFile() const
DomItem filterUp(function_ref< bool(DomType k, const DomItem &)> filter, FilterUpOptions options) const
DomItem scope(FilterUpOptions options=FilterUpOptions::ReturnOuter) const
bool visitLookup1(const QString &symbolName, function_ref< bool(const DomItem &)> visitor, LookupOptions=LookupOption::Normal, const ErrorHandler &h=nullptr, QSet< quintptr > *visited=nullptr, QList< Path > *visitedRefs=nullptr) const
DomItem get(const ErrorHandler &h=nullptr, QList< Path > *visitedRefs=nullptr) const
static ErrorGroups myErrors()
DomItem operator[](const char16_t *component) const
bool visitUp(function_ref< bool(const DomItem &)> visitor) const
Let the visitor visit the Dom Tree hierarchy of this DomItem.
index_type indexes() const
bool hasAnnotations() const
bool iterateSubOwners(function_ref< bool(const DomItem &owner)> visitor) const
MutableDomItem makeCopy(CopyOption option=CopyOption::EnvConnected) const
bool iterateErrors(function_ref< bool(const DomItem &, const ErrorMessage &)> visitor, bool iterate, Path inPath=Path()) const
DomItem proceedToScope(const ErrorHandler &h=nullptr, QList< Path > *visitedRefs=nullptr) const
Dereference DomItems pointing to other DomItems.
QList< DomItem > values() const
bool iterateDirectSubpaths(DirectVisitor v) const
DomItem container() const
void clearErrors(const ErrorGroups &groups=ErrorGroups({}), bool iterate=true) const
QList< QString > fields() const
bool writeOut(const QString &path, const LineWriterOptions &opt=LineWriterOptions(), FileWriter *fw=nullptr, WriteOutChecks extraChecks=WriteOutCheck::Default) const
DomItem(const std::shared_ptr< DomEnvironment > &)
FileWriter::Status dump(const QString &path, function_ref< bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter=noFilter, int indent=0, FileWriter *fw=nullptr) const
bool visitScopeChain(function_ref< bool(const DomItem &)> visitor, LookupOptions=LookupOption::Normal, const ErrorHandler &h=nullptr, QSet< quintptr > *visited=nullptr, QList< Path > *visitedRefs=nullptr) const
Let the visitor visit the QML scope hierarchy of this DomItem.
std::shared_ptr< DomTop > topPtr() const
QDateTime frozenAt() const
DomItem subListItem(const List &list) const
DomItem component(GoTo option=GoTo::Strict) const
bool visitLookup(const QString &symbolName, function_ref< bool(const DomItem &)> visitor, LookupType type=LookupType::Symbol, LookupOptions=LookupOption::Normal, const ErrorHandler &errorHandler=nullptr, QSet< quintptr > *visited=nullptr, QList< Path > *visitedRefs=nullptr) const
void writeOutPre(OutWriter &lw) const
DomItem lookupFirst(const QString &symbolName, LookupType type=LookupType::Symbol, LookupOptions=LookupOption::Normal, const ErrorHandler &errorHandler=nullptr) const
bool visitIndexes(function_ref< bool(const DomItem &)> visitor) const
DomItem fileObject(GoTo option=GoTo::Strict) const
bool visitKeys(function_ref< bool(const QString &, const DomItem &)> visitor) const
bool visitStaticTypePrototypeChains(function_ref< bool(const DomItem &)> visitor, VisitPrototypesOptions options=VisitPrototypesOption::Normal, const ErrorHandler &h=nullptr, QSet< quintptr > *visited=nullptr, QList< Path > *visitedRefs=nullptr) const
DomItem::visitStaticTypePrototypeChains.
QQmlJSScope::ConstPtr semanticScope() const
bool writeOutForFile(OutWriter &ow, WriteOutChecks extraChecks) const
bool commitToBase(const std::shared_ptr< DomEnvironment > &validPtr=nullptr) const
QList< DomItem > lookup(const QString &symbolName, LookupType type=LookupType::Symbol, LookupOptions=LookupOption::Normal, const ErrorHandler &errorHandler=nullptr) const
void dump(const Sink &, int indent=0, function_ref< bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter=noFilter) const
friend QMLDOM_EXPORT bool operator==(const DomItem &, const DomItem &)
QSet< QString > propertyInfoNames() const
static ErrorGroups myResolveErrors()
bool visitDirectAccessibleScopes(function_ref< bool(const DomItem &)> visitor, VisitPrototypesOptions options=VisitPrototypesOption::Normal, const ErrorHandler &h=nullptr, QSet< quintptr > *visited=nullptr, QList< Path > *visitedRefs=nullptr) const
DomItem environment() const
bool isCanonicalChild(const DomItem &child) const
DomItem operator[](QStringView component) const
DomItem rootQmlObject(GoTo option=GoTo::Strict) const
DomItem directParent() const
Path canonicalPath() const
QStringList sortedKeys() const
void addError(ErrorMessage &&msg) const
DomItem containingObject() const
DomItem containingScriptExpression() const
QList< DomItem > getAll(const ErrorHandler &h=nullptr, QList< Path > *visitedRefs=nullptr) const
bool visitPrototypeChain(function_ref< bool(const DomItem &)> visitor, VisitPrototypesOptions options=VisitPrototypesOption::Normal, const ErrorHandler &h=nullptr, QSet< quintptr > *visited=nullptr, QList< Path > *visitedRefs=nullptr) const
DomItem index(index_type) const
DomItem subReferencesItem(const PathEls::PathComponent &c, const QList< Path > &paths) const
bool visitLocalSymbolsNamed(const QString &name, function_ref< bool(const DomItem &)> visitor) const
DomItem subReferenceItem(const PathEls::PathComponent &c, const Path &referencedObject) const
void dumpPtr(const Sink &sink) const
InternalKind internalKind() const
DomItem path(const QString &p, const ErrorHandler &h=&defaultErrorHandler) const
bool isOwningItem() const
DomItem owner() const
The owner of an element, for an qmlObject this is the containing qml file.
ErrorHandler errorHandler() const
DomItem operator[](const Path &path) const
QQmlJSScope::ConstPtr nearestSemanticScope() const
QString canonicalFilePath() const
void writeOut(OutWriter &lw) const
Path pathFromOwner() const
DomItem qmlObject(GoTo option=GoTo::Strict, FilterUpOptions options=FilterUpOptions::ReturnOuter) const
Returns the QmlObject that this belongs to.
DomItem path(QStringView p, const ErrorHandler &h=&defaultErrorHandler) const
DomItem key(const QString &name) const
PropertyInfo propertyInfoWithName(const QString &name) const
QSet< QString > keys() const
DomItem field(QStringView name) const
DomItem goToFile(const QString &filePath) const
QDateTime lastDataUpdateAt() const
DomItem(const std::shared_ptr< DomUniverse > &)
static ErrorGroup domErrorGroup
void dump(const DomItem &, const Sink &s, int indent, function_ref< bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter) const override
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override
Path pathFromOwner() const override
Path canonicalPath(const DomItem &self) const override
DomItem containingObject(const DomItem &self) const override
convenience macro creating a new ErrorGroup and registering its groupId as translatable string
Represents a set of tags grouping a set of related error messages.
ErrorMessage warning(const Dumper &message) const
ErrorMessage error(const Dumper &message) const
Represents an error message connected to the dom.
ErrorMessage handle(const ErrorHandler &errorHandler=nullptr)
ErrorMessage & withItem(const DomItem &)
static FieldFilter compareNoCommentsFilter()
FileToLoad(const std::weak_ptr< DomEnvironment > &environment, const QString &canonicalPath, const QString &logicalPath, const std::optional< InMemoryContents > &content)
const LineWriterOptions & options() const
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor v) const override
void writeOut(const DomItem &self, OutWriter &ow, bool compact) const
void writeOut(const DomItem &self, OutWriter &ow, bool compact) const
std::function< bool(const DomItem &, function_ref< bool(index_type, function_ref< DomItem()>)>)> IteratorFunction
List(const Path &pathFromOwner, const LookupFunction &lookup, const Length &length, const IteratorFunction &iterator, const QString &elType)
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override
void dump(const DomItem &, const Sink &s, int indent, function_ref< bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)>) const override
std::function< DomItem(const DomItem &, index_type)> LookupFunction
quintptr id() const override
index_type indexes(const DomItem &self) const override
DomItem index(const DomItem &self, index_type index) const override
std::function< index_type(const DomItem &)> Length
std::function< DomItem(const DomItem &, QString)> LookupFunction
Map(const Path &pathFromOwner, const LookupFunction &lookup, const Keys &keys, const QString &targetType)
std::function< QSet< QString >(const DomItem &)> Keys
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override
QSet< QString > const keys(const DomItem &self) const override
quintptr id() const override
DomItem key(const DomItem &self, const QString &name) const override
MutableDomItem addChild(QmlObject child)
MutableDomItem addPropertyDef(const PropertyDefinition &propertyDef, AddOption option=AddOption::Overwrite)
ErrorHandler errorHandler()
MutableDomItem addMethod(const MethodInfo &functionDef, AddOption option=AddOption::Overwrite)
void addError(ErrorMessage &&msg)
MutableDomItem path(const Path &p)
MutableDomItem addBinding(Binding binding, AddOption option=AddOption::Overwrite)
A DomItem that owns other DomItems and is managed through a shared pointer.
QDateTime createdAt() const
virtual bool iterateSubOwners(const DomItem &self, function_ref< bool(const DomItem &owner)> visitor)
virtual int revision() const
DomItem containingObject(const DomItem &self) const override
bool iterateErrors(const DomItem &self, function_ref< bool(const DomItem &source, const ErrorMessage &msg)> visitor, const Path &inPath=Path())
virtual void addError(const DomItem &self, ErrorMessage &&msg)
static int nextRevision()
QDateTime frozenAt() const
void addErrorLocal(ErrorMessage &&msg)
virtual QDateTime lastDataUpdateAt() const
void clearErrors(const ErrorGroups &groups=ErrorGroups({}))
OwningItem(int derivedFrom, const QDateTime &lastDataUpdateAt)
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override
virtual bool frozen() const
virtual void refreshedDataAt(QDateTime tNew)
OwningItem(int derivedFrom=0)
OwningItem(const OwningItem &o)
PathCurrent headCurrent() const
Path dropTail(int n=1) const
Path withPath(const Path &toAdd, bool avoidToAddAsBase=false) const
Returns a copy of this with toAdd appended to it.
Source split() const
Splits the path at the last field, root or current Component.
std::function< bool(const DomItem &)> headFilter() const
Path operator[](int i) const
Path mid(int offset, int length) const
PathRoot headRoot() const
MutableDomItem addBinding(MutableDomItem &self, const Binding &binding, AddOption option)
MutableDomItem addChild(MutableDomItem &self, const QmlObject &child)
MutableDomItem addPropertyDef(MutableDomItem &self, const PropertyDefinition &propertyDef, AddOption option)
MutableDomItem addMethod(MutableDomItem &self, const MethodInfo &functionDef, AddOption option)
QList< std::pair< SourceLocation, DomItem > > Attributes
static bool addForPath(const DomItem &el, const Path &canonicalPath, const RefCacheEntry &entry, AddOption addOption=AddOption::KeepExisting)
QList< QString > fields(const DomItem &self) const override
quintptr id() const override
static constexpr DomType kindValue
DomItem index(const DomItem &, index_type) const override
DomItem field(const DomItem &self, QStringView name) const override
DomItem get(const DomItem &self, const ErrorHandler &h=nullptr, QList< Path > *visitedRefs=nullptr) const
QList< DomItem > getAll(const DomItem &self, const ErrorHandler &h=nullptr, QList< Path > *visitedRefs=nullptr) const
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override
Reference(const Path &referredObject=Path(), const Path &pathFromOwner=Path(), const SourceLocation &loc=SourceLocation())
DomItem key(const DomItem &, const QString &) const override
Use this to contain any script element.
ScriptElement::PointerType< ScriptElement > base() const
Returns a pointer to the virtual base for virtual method calls.
Provides entities to maintain mappings between elements and their location in a file.
Tree treeOf(const DomItem &)
QMLDOM_EXPORT bool domTypeIsContainer(DomType k)
static QMap< QString, LookupType > stringToLookupTypeMap()
constexpr bool domTypeIsOwningItem(DomType)
static std::optional< LookupType > lookupTypeFromString(const QString &expectedType)
static bool visitForLookupType(const DomItem &el, LookupType lookupType, function_ref< bool(const DomItem &)> visitor)
static DomItem rootFromContext(const DomItem &root, PathRoot contextId)
QMLDOM_EXPORT QMap< DomKind, QString > domKindToStringMap()
std::shared_ptr< ExternalOwningItem > getFileItemOwner(const DomItem &fileItem)
static bool visitQualifiedNameLookup(const DomItem &newIt, const QStringList &subpath, function_ref< bool(const DomItem &)> visitor, LookupType lookupType, const ErrorHandler &errorHandler, QList< Path > *visitedRefs)
bool operator!=(const DomItem &o1, const DomItem &o2)
QMLDOM_EXPORT bool domTypeIsExternalItem(DomType k)
QMLDOM_EXPORT QMap< DomType, QString > domTypeToStringMap()
QMLDOM_EXPORT bool domTypeIsScope(DomType k)
static LookupOptions resolveLookupOptions(const PathCurrent ¤t, const DomItem &it)
QMLDOM_EXPORT QString domTypeToString(DomType k)
QMLDOM_EXPORT QString domKindToString(DomKind k)
bool operator!=(const Path &lhs, const Path &rhs)
std::function< void(const ErrorMessage &)> ErrorHandler
QMLDOM_EXPORT bool domTypeIsTopItem(DomType k)
QMLDOM_EXPORT void defaultErrorHandler(const ErrorMessage &)
Calls the default error handler (by default errorToQDebug).
static bool visitPrototypeIndex(QList< DomItem > &toDo, const DomItem ¤t, const DomItem &derivedFromPrototype, const ErrorHandler &h, QList< Path > *visitedRefs, VisitPrototypesOptions options, const DomItem &prototype)
bool operator==(const Path &lhs, const Path &rhs)
static DomItem resolveReference(const DomItem &it, const Path &refRef, QList< Path > *visitedRefs, const ErrorHandler &errorHandler, const ErrorGroups &errorGroup)
Combined button and popup list for selecting options.
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
#define NewErrorGroup(name)
A common base class for all the script elements.
void setSemanticScope(const QQmlJSScope::ConstPtr &scope)
QQmlJSScope::ConstPtr semanticScope()