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)));
236 return parent.canonicalFilePath();
242 qCWarning(writeOutLog) <<
"Ignoring unsupported writeOut for " << domTypeToString(kind()) <<
":"
243 << self.canonicalPath();
252 static QHash<QString, QString> knownFields;
253 static QBasicMutex m;
254 auto toField = [](
const QString &f) -> QStringView {
256 if (!knownFields.contains(f))
258 return knownFields[f];
260 if (m_value.isMap()) {
261 QCborMap map = m_value.toMap();
262 auto it = map.cbegin();
263 auto end = map.cend();
265 QString key = it.key().toString();
272 comp =
PathEls::Field(toField(key));
275 auto val = it.value();
276 if (!self.invokeVisitorOnValue(visitor, comp, val))
281 }
else if (m_value.isArray()){
282 QCborArray array = m_value.toArray();
283 auto it = array.cbegin();
284 auto end = array.cend();
287 if (!self.invokeVisitorOnValue(visitor,
PathEls::Index(i++), *it++))
303 if (m_value.isMap()) {
305 case ConstantData::Options::MapIsMap:
307 case ConstantData::Options::FirstMapIsFields:
308 return DomKind::Object;
311 if (m_value.isArray())
312 return DomKind::List;
313 return DomKind::Value;
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
345
346
347
348
349
352 const QString &canonicalPath,
const QString &logicalPath,
362 const QString &path,
const QString &code)
364 const QString canonicalPath = QFileInfo(path).canonicalFilePath();
369 canonicalPath.isEmpty() ? path : canonicalPath,
379 const QString canonicalPath = QFileInfo(path).canonicalFilePath();
405 Path res = visitEl([
this](
auto &&el) {
return el->canonicalPath(*
this); });
407 qCWarning(domLog) <<
"non anchored canonical path:" << res.toString();
416 return visitEl([
this](
auto &&el) {
return el->containingObject(*
this); });
420
421
422
423
424
427 if (
DomItem res = filterUp([](DomType k,
const DomItem &) {
return k == DomType::QmlObject; },
430 if (options == GoTo::MostLikely) {
431 if (
DomItem comp = component(options))
432 return comp.field(Fields::objects).index(0);
445 if (k == DomType::ExternalItemInfo || (options == GoTo::MostLikely && k == DomType::ExternalItemPair))
446 return field(Fields::currentItem);
462 return qmlObject(options, FilterUpOptions::ReturnInner);
471 if (s.pathFromSource.length() > 1)
481 if (shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
482 return env.copy(envPtr->ensureGlobalScopeWithName(env, envPtr->globalScopeName())->current,
489
490
491
496 return std::visit([
this](
auto &&el) {
497 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
500 return DomItem(
this->m_top, el,
this->m_ownerPath, el.get());
508 return std::visit([](
auto &&el) {
509 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
530 return res.field(Fields::universe);
535
536
537
538
539
542 if (
DomItem res = filterUp([](DomType k,
const DomItem &) {
return k == DomType::ScriptExpression; },
543 FilterUpOptions::ReturnOuter))
549
550
551
552
553
556 if (
DomItem res = filterUp([](DomType k,
const DomItem &) {
return k == DomType::QmlFile; },
557 FilterUpOptions::ReturnOuter))
563
564
565
566
569 Q_UNUSED(canonicalPath);
571 top().field(Fields::qmlFileWithPath).key(canonicalPath).field(Fields::currentItem);
576
577
578
591
592
593
600
601
602
603
625 current = current
.path(currentPath
);
637 DomItem res = filterUp([](DomType,
const DomItem &el) {
return el.isScope(); }, options);
643 QQmlJSScope::ConstPtr scope;
644 visitUp([&scope](
const DomItem &item) {
645 scope = item.semanticScope();
653 QQmlJSScope::ConstPtr scope = std::visit(
654 [](
auto &&e) -> QQmlJSScope::ConstPtr {
655 using T = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
656 if constexpr (std::is_same_v<T,
const QmlObject *>) {
657 return e->semanticScope();
658 }
else if constexpr (std::is_same_v<T,
const QmlComponent *>) {
659 return e->semanticScope();
660 }
else if constexpr (std::is_same_v<T,
const QmltypesComponent *>) {
661 return e->semanticScope();
662 }
else if constexpr (std::is_same_v<T, SimpleObjectWrap>) {
663 if (
const MethodInfo *mi = e->
template as<MethodInfo>()) {
664 return mi->semanticScope();
666 if (
const auto *propertyDefinition = e->
template as<PropertyDefinition>()) {
667 return propertyDefinition->semanticScope();
669 }
else if constexpr (std::is_same_v<T, ScriptElementDomWrapper>) {
670 return e.element().base()->semanticScope();
681 return refPtr->get(*
this, h, visitedRefs);
688 return refPtr->getAll(*
this, h, visitedRefs);
695 visitPrototypeChain([&pInfo, name](
const DomItem &obj) {
696 return obj.visitLocalSymbolsNamed(name, [&pInfo, name](
const DomItem &el) {
697 switch (el.internalKind()) {
698 case DomType::Binding:
699 pInfo.bindings.append(el);
701 case DomType::PropertyDefinition:
702 pInfo.propertyDefs.append(el);
716 visitPrototypeChain([&res](
const DomItem &obj) {
717 res += obj.propertyDefs().keys();
718 res += obj.bindings().keys();
727 [](DomType kind,
const DomItem &) {
728 return kind == DomType::QmlComponent || kind == DomType::QmltypesComponent
729 || kind == DomType::GlobalComponent;
731 FilterUpOptions::ReturnInner))
733 if (options == GoTo::MostLikely) {
741 case DomType::ExternalItemPair:
742 case DomType::ExternalItemInfo:
743 item = fileObject(options);
746 return item.field(Fields::components).key(QString()).index(0);
761 static auto map = []() {
762 QMetaEnum metaEnum = QMetaEnum::fromType<LookupType>();
763 QMap<QString, LookupType> res;
764 for (
int i = 0; i < metaEnum.keyCount(); ++i) {
765 res[QString::fromUtf8(metaEnum.key(i)).toLower()] = LookupType(metaEnum.value(i));
793
794
795
796
797
801 if (visitedRefs->contains(refRef)) {
803 .error([visitedRefs, refRef](
const Sink &sink) {
804 const QString msg = DomItem::tr(
"Circular reference:") + QLatin1Char(
'\n');
805 sink(QStringView{ msg });
806 for (
const Path &vPath : *visitedRefs) {
819 visitedRefs->append(refRef);
822 ref->referredObjectPath,
833 LookupOptions opt = LookupOption::Normal;
834 if (current == PathCurrent::LookupStrict)
835 return opt | LookupOption::Strict;
839 DomItem strict = comp.field(u"~strictLookup~");
842 strict = env.field(u"defaultStrictLookup");
844 if (strict && strict.value().toBool())
845 opt = opt | LookupOption::Strict;
852 const auto &map = stringToLookupTypeMap();
853 auto it = map.find(expectedType.toLower());
860 ResolveOptions options,
const Path &fullPath, QList<Path> *visitedRefs)
const
863 Path fPath = fullPath;
867 return visitor(fPath, *
this);
868 QList<QSet<quintptr>> visited(path.length() + 1);
870 QList<ResolveToDo> toDos(1);
875 .error(tr(
"Root context %1 is not known").arg(path.headName())
)
876 .handle(errorHandler);
879 toDos[0] = {std::move(root), 1};
881 toDos[0] = {*
this, 0};
883 while (!toDos.isEmpty()) {
886 auto idNow = toDo.item.id();
887 if (idNow == quintptr(0) && toDo.item == *
this)
888 idNow = quintptr(
this);
889 if (idNow != quintptr(0) && visited[0].contains(idNow))
894 bool branchExhausted =
false;
895 while (iPath < path
.length() && it && !branchExhausted) {
896 auto idNow = it.id();
897 if (idNow == quintptr() && toDo.item == *
this)
898 idNow = quintptr(
this);
899 if (idNow != quintptr(0)) {
900 auto vPair = std::make_pair(idNow, iPath);
901 if (visited[vPair.second].contains(vPair.first))
903 visited[vPair.second].insert(vPair.first);
907 auto cNow = path
[iPath++
];
910 it = it.key(cNow.headName());
914 it = resolveReference(it, it.canonicalPath(),
915 visitedRefs ==
nullptr ? &vRefs : visitedRefs,
916 errorHandler, myResolveErrors());
918 it = it.field(cNow.headName());
922 it = it.index(cNow.headIndex());
931 .handle(errorHandler);
932 branchExhausted =
true;
935 toFind = path
[iPath++
];
937 QList<Path::Kind> validFind({Path::Kind::Key, Path::Kind::Field, Path::Kind::Field, Path::Kind::Index});
938 if (!validFind.contains(toFind.headKind())) {
939 myResolveErrors().error(tr(
"After an empty path only key, field or indexes are supported, not %1.").arg(toFind.toString())
)
940 .handle(errorHandler);
941 branchExhausted =
true;
944 if (!branchExhausted)
947 [&toFind, &toDos, iPath](Path,
const DomItem &item,
bool) {
949 DomItem newItem = item[toFind];
951 toDos.append({ std::move(newItem), iPath });
954 VisitOption::VisitSelf | VisitOption::Recurse
955 | VisitOption::VisitAdopted | VisitOption::NoPath);
956 branchExhausted =
true;
961 .arg(cNow.toString()).arg(iPath -1).arg(path.toString())
).handle(errorHandler);
970 if (domKind() != DomKind::Object)
974 bool cont = it.visitPrototypeChain(
975 [&toDos, iPath](
const DomItem &subEl) {
976 toDos.append({ subEl, iPath });
983 branchExhausted =
true;
987 bool cont = it.visitScopeChain(
988 [&toDos, iPath](
const DomItem &subEl) {
989 toDos.append({ subEl, iPath });
992 LookupOption::Normal, errorHandler);
995 branchExhausted =
true;
1003 it = it.component().ids();
1006 it = it.component()[Fields::exports];
1011 const LookupOptions opt = resolveLookupOptions(current, it);
1014 .error(tr(
"Javascript lookups not yet implemented")
)
1015 .handle(errorHandler);
1019 auto idNow = it.id();
1020 if (idNow == quintptr(0) && toDo.item == *
this)
1021 idNow = quintptr(
this);
1022 if (idNow != quintptr(0)) {
1023 auto vPair = std::make_pair(idNow, iPath);
1024 if (visited[vPair.second].contains(vPair.first))
1026 visited[vPair.second].insert(vPair.first);
1032 .error(tr(
"Premature end of path, expected a field specifying the "
1033 "type, and a key specifying the name to search after a "
1034 "lookup directive in %2")
1035 .arg(path.toString())
)
1036 .handle(errorHandler);
1039 Path cNow = path
[iPath++
];
1042 .error(tr(
"Expected a key path specifying the type to search after "
1043 "a lookup directive, not %1 at component %2 of %3")
1044 .arg(cNow.toString())
1046 .arg(path.toString())
)
1047 .handle(errorHandler);
1050 QString expectedType = cNow.headName();
1051 auto lookupType = lookupTypeFromString(expectedType);
1054 .error(tr(
"Type for lookup was expected to be one of '%1', not "
1056 .arg(stringToLookupTypeMap().keys().join(
", "_L1),
1058 .handle(errorHandler);
1061 cNow = path
[iPath++
];
1064 .error(tr(
"Expected a key specifying the path to search after the "
1065 "@lookup directive and type, not %1 at component %2 of "
1067 .arg(cNow.toString())
1069 .arg(path.toString())
)
1070 .handle(errorHandler);
1073 QString target = cNow.headName();
1074 if (target.isEmpty()) {
1076 .warning(tr(
"Path with empty lookup at component %1 of %2 will "
1077 "match nothing in %3.")
1079 .arg(path.toString())
1081 .handle(errorHandler);
1086 [&toDos, iPath](
const DomItem &subEl) {
1087 toDos.append({ subEl, iPath });
1090 *(
std::move(lookupType)), opt, errorHandler, &(visited[iPath]),
1092 branchExhausted =
true;
1098 case Path::Kind::Any:
1101 [&toDos, iPath](Path,
const DomItem &item,
bool) {
1102 toDos.append({ item, iPath });
1105 VisitOption::VisitSelf | VisitOption::Recurse | VisitOption::VisitAdopted);
1106 branchExhausted =
true;
1110 branchExhausted =
true;
1115 if (!branchExhausted && iPath == path
.length() && !visitor(fPath, it))
1126 resolve(p, [&res](
const Path &,
const DomItem &it) {
1145 return visitEl([
this](
auto &&el) {
return el->fields(*
this); });
1150 return visitEl([
this, name](
auto &&el) {
return el->field(*
this, name); });
1155 return visitEl([
this](
auto &&el) {
return el->indexes(*
this); });
1160 return visitEl([
this, i](
auto &&el) {
return el->index(*
this, i); });
1166 int nIndexes = indexes();
1167 for (
int i = 0; i < nIndexes; ++i) {
1177 return visitEl([
this](
auto &&el) {
return el->keys(*
this); });
1182 QSet<QString> ks = keys();
1183 QStringList sortedKs(ks.begin(), ks.end());
1184 std::sort(sortedKs.begin(), sortedKs.end());
1190 return visitEl([
this, name](
auto &&el) {
return el->key(*
this, name); });
1196 const QStringList keys = sortedKeys();
1197 for (
const QString &k : keys) {
1208 iterateDirectSubpaths([&res](
const PathEls::PathComponent &, function_ref<DomItem()> item) {
1218 DomItem anns = field(Fields::annotations);
1219 for (
const auto &ann : anns.values()) {
1220 if (ann.annotations().indexes() == 0) {
1225 DomItem annAnn = ann.annotations();
1226 Q_ASSERT_X(annAnn.indexes() == 1 && annAnn.index(0).name() == u"duplicate",
1227 "DomItem::writeOutPre",
"Unexpected annotation of annotation");
1231 ow.itemStart(*
this);
1237 visitEl([
this, &ow](
auto &&el) { el->writeOut(*
this, ow); });
1248 WriteOutChecks extraChecks)
const
1250 auto compare = [
this](
const DomItem &obj1,
const DomItem &obj2, QStringView obj2Name,
1252 const auto diffList = domCompareStrList(obj1, obj2, filter, DomCompareStrList::AllDiffs);
1253 if (!diffList.isEmpty()) {
1254 qCWarning(writeOutLog).noquote().nospace()
1255 << obj2Name <<
" writeOut of " <<
this->canonicalFilePath() <<
" has changes:\n"
1256 << diffList.join(QString());
1261 auto checkStability = [&ow,
this](
const QString &expected,
const DomItem &obj,
1262 QStringView objName) {
1265 ow2.indentNextlines =
true;
1268 if (ow2.writtenStr != expected) {
1269 qCWarning(writeOutLog).noquote().nospace()
1270 << objName <<
" non stable writeOut of " <<
this->canonicalFilePath() <<
":"
1271 << lineDiff(expected, ow2.writtenStr, 2);
1280 std::shared_ptr<DomEnvironment> newEnvPtr = newEnv.ownerAs<DomEnvironment>();
1282 return WriteOutCheckResult::Failed;
1284 auto newFilePtr =
std::make_shared<QmlFile>(canonicalFilePath(), ow.writtenStr);
1288 if (newFilePtr->isValid()) {
1290 newEnvPtr->populateFromQmlFile(newFile);
1292 && !compare(reformatted, newFile, u"reparsed",
1294 return WriteOutCheckResult::Failed;
1296 checkStability(ow.writtenStr, newFile, u"reparsed");
1299 const auto iterateErrors = [&newFile](
const Sink &s) {
1300 newFile.iterateErrors(
1309 qCWarning(writeOutLog).noquote().nospace()
1310 <<
"writeOut of " << canonicalFilePath()
1311 <<
" created invalid code:\n----------\n"
1312 << ow.writtenStr <<
"\n----------" << iterateErrors;
1313 return WriteOutCheckResult::Failed;
1316 return WriteOutCheckResult::Success;
1320
1321
1322
1323
1324
1325
1326
1327
1328
1331 ow.indentNextlines =
true;
1332 auto currentFileItem = fileObject();
1335 WriteOutCheckResult result = WriteOutCheckResult::Success;
1337 result = performWriteOutChecks(currentFileItem, ow, extraChecks);
1338 return result == WriteOutCheckResult::Success ?
bool(currentFileItem) :
false;
1342 FileWriter *fw, WriteOutChecks extraChecks)
const
1347 auto status = fw->write(
1349 [
this, path, &options, extraChecks](QTextStream &ts) {
1350 auto lw = createLineWriter([&ts](QStringView s) { ts << s; }, path, options);
1351 OutWriter ow(getFileItemOwner(fileObject()), *lw);
1352 return writeOutForFile(ow, extraChecks);
1356 case FileWriter::Status::DidWrite:
1357 case FileWriter::Status::SkippedEqual:
1359 case FileWriter::Status::ShouldWrite:
1360 case FileWriter::Status::SkippedDueToFailure:
1361 qCWarning(writeOutLog) <<
"failure reformatting " << path;
1364 qCWarning(writeOutLog) <<
"Unknown FileWriter::Status ";
1372 bool isChild =
false;
1385 bool hasAnnotations =
false;
1389 if (
const Id *myPtr = as<
Id>())
1390 hasAnnotations = !myPtr->annotations.isEmpty();
1394 hasAnnotations = !myPtr->annotations.isEmpty();
1398 hasAnnotations = !myPtr->annotations.isEmpty();
1402 hasAnnotations = !myPtr->annotations().isEmpty();
1406 hasAnnotations = !myPtr->annotations().isEmpty();
1411 return hasAnnotations;
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1437 VisitOptions options, DomItem::ChildrenVisitor openingVisitor,
1438 DomItem::ChildrenVisitor closingVisitor,
const FieldFilter &filter)
const
1442 if (options & VisitOption::VisitSelf && !visitor(basePath, *
this,
true))
1444 if (options & VisitOption::VisitSelf && !openingVisitor(basePath, *
this,
true))
1446 auto atEnd = qScopeGuard([closingVisitor, basePath,
this, options]() {
1447 if (options & VisitOption::VisitSelf) {
1448 closingVisitor(basePath, *
this,
true);
1451 return iterateDirectSubpaths(
1452 [
this, basePath, visitor, openingVisitor, closingVisitor, options,
1453 &filter](
const PathEls::PathComponent &c, function_ref<DomItem()> itemF) {
1455 if (!(options & VisitOption::NoPath)) {
1457 pNow = pNow.withComponent(c);
1459 if (!filter(*
this, c, DomItem{}))
1461 DomItem item = itemF();
1462 bool directChild = isCanonicalChild(item);
1463 if (!directChild && !(options & VisitOption::VisitAdopted))
1465 if (!directChild || !(options & VisitOption::Recurse)) {
1466 if (!visitor(pNow, item, directChild))
1471 if (!openingVisitor(pNow, item, directChild))
1473 closingVisitor(pNow, item, directChild);
1475 return item.visitTree(pNow, visitor, options | VisitOption::VisitSelf,
1476 openingVisitor, closingVisitor, filter);
1483 QList<Path> *visitedRefs, VisitPrototypesOptions options,
1487 if (visitedRefs->contains(elId))
1490 visitedRefs->append(elId);
1491 QList<DomItem> protos = prototype.getAll(h, visitedRefs);
1492 if (protos.isEmpty()) {
1493 if (std::shared_ptr<DomEnvironment> envPtr =
1494 derivedFromPrototype.environment().ownerAs<DomEnvironment>())
1497 .warning(derivedFromPrototype.tr(
"could not resolve prototype %1 (%2)")
1499 prototype.field(Fields::referredObjectPath)
1502 .withItem(derivedFromPrototype)
1505 if (protos.size() > 1) {
1506 QStringList protoPaths;
1507 for (
const DomItem &p : protos)
1508 protoPaths.append(p.canonicalPath().toString());
1511 .tr(
"Multiple definitions found, using first only, resolving "
1512 "prototype %1 (%2): %3")
1514 prototype.field(Fields::referredObjectPath)
1517 protoPaths.join(QLatin1String(
", ")))
)
1518 .withItem(derivedFromPrototype)
1523 for (
int i = nProtos; i != 0;) {
1524 DomItem proto = protos.at(--i);
1527 proto = proto.proceedToScope(h, visitedRefs);
1534 .warning(derivedFromPrototype.tr(
"Unexpected prototype type %1 (%2)")
1536 prototype.field(Fields::referredObjectPath)
1539 .withItem(derivedFromPrototype)
1549 QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1551 QSet<quintptr> visitedLocal;
1553 visited = &visitedLocal;
1554 QList<Path> refsLocal;
1556 visitedRefs = &refsLocal;
1558 DomItem current = qmlObject();
1563 QList<DomItem> toDo({ current });
1564 while (!toDo.isEmpty()) {
1565 current = toDo.takeLast();
1566 current = current.proceedToScope(h, visitedRefs);
1567 if (visited->contains(current.id())) {
1573 .warning(tr(
"Detected multiple visit of %1 visiting prototypes of %2")
1580 visited->insert(current.id());
1581 if (shouldVisit && !visitor(current))
1584 current.field(Fields::prototypes)
1585 .visitIndexes([&toDo, ¤t,
this, &h, visitedRefs, options](
const DomItem &el) {
1586 return visitPrototypeIndex(toDo, current, *
this, h, visitedRefs, options, el);
1593 function_ref<
bool(
const DomItem &)> visitor, VisitPrototypesOptions options,
1594 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1599 if (k == DomType::QmlObject)
1600 return visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1601 if (visited && id() != 0) {
1602 if (visited->contains(id()))
1604 visited->insert(id());
1608 DomItem v = proceedToScope(h, visitedRefs);
1610 return v.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1614 DomItem v = field(Fields::value);
1616 return v.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1620 DomItem t = field(Fields::type).proceedToScope(h, visitedRefs);
1622 return t.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1630
1631
1632
1633
1634
1635
1636
1637
1638
1640 function_ref<
bool(
const DomItem &)> visitor, VisitPrototypesOptions options,
1641 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1643 QSet<quintptr> visitedLocal;
1645 visited = &visitedLocal;
1646 DomItem current = qmlObject();
1647 DomItem comp = current.component();
1648 if (comp.field(Fields::isSingleton).value().toBool(
false)
1649 && !current.visitPrototypeChain(visitor, options, h, visited, visitedRefs))
1651 if (
DomItem attachedT = current.component().field(Fields::attachedType).field(Fields::get))
1652 if (!attachedT.visitPrototypeChain(
1654 visited, visitedRefs))
1660
1661
1667 if (!visitor(current))
1675
1676
1678 function_ref<
bool(
const DomItem &)> visitor, LookupOptions options,
const ErrorHandler &h,
1679 QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1681 QSet<quintptr> visitedLocal;
1683 visited = &visitedLocal;
1684 QList<Path> visitedRefsLocal;
1686 visitedRefs = &visitedRefsLocal;
1692 QList<DomItem> toDo { current };
1693 bool visitFirst = !(options & LookupOption::SkipFirstScope);
1694 bool visitCurrent = visitFirst;
1696 QSet<quintptr> alreadyAddedComponentMaps;
1697 while (!toDo.isEmpty()) {
1698 DomItem current = toDo.takeLast();
1699 if (visited->contains(current.id()))
1701 visited->insert(current.id());
1702 if (visitCurrent && !visitor(current))
1704 visitCurrent =
true;
1710 DomItem root = current.rootQmlObject();
1711 if (root && root
!= current) {
1725 if ((options & LookupOption::Strict) == 0) {
1726 if (
DomItem comp = current.field(Fields::nextComponent))
1729 if (first && visitFirst && (options & LookupOption::VisitTopClassType)
1730 && *
this == current) {
1731 if (
DomItem attachedT = current.field(Fields::attachedType).field(Fields::get))
1732 toDo.append(attachedT);
1740 if (alreadyAddedComponentMaps.contains(componentMap.id()))
1742 alreadyAddedComponentMaps.insert(componentMap.id());
1743 const auto keys = componentMap.keys();
1744 for (
const QString &x : keys) {
1745 DomItem componentList = componentMap.key(x);
1746 for (
int i = 0; i < componentList.indexes(); ++i) {
1747 DomItem component = componentList.index(i);
1748 if (component != current && !visited->contains(component.id()))
1749 toDo.append(component);
1757 current.field(Fields::importScope))
1758 toDo.append(iScope);
1768 if (
auto globalC = globalScope().field(Fields::rootComponent))
1769 toDo.append(globalC);
1774 if (
DomItem next = current.field(Fields::objects).index(0))
1783 .error(tr(
"Unexpected non scope object %1 (%2) reached in visitScopeChain")
1784 .arg(domTypeToString(current.internalKind()),
1795 const QString &symbolName, function_ref<
bool(
const DomItem &)> visitor, LookupOptions opts,
1796 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1798 return visitScopeChain(
1799 [symbolName, visitor](
const DomItem &obj) {
1800 return obj.visitLocalSymbolsNamed(symbolName,
1801 [visitor](
const DomItem &el) {
return visitor(el); });
1803 opts, h, visited, visitedRefs);
1815 QRegularExpression reTarget = QRegularExpression(QRegularExpression::anchoredPattern(
1816 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>\*?))"));
1818 QRegularExpressionMatch m = reTarget.matchView(target);
1819 if (!m.hasMatch()) {
1821 .error(tr(
"Unexpected complex CppType %1").arg(target)
)
1824 res.baseType = m.captured(u"baseType");
1825 res
.isPointer = !m.captured(u"ptr").isEmpty();
1826 if (!m.captured(u"list").isEmpty()) {
1828 res.baseType = m.captured(u"list");
1829 res
.isPointer = !m.captured(u"listPtr").isEmpty();
1831 if (!m.captured(u"mapValue").isEmpty()) {
1833 if (m.captured(u"mapKey") != u"QString") {
1835 .error(tr(
"Unexpected complex CppType %1 (map with non QString key)")
1839 res.baseType = m.captured(u"mapValue");
1840 res
.isPointer = !m.captured(u"mapPtr").isEmpty();
1852 function_ref<
bool(
const DomItem &)> visitor)
1854 bool correctType =
false;
1856 switch (lookupType) {
1857 case LookupType::Binding:
1860 case LookupType::Method:
1863 case LookupType::Property:
1866 case LookupType::PropertyDef:
1869 case LookupType::Type:
1882 const DomItem &newIt,
const QStringList &subpath,
1883 function_ref<
bool(
const DomItem &)> visitor, LookupType lookupType,
1884 const ErrorHandler &errorHandler, QList<Path> *visitedRefs)
1886 QList<ResolveToDo> lookupToDos(
1887 { ResolveToDo{ newIt, 1 } });
1889 QList<QSet<quintptr>> lookupVisited(subpath.size() + 1);
1890 while (!lookupToDos.isEmpty()) {
1892 auto vNow = std::make_pair(tNow.item.id(), tNow.pathIndex);
1895 Q_ASSERT(iSubPath < subpath.size());
1896 QString subPathNow = subpath[iSubPath++];
1897 DomItem scope = subNow.proceedToScope();
1898 if (iSubPath < subpath.size()) {
1899 if (vNow.first != 0) {
1900 if (lookupVisited[vNow.second].contains(vNow.first))
1903 lookupVisited[vNow.second].insert(vNow.first);
1906 scope.visitDirectAccessibleScopes(
1907 [&lookupToDos, &subPathNow, iSubPath](
const DomItem &el) {
1908 return el.visitLocalSymbolsNamed(
1909 subPathNow, [&lookupToDos, iSubPath](
const DomItem &subEl) {
1910 lookupToDos.append({ subEl, iSubPath });
1917 bool cont = scope.visitDirectAccessibleScopes(
1918 [&visitor, &subPathNow, lookupType](
const DomItem &el) ->
bool {
1919 if (lookupType == LookupType::Symbol)
1920 return el.visitLocalSymbolsNamed(subPathNow, visitor);
1922 return el.visitLocalSymbolsNamed(
1923 subPathNow, [lookupType, &visitor](
const DomItem &el) ->
bool {
1924 return visitForLookupType(el, lookupType, visitor);
1937 const QString &target, function_ref<
bool(
const DomItem &)> visitor, LookupType lookupType,
1938 LookupOptions opts,
const ErrorHandler &errorHandler, QSet<quintptr> *visited,
1939 QList<Path> *visitedRefs)
const
1941 if (target.isEmpty())
1943 switch (lookupType) {
1944 case LookupType::Binding:
1945 case LookupType::Method:
1946 case LookupType::Property:
1947 case LookupType::PropertyDef:
1948 case LookupType::Symbol:
1949 case LookupType::Type: {
1950 QStringList subpath = target.split(QChar::fromLatin1(
'.'));
1951 if (subpath.size() == 1) {
1952 return visitLookup1(subpath.first(), visitor, opts, errorHandler, visited, visitedRefs);
1954 return visitLookup1(
1956 [&subpath, visitor, lookupType, &errorHandler,
1957 visitedRefs](
const DomItem &newIt) ->
bool {
1958 return visitQualifiedNameLookup(newIt, subpath, visitor, lookupType,
1959 errorHandler, visitedRefs);
1961 opts, errorHandler, visited, visitedRefs);
1965 case LookupType::CppType: {
1966 QString baseTarget = CppTypeInfo::fromString(target, errorHandler).baseType;
1970 localQmltypes = localQmltypes
.owner();
1972 if (localQmltypes) {
1973 if (
DomItem localTypes = localQmltypes.field(Fields::components).key(baseTarget)) {
1974 bool cont = localTypes.visitIndexes([&visitor](
const DomItem &els) {
1975 return els.visitIndexes([&visitor](
const DomItem &el) {
1976 if (DomItem obj = el.field(Fields::objects).index(0))
1977 return visitor(obj);
1986 return qmltypes.visitKeys([baseTarget, &visitor](
const QString &,
const DomItem &els) {
1988 els.field(Fields::currentItem).field(Fields::components).key(baseTarget);
1989 return comps.visitIndexes([&visitor](
const DomItem &el) {
1990 if (DomItem obj = el.field(Fields::objects).index(0))
1991 return visitor(obj);
2003
2004
2005
2006
2007
2008
2009
2018 current = current.get(h, visitedRefs);
2022 current = current.field(Fields::type);
2025 current = current.field(Fields::referredObject);
2041 [&res](
const DomItem &el) {
2045 type, opts, errorHandler);
2055 [&res](
const DomItem &el) {
2059 type, opts, errorHandler);
2065 return visitEl([](
auto &&b) {
return b->id(); });
2070 return visitEl([](
auto &&e) {
return e->pathFromOwner(); });
2075 return visitEl([
this](
auto &&e) {
return e->canonicalFilePath(*
this); });
2084 DomItem newItem =
std::visit([
this, &o](
auto &&el) {
2085 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>) {
2088 auto copyPtr = el->makeCopy(o);
2089 return DomItem(m_top, copyPtr, m_ownerPath, copyPtr.get());
2095 std::shared_ptr<DomEnvironment> newEnvPtr;
2096 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
2097 newEnvPtr =
std::make_shared<DomEnvironment>(envPtr, envPtr->loadPaths(), envPtr->options(),
2098 envPtr->domCreationOption());
2099 DomBase *eBase = envPtr.get();
2100 if (
std::holds_alternative<
const DomEnvironment *>(m_element) && eBase
2101 &&
std::get<
const DomEnvironment *>(m_element) == eBase)
2103 }
else if (std::shared_ptr<DomUniverse> univPtr = top().ownerAs<DomUniverse>()) {
2104 newEnvPtr =
std::make_shared<DomEnvironment>(
2113 [
this, newEnvPtr, &o](
auto &&el) {
2114 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>) {
2117 auto copyPtr = el->makeCopy(o);
2118 return DomItem(newEnvPtr, copyPtr, m_ownerPath, copyPtr.get());
2139 case DomType::ModuleIndex:
2140 case DomType::MockOwner:
2141 case DomType::ScriptExpression:
2142 case DomType::AstComments:
2143 case DomType::LoadInfo:
2144 case DomType::FileLocationsNode:
2145 case DomType::DomEnvironment:
2146 case DomType::DomUniverse:
2147 qCWarning(domLog) <<
"DomItem::makeCopy " << internalKindStr()
2148 <<
" does not support binding to environment";
2152 qCWarning(domLog) <<
"DomItem::makeCopy(" << internalKindStr()
2153 <<
") is not an known OwningItem";
2165 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
2166 return envPtr->commitToBase(env, validEnvPtr);
2181 case DomType::QmlObject:
2182 f = field(Fields::propertyDefs);
2184 if (!v.visitIndexes(visitor))
2186 f = field(Fields::bindings);
2188 if (!v.visitIndexes(visitor))
2190 f = field(Fields::methods);
2192 if (!v.visitIndexes(visitor))
2198 case DomType::QmlComponent:
2199 f = field(Fields::ids);
2201 if (!v.visitIndexes(visitor))
2204 case DomType::JsResource:
2205 case DomType::GlobalComponent:
2206 case DomType::QmltypesComponent:
2207 f = field(Fields::enumerations);
2209 if (!v.visitIndexes(visitor))
2213 DomItem params = field(Fields::parameters);
2214 if (!params.visitIndexes([name, visitor](
const DomItem &p) {
2216 if (pPtr->name == name && !visitor(p))
2224 f = field(Fields::components);
2226 if (!v.visitIndexes(visitor))
2231 f = field(Fields::imported);
2233 if (!v.visitIndexes(visitor))
2235 f = field(Fields::qualifiedImports);
2237 if (v && !visitor(v))
2250 if (internalKind() == DomType::Map)
2252 return field(cName);
2257 if (internalKind() == DomType::Map)
2258 return key(cName.toString());
2259 return field(cName);
2269 return base()->value();
2274 sink(u"DomItem{ topPtr:");
2275 sink(QString::number((quintptr)topPtr().get(), 16));
2276 sink(u", ownerPtr:");
2277 sink(QString::number((quintptr)owningItemPtr().get(), 16));
2278 sink(u", ownerPath:");
2279 m_ownerPath.dump(sink);
2281 sink(QString::number((quintptr)base(),16));
2286 const Sink &s,
int indent,
2287 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2289 visitEl([
this, s, indent, filter](
auto &&e) { e->dump(*
this, s, indent, filter); });
2294 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter,
2295 int nBackups,
int indent,
FileWriter *fw)
const
2302 [
this, indent, filter](QTextStream &ts) {
2303 this->dump([&ts](QStringView s) { ts << s; }, indent, filter);
2307 case FileWriter::Status::ShouldWrite:
2308 case FileWriter::Status::SkippedDueToFailure:
2309 qWarning() <<
"Failure dumping " <<
canonicalPath() <<
" to " << path;
2311 case FileWriter::Status::DidWrite:
2312 case FileWriter::Status::SkippedEqual:
2320 return dumperToString([
this](
const Sink &s){ dump(s); });
2325 return std::visit([](
auto &&ow) {
2326 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2329 return ow->derivedFrom();
2335 return std::visit([](
auto &&ow) {
2336 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2339 return ow->revision();
2345 return std::visit([](
auto &&ow) {
2346 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2347 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2349 return ow->createdAt();
2355 return std::visit([](
auto &&ow) {
2356 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2357 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2359 return ow->frozenAt();
2365 return std::visit([](
auto &&ow) {
2366 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2367 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2369 return ow->lastDataUpdateAt();
2375 std::visit([
this, &msg](
auto &&ow) {
2376 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2391 std::visit([&groups](
auto &&ow) {
2392 if constexpr (!std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2393 ow->clearErrors(groups);
2397 iterateSubOwners([groups](
const DomItem &i){
2398 i.clearErrors(groups,
true);
2405 function_ref<
bool(
const DomItem &,
const ErrorMessage &)> visitor,
bool iterate,
2408 if (!
std::visit([
this, visitor, inPath](
auto &&el) {
2409 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2412 return el->iterateErrors(
owner(), visitor, inPath);
2417 if (iterate && !iterateSubOwners([inPath, visitor](
const DomItem &i) {
2418 return i.iterateErrors(visitor,
true, inPath);
2428 return std::visit([
this, visitor](
auto &&o) {
2429 if constexpr (std::is_same_v<std::decay_t<
decltype(o)>, std::monostate>)
2432 return o->iterateSubOwners(
owner(), visitor);
2439 [
this, v](
auto &&el) {
return el->iterateDirectSubpaths(*
this, v); });
2445 List::fromQList<Path>(pathFromOwner().withComponent(c), paths,
2446 [](
const DomItem &list,
const PathEls::PathComponent &p,
const Path &el) {
2447 return list.subReferenceItem(p, el);
2454 return DomItem(m_top, m_owner, m_ownerPath, Reference(referencedObject, Path(c)));
2456 return DomItem(m_top, m_owner, m_ownerPath,
2457 Reference(referencedObject, pathFromOwner().withComponent(c)));
2463 return std::visit([](
auto &&el) -> shared_ptr<
DomTop> {
2464 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2474 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2482
2483
2484
2487 return visitEl([](
auto &&el) ->
const DomBase * {
return el->domBase(); });
2496 DomItem(universePtr, universePtr,
Path(), universePtr.get())
2501
2502
2503
2504
2505
2506
2507
2516 FileToLoad::fromMemory(env, QString(), code),
2518 std::make_optional(fileType));
2519 return tFile.fileObject();
2546 const DomItem &,
const Sink &s,
int,
2553 const Keys &keys,
const QString &targetType)
2564 QSet<QString> ksSet = keys(self);
2565 QStringList ksList = QStringList(ksSet.begin(), ksSet.end());
2566 std::sort(ksList.begin(), ksList.end());
2567 for (
const QString &k : std::as_const(ksList)) {
2568 if (!visitor(PathEls::Key(k), [&self,
this, k]() {
return key(self, k); }))
2576 return m_keys(self);
2581 return m_lookup(self, name);
2585 const DomItem &self,
const Sink &sink,
int indent,
2586 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2589 DomKind dK = self.domKind();
2591 case DomKind::Object:
2592 sink(u"{ \"~type~\":");
2593 sinkEscaped(sink, typeName());
2596 case DomKind::Value:
2598 sink(QString::fromUtf8(value().toJsonValue().toJson()));
2601 case DomKind::Empty:
2610 case DomKind::ScriptElement:
2614 auto closeParens = qScopeGuard(
2617 case DomKind::Object:
2618 sinkNewline(sink, indent);
2621 case DomKind::Value:
2623 case DomKind::Empty:
2626 sinkNewline(sink, indent);
2630 sinkNewline(sink, indent);
2633 case DomKind::ScriptElement:
2639 self.iterateDirectSubpaths(
2641 function_ref<DomItem()> itemF) {
2643 if (!filter(self, c, i))
2651 sinkNewline(sink, indent + 2);
2652 if (dK != DomKind::Object)
2653 sink(u"UNEXPECTED ENTRY ERROR:");
2654 sinkEscaped(sink, c.name());
2658 sinkNewline(sink, indent + 2);
2659 if (dK != DomKind::Map)
2660 sink(u"UNEXPECTED ENTRY ERROR:");
2661 sinkEscaped(sink, c.name());
2665 sinkNewline(sink, indent + 2);
2666 if (dK != DomKind::List)
2667 sink(u"UNEXPECTED ENTRY ERROR:");
2668 else if (idx++ != c.index())
2669 sink(u"OUT OF ORDER ARRAY:");
2672 sinkNewline(sink, indent + 2);
2673 sink(u"UNEXPECTED PATH KIND ERROR (ignored)");
2677 i.dump(sink, indent + 2, filter);
2679 sink(uR"({ "~type~": "Reference", "immediate": true, "referredObjectPath":")");
2691 const QString &elType):
2702 const DomItem &self,
const Sink &sink,
int indent,
2703 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2707 iterateDirectSubpaths(
2709 [&self, indent, &first, sink, filter](
const PathEls::PathComponent &c,
2710 function_ref<DomItem()> itemF) {
2711 DomItem item = itemF();
2712 if (!filter(self, c, item))
2718 sinkNewline(sink, indent + 2);
2719 item.dump(sink, indent + 2, filter);
2728 return m_iterator(self, [visitor](index_type i, function_ref<DomItem()> itemF) {
2729 return visitor(PathEls::Index(i), itemF);
2732 index_type len = indexes(self);
2733 for (index_type i = 0; i < len; ++i) {
2734 if (!visitor(
PathEls::Index(i), [
this, &self, i]() {
return index(self, i); }))
2742 return m_length(self);
2747 return m_lookup(self, index);
2753 ow.writeRegion(fLoc, LeftBracketRegion);
2755 iterateDirectSubpaths(self,
2756 [&ow, &first, &fLoc, compact](
const PathEls::PathComponent &,
2757 function_ref<DomItem()> elF) {
2761 ow.writeRegion(fLoc, CommaTokenRegion).ensureSpace();
2763 ow.ensureNewline(1);
2768 if (!compact && !first)
2770 ow.writeRegion(fLoc, RightBracketRegion);
2777 Q_ASSERT(m_pathFromOwner &&
"uninitialized DomElement");
2783 Q_ASSERT(m_pathFromOwner &&
"uninitialized DomElement");
2790 m_pathFromOwner = newPath;
2795 for (
const Path &p : referredObjectPath) {
2796 switch (p.headKind()) {
2797 case Path::Kind::Current:
2798 switch (p.headCurrent()) {
2799 case PathCurrent::Lookup:
2800 case PathCurrent::LookupDynamic:
2801 case PathCurrent::LookupStrict:
2802 case PathCurrent::ObjChain:
2803 case PathCurrent::ScopeChain:
2809 case Path::Kind::Empty:
2810 case Path::Kind::Any:
2811 case Path::Kind::Filter:
2833 cont = cont && self.invokeVisitorOnLazyField(visitor, Fields::referredObjectPath, [
this]() {
2834 return referredObjectPath.toString();
2836 cont = cont && visitor(
PathEls::Field(Fields::get), [
this, &self]() {
return this->get(self); });
2842 if (
Fields::referredObjectPath == name) {
2843 return self.subDataItem(
PathEls::Field(Fields::referredObjectPath),
2844 referredObjectPath.toString());
2846 if (Fields::get == name)
2853 return QList<QString>({Fields::referredObjectPath.toString(), Fields::get.toString()});
2869 if (referredObjectPath) {
2877 RefCacheEntry cached = RefCacheEntry::forPath(self, selfPath);
2878 switch (cached.cached) {
2879 case RefCacheEntry::Cached::None:
2881 case RefCacheEntry::Cached::First:
2882 case RefCacheEntry::Cached::All:
2883 if (!cached.canonicalPaths.isEmpty())
2884 cachedPath = cached.canonicalPaths.first();
2892 qCWarning(refLog) <<
"referenceCache outdated, reference at " << selfPath
2893 <<
" leads to invalid path " << cachedPath;
2899 QList<Path> visitedRefsLocal;
2907 (visitedRefs ? visitedRefs : &visitedRefsLocal));
2910 env, selfPath, RefCacheEntry { RefCacheEntry::Cached::First, { cachedPath } });
2919 if (referredObjectPath) {
2922 QList<Path> cachedPaths;
2926 RefCacheEntry cached = RefCacheEntry::forPath(env, selfPath);
2927 switch (cached.cached) {
2928 case RefCacheEntry::Cached::None:
2929 case RefCacheEntry::Cached::First:
2931 case RefCacheEntry::Cached::All:
2932 cachedPaths += cached.canonicalPaths;
2933 if (cachedPaths.isEmpty())
2937 if (!cachedPaths.isEmpty()) {
2938 bool outdated =
false;
2939 for (
const Path &p : cachedPaths) {
2940 DomItem newEl = env.path(p);
2943 qCWarning(refLog) <<
"referenceCache outdated, reference at " << selfPath
2944 <<
" leads to invalid path " << p;
2964 QList<Path> canonicalPaths;
2965 for (
const DomItem &i : res) {
2967 canonicalPaths.append(i.canonicalPath());
2970 <<
"getAll of reference at " << selfPath <<
" visits empty items.";
2974 RefCacheEntry { RefCacheEntry::Cached::All, std::move(canonicalPaths) });
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2998 : m_derivedFrom(derivedFrom),
3006 : m_derivedFrom(derivedFrom),
3020 QMultiMap<Path, ErrorMessage> my_errors;
3022 QMutexLocker l1(o.mutex());
3023 my_errors = o.m_errors;
3027 QMutexLocker l2(mutex());
3028 m_errors = my_errors;
3035 static QAtomicInt nextRev(0);
3042 cont = cont && visitor(
PathEls::Field(Fields::errors), [&self,
this]() {
3043 QMultiMap<Path, ErrorMessage> myErrors = localErrors();
3044 return self.subMapItem(Map(
3045 self.pathFromOwner().withField(Fields::errors),
3046 [myErrors](
const DomItem &map,
const QString &key) {
3047 auto it = myErrors.find(Path::fromString(key));
3048 if (it != myErrors.end())
3049 return map.subDataItem(PathEls::Key(key), it->toCbor(),
3050 ConstantData::Options::FirstMapIsFields);
3054 [myErrors](
const DomItem &) {
3056 auto it = myErrors.keyBegin();
3057 auto end = myErrors.keyEnd();
3059 res.insert(it++->toString());
3062 QLatin1String(
"ErrorMessages")));
3070 if (s.pathFromSource) {
3071 if (!s.pathToSource)
3073 return self
.path(s.pathToSource
);
3080 return m_derivedFrom;
3090 return m_frozenAt > m_createdAt;
3096 m_frozenAt = QDateTime::currentDateTimeUtc();
3097 if (m_frozenAt <= m_createdAt)
3098 m_frozenAt = m_createdAt.addSecs(1);
3111 return m_lastDataUpdateAt;
3121 if (m_lastDataUpdateAt < tNew)
3122 m_lastDataUpdateAt = tNew;
3132 QMutexLocker l(mutex());
3133 quint32 &c = m_errorsCounts[msg];
3136 m_errors.insert(msg.path, msg);
3141 QMutexLocker l(mutex());
3142 auto it = m_errors.begin();
3143 while (it != m_errors.end()) {
3144 if (it->errorGroups == groups)
3145 it = m_errors.erase(it);
3152 const DomItem &self, function_ref<
bool(
const DomItem &,
const ErrorMessage &)> visitor,
3155 QMultiMap<Path, ErrorMessage> myErrors;
3157 QMutexLocker l(mutex());
3158 myErrors = m_errors;
3160 auto it = myErrors.lowerBound(inPath);
3161 auto end = myErrors.end();
3162 while (it != end && it.key().mid(0, inPath
.length()) == inPath) {
3163 if (!visitor(self, *it++))
3171 return self.iterateDirectSubpaths(
3174 if (i.owningItemPtr() != self.owningItemPtr()) {
3176 if (container.id() == self.id())
3185 if (o1.m_kind != o2.m_kind)
3187 return o1.visitEl([&o1, &o2](
auto &&el1) {
3188 auto &&el2 = std::get<std::decay_t<
decltype(el1)>>(o2.m_element);
3189 auto id1 = el1->id();
3190 auto id2 = el2->id();
3193 if (id1 != quintptr(0))
3195 if (o1.m_owner != o2.m_owner)
3197 Path p1 = el1->pathFromOwner();
3198 Path p2 = el2->pathFromOwner();
3217 Q_ASSERT(
false &&
"addPropertyDef on non qml scope");
3226 Q_ASSERT(
false &&
"addBinding on non qml scope");
3235 Q_ASSERT(
false &&
"addMethod on non qml scope");
3243 }
else if (QmlComponent *el = mutableAs<QmlComponent>()) {
3247 Q_ASSERT(
false &&
"addChild on non qml scope");
3255 dumperToQDebug([&c](
const Sink &s) { c.dump(s); }, debug);
3262 return debug.noquote().nospace() <<
"MutableDomItem(" << domTypeToString(cc.internalKind())
3263 <<
", " << cc.canonicalPath().toString() <<
")";
3268 index_type len = index_type(m_pList.size());
3269 for (index_type i = 0; i < len; ++i) {
3270 if (!v(
PathEls::Index(i), [
this, &self, i] {
return this->index(self, i); }))
3279 ow.writeRegion(fLoc, LeftBracketRegion);
3281 index_type len = index_type(m_pList.size());
3282 for (index_type i = 0; i < len; ++i) {
3286 ow.writeRegion(fLoc, CommaTokenRegion).ensureSpace();
3288 ow.ensureNewline(1);
3292 if (!compact && !first)
3294 ow.writeRegion(fLoc, RightBracketRegion);
3307
3308
3309
3310
3311
3330 return fileItem.ownerAs<JsFile>();
3332 return fileItem.ownerAs<QmlFile>();
3334 Q_UNREACHABLE_RETURN({});
3343#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
DomItem globalScope() const
DomItem(const std::shared_ptr< DomEnvironment > &)
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
FileWriter::Status dump(const QString &path, function_ref< bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter=noFilter, int nBackups=2, int indent=0, FileWriter *fw=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
bool writeOut(const QString &path, int nBackups=2, const LineWriterOptions &opt=LineWriterOptions(), FileWriter *fw=nullptr, WriteOutChecks extraChecks=WriteOutCheck::Default) 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.
Path operator[](int i) const
Path mid(int offset, int length) const
std::function< bool(const DomItem &)> headFilter() const
PathRoot headRoot() const
MutableDomItem addBinding(MutableDomItem &self, const Binding &binding, AddOption option)
MutableDomItem addChild(MutableDomItem &self, const QmlObject &child)
static constexpr DomType kindValue
MutableDomItem addPropertyDef(MutableDomItem &self, const PropertyDefinition &propertyDef, AddOption option)
MutableDomItem addMethod(MutableDomItem &self, const MethodInfo &functionDef, AddOption option)
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()