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 WriteOutChecks extraChecks)
const
1347 auto status = fw->write(path, [
this, path, &options, extraChecks](QTextStream &ts) {
1348 auto lw = createLineWriter([&ts](QStringView s) { ts << s; }, path, options);
1349 OutWriter ow(getFileItemOwner(fileObject()), *lw);
1350 return writeOutForFile(ow, extraChecks);
1353 case FileWriter::Status::DidWrite:
1354 case FileWriter::Status::SkippedEqual:
1356 case FileWriter::Status::ShouldWrite:
1357 case FileWriter::Status::SkippedDueToFailure:
1358 qCWarning(writeOutLog) <<
"failure reformatting " << path;
1361 qCWarning(writeOutLog) <<
"Unknown FileWriter::Status ";
1369 bool isChild =
false;
1382 bool hasAnnotations =
false;
1386 if (
const Id *myPtr = as<
Id>())
1387 hasAnnotations = !myPtr->annotations.isEmpty();
1391 hasAnnotations = !myPtr->annotations.isEmpty();
1395 hasAnnotations = !myPtr->annotations.isEmpty();
1399 hasAnnotations = !myPtr->annotations().isEmpty();
1403 hasAnnotations = !myPtr->annotations().isEmpty();
1408 return hasAnnotations;
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1434 VisitOptions options, DomItem::ChildrenVisitor openingVisitor,
1435 DomItem::ChildrenVisitor closingVisitor,
const FieldFilter &filter)
const
1439 if (options & VisitOption::VisitSelf && !visitor(basePath, *
this,
true))
1441 if (options & VisitOption::VisitSelf && !openingVisitor(basePath, *
this,
true))
1443 auto atEnd = qScopeGuard([closingVisitor, basePath,
this, options]() {
1444 if (options & VisitOption::VisitSelf) {
1445 closingVisitor(basePath, *
this,
true);
1448 return iterateDirectSubpaths(
1449 [
this, basePath, visitor, openingVisitor, closingVisitor, options,
1450 &filter](
const PathEls::PathComponent &c, function_ref<DomItem()> itemF) {
1452 if (!(options & VisitOption::NoPath)) {
1454 pNow = pNow.withComponent(c);
1456 if (!filter(*
this, c, DomItem{}))
1458 DomItem item = itemF();
1459 bool directChild = isCanonicalChild(item);
1460 if (!directChild && !(options & VisitOption::VisitAdopted))
1462 if (!directChild || !(options & VisitOption::Recurse)) {
1463 if (!visitor(pNow, item, directChild))
1468 if (!openingVisitor(pNow, item, directChild))
1470 closingVisitor(pNow, item, directChild);
1472 return item.visitTree(pNow, visitor, options | VisitOption::VisitSelf,
1473 openingVisitor, closingVisitor, filter);
1480 QList<Path> *visitedRefs, VisitPrototypesOptions options,
1484 if (visitedRefs->contains(elId))
1487 visitedRefs->append(elId);
1488 QList<DomItem> protos = prototype.getAll(h, visitedRefs);
1489 if (protos.isEmpty()) {
1490 if (std::shared_ptr<DomEnvironment> envPtr =
1491 derivedFromPrototype.environment().ownerAs<DomEnvironment>())
1494 .warning(derivedFromPrototype.tr(
"could not resolve prototype %1 (%2)")
1496 prototype.field(Fields::referredObjectPath)
1499 .withItem(derivedFromPrototype)
1502 if (protos.size() > 1) {
1503 QStringList protoPaths;
1504 for (
const DomItem &p : protos)
1505 protoPaths.append(p.canonicalPath().toString());
1508 .tr(
"Multiple definitions found, using first only, resolving "
1509 "prototype %1 (%2): %3")
1511 prototype.field(Fields::referredObjectPath)
1514 protoPaths.join(QLatin1String(
", ")))
)
1515 .withItem(derivedFromPrototype)
1520 for (
int i = nProtos; i != 0;) {
1521 DomItem proto = protos.at(--i);
1524 proto = proto.proceedToScope(h, visitedRefs);
1531 .warning(derivedFromPrototype.tr(
"Unexpected prototype type %1 (%2)")
1533 prototype.field(Fields::referredObjectPath)
1536 .withItem(derivedFromPrototype)
1546 QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1548 QSet<quintptr> visitedLocal;
1550 visited = &visitedLocal;
1551 QList<Path> refsLocal;
1553 visitedRefs = &refsLocal;
1555 DomItem current = qmlObject();
1560 QList<DomItem> toDo({ current });
1561 while (!toDo.isEmpty()) {
1562 current = toDo.takeLast();
1563 current = current.proceedToScope(h, visitedRefs);
1564 if (visited->contains(current.id())) {
1570 .warning(tr(
"Detected multiple visit of %1 visiting prototypes of %2")
1577 visited->insert(current.id());
1578 if (shouldVisit && !visitor(current))
1581 current.field(Fields::prototypes)
1582 .visitIndexes([&toDo, ¤t,
this, &h, visitedRefs, options](
const DomItem &el) {
1583 return visitPrototypeIndex(toDo, current, *
this, h, visitedRefs, options, el);
1590 function_ref<
bool(
const DomItem &)> visitor, VisitPrototypesOptions options,
1591 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1596 if (k == DomType::QmlObject)
1597 return visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1598 if (visited && id() != 0) {
1599 if (visited->contains(id()))
1601 visited->insert(id());
1605 DomItem v = proceedToScope(h, visitedRefs);
1607 return v.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1611 DomItem v = field(Fields::value);
1613 return v.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1617 DomItem t = field(Fields::type).proceedToScope(h, visitedRefs);
1619 return t.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1627
1628
1629
1630
1631
1632
1633
1634
1635
1637 function_ref<
bool(
const DomItem &)> visitor, VisitPrototypesOptions options,
1638 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1640 QSet<quintptr> visitedLocal;
1642 visited = &visitedLocal;
1643 DomItem current = qmlObject();
1644 DomItem comp = current.component();
1645 if (comp.field(Fields::isSingleton).value().toBool(
false)
1646 && !current.visitPrototypeChain(visitor, options, h, visited, visitedRefs))
1648 if (
DomItem attachedT = current.component().field(Fields::attachedType).field(Fields::get))
1649 if (!attachedT.visitPrototypeChain(
1651 visited, visitedRefs))
1657
1658
1664 if (!visitor(current))
1672
1673
1675 function_ref<
bool(
const DomItem &)> visitor, LookupOptions options,
const ErrorHandler &h,
1676 QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1678 QSet<quintptr> visitedLocal;
1680 visited = &visitedLocal;
1681 QList<Path> visitedRefsLocal;
1683 visitedRefs = &visitedRefsLocal;
1689 QList<DomItem> toDo { current };
1690 bool visitFirst = !(options & LookupOption::SkipFirstScope);
1691 bool visitCurrent = visitFirst;
1693 QSet<quintptr> alreadyAddedComponentMaps;
1694 while (!toDo.isEmpty()) {
1695 DomItem current = toDo.takeLast();
1696 if (visited->contains(current.id()))
1698 visited->insert(current.id());
1699 if (visitCurrent && !visitor(current))
1701 visitCurrent =
true;
1707 DomItem root = current.rootQmlObject();
1708 if (root && root
!= current) {
1722 if ((options & LookupOption::Strict) == 0) {
1723 if (
DomItem comp = current.field(Fields::nextComponent))
1726 if (first && visitFirst && (options & LookupOption::VisitTopClassType)
1727 && *
this == current) {
1728 if (
DomItem attachedT = current.field(Fields::attachedType).field(Fields::get))
1729 toDo.append(attachedT);
1737 if (alreadyAddedComponentMaps.contains(componentMap.id()))
1739 alreadyAddedComponentMaps.insert(componentMap.id());
1740 const auto keys = componentMap.keys();
1741 for (
const QString &x : keys) {
1742 DomItem componentList = componentMap.key(x);
1743 for (
int i = 0; i < componentList.indexes(); ++i) {
1744 DomItem component = componentList.index(i);
1745 if (component != current && !visited->contains(component.id()))
1746 toDo.append(component);
1754 current.field(Fields::importScope))
1755 toDo.append(iScope);
1765 if (
auto globalC = globalScope().field(Fields::rootComponent))
1766 toDo.append(globalC);
1771 if (
DomItem next = current.field(Fields::objects).index(0))
1780 .error(tr(
"Unexpected non scope object %1 (%2) reached in visitScopeChain")
1781 .arg(domTypeToString(current.internalKind()),
1792 const QString &symbolName, function_ref<
bool(
const DomItem &)> visitor, LookupOptions opts,
1793 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1795 return visitScopeChain(
1796 [symbolName, visitor](
const DomItem &obj) {
1797 return obj.visitLocalSymbolsNamed(symbolName,
1798 [visitor](
const DomItem &el) {
return visitor(el); });
1800 opts, h, visited, visitedRefs);
1812 QRegularExpression reTarget = QRegularExpression(QRegularExpression::anchoredPattern(
1813 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>\*?))"));
1815 QRegularExpressionMatch m = reTarget.matchView(target);
1816 if (!m.hasMatch()) {
1818 .error(tr(
"Unexpected complex CppType %1").arg(target)
)
1821 res.baseType = m.captured(u"baseType");
1822 res
.isPointer = !m.captured(u"ptr").isEmpty();
1823 if (!m.captured(u"list").isEmpty()) {
1825 res.baseType = m.captured(u"list");
1826 res
.isPointer = !m.captured(u"listPtr").isEmpty();
1828 if (!m.captured(u"mapValue").isEmpty()) {
1830 if (m.captured(u"mapKey") != u"QString") {
1832 .error(tr(
"Unexpected complex CppType %1 (map with non QString key)")
1836 res.baseType = m.captured(u"mapValue");
1837 res
.isPointer = !m.captured(u"mapPtr").isEmpty();
1849 function_ref<
bool(
const DomItem &)> visitor)
1851 bool correctType =
false;
1853 switch (lookupType) {
1854 case LookupType::Binding:
1857 case LookupType::Method:
1860 case LookupType::Property:
1863 case LookupType::PropertyDef:
1866 case LookupType::Type:
1879 const DomItem &newIt,
const QStringList &subpath,
1880 function_ref<
bool(
const DomItem &)> visitor, LookupType lookupType,
1881 const ErrorHandler &errorHandler, QList<Path> *visitedRefs)
1883 QList<ResolveToDo> lookupToDos(
1884 { ResolveToDo{ newIt, 1 } });
1886 QList<QSet<quintptr>> lookupVisited(subpath.size() + 1);
1887 while (!lookupToDos.isEmpty()) {
1889 auto vNow = std::make_pair(tNow.item.id(), tNow.pathIndex);
1892 Q_ASSERT(iSubPath < subpath.size());
1893 QString subPathNow = subpath[iSubPath++];
1894 DomItem scope = subNow.proceedToScope();
1895 if (iSubPath < subpath.size()) {
1896 if (vNow.first != 0) {
1897 if (lookupVisited[vNow.second].contains(vNow.first))
1900 lookupVisited[vNow.second].insert(vNow.first);
1903 scope.visitDirectAccessibleScopes(
1904 [&lookupToDos, &subPathNow, iSubPath](
const DomItem &el) {
1905 return el.visitLocalSymbolsNamed(
1906 subPathNow, [&lookupToDos, iSubPath](
const DomItem &subEl) {
1907 lookupToDos.append({ subEl, iSubPath });
1914 bool cont = scope.visitDirectAccessibleScopes(
1915 [&visitor, &subPathNow, lookupType](
const DomItem &el) ->
bool {
1916 if (lookupType == LookupType::Symbol)
1917 return el.visitLocalSymbolsNamed(subPathNow, visitor);
1919 return el.visitLocalSymbolsNamed(
1920 subPathNow, [lookupType, &visitor](
const DomItem &el) ->
bool {
1921 return visitForLookupType(el, lookupType, visitor);
1934 const QString &target, function_ref<
bool(
const DomItem &)> visitor, LookupType lookupType,
1935 LookupOptions opts,
const ErrorHandler &errorHandler, QSet<quintptr> *visited,
1936 QList<Path> *visitedRefs)
const
1938 if (target.isEmpty())
1940 switch (lookupType) {
1941 case LookupType::Binding:
1942 case LookupType::Method:
1943 case LookupType::Property:
1944 case LookupType::PropertyDef:
1945 case LookupType::Symbol:
1946 case LookupType::Type: {
1947 QStringList subpath = target.split(QChar::fromLatin1(
'.'));
1948 if (subpath.size() == 1) {
1949 return visitLookup1(subpath.first(), visitor, opts, errorHandler, visited, visitedRefs);
1951 return visitLookup1(
1953 [&subpath, visitor, lookupType, &errorHandler,
1954 visitedRefs](
const DomItem &newIt) ->
bool {
1955 return visitQualifiedNameLookup(newIt, subpath, visitor, lookupType,
1956 errorHandler, visitedRefs);
1958 opts, errorHandler, visited, visitedRefs);
1962 case LookupType::CppType: {
1963 QString baseTarget = CppTypeInfo::fromString(target, errorHandler).baseType;
1967 localQmltypes = localQmltypes
.owner();
1969 if (localQmltypes) {
1970 if (
DomItem localTypes = localQmltypes.field(Fields::components).key(baseTarget)) {
1971 bool cont = localTypes.visitIndexes([&visitor](
const DomItem &els) {
1972 return els.visitIndexes([&visitor](
const DomItem &el) {
1973 if (DomItem obj = el.field(Fields::objects).index(0))
1974 return visitor(obj);
1983 return qmltypes.visitKeys([baseTarget, &visitor](
const QString &,
const DomItem &els) {
1985 els.field(Fields::currentItem).field(Fields::components).key(baseTarget);
1986 return comps.visitIndexes([&visitor](
const DomItem &el) {
1987 if (DomItem obj = el.field(Fields::objects).index(0))
1988 return visitor(obj);
2000
2001
2002
2003
2004
2005
2006
2015 current = current.get(h, visitedRefs);
2019 current = current.field(Fields::type);
2022 current = current.field(Fields::referredObject);
2038 [&res](
const DomItem &el) {
2042 type, opts, errorHandler);
2052 [&res](
const DomItem &el) {
2056 type, opts, errorHandler);
2062 return visitEl([](
auto &&b) {
return b->id(); });
2067 return visitEl([](
auto &&e) {
return e->pathFromOwner(); });
2072 return visitEl([
this](
auto &&e) {
return e->canonicalFilePath(*
this); });
2081 DomItem newItem =
std::visit([
this, &o](
auto &&el) {
2082 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>) {
2085 auto copyPtr = el->makeCopy(o);
2086 return DomItem(m_top, copyPtr, m_ownerPath, copyPtr.get());
2092 std::shared_ptr<DomEnvironment> newEnvPtr;
2093 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
2094 newEnvPtr =
std::make_shared<DomEnvironment>(envPtr, envPtr->loadPaths(), envPtr->options(),
2095 envPtr->domCreationOption());
2096 DomBase *eBase = envPtr.get();
2097 if (
std::holds_alternative<
const DomEnvironment *>(m_element) && eBase
2098 &&
std::get<
const DomEnvironment *>(m_element) == eBase)
2100 }
else if (std::shared_ptr<DomUniverse> univPtr = top().ownerAs<DomUniverse>()) {
2101 newEnvPtr =
std::make_shared<DomEnvironment>(
2110 [
this, newEnvPtr, &o](
auto &&el) {
2111 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>) {
2114 auto copyPtr = el->makeCopy(o);
2115 return DomItem(newEnvPtr, copyPtr, m_ownerPath, copyPtr.get());
2136 case DomType::ModuleIndex:
2137 case DomType::MockOwner:
2138 case DomType::ScriptExpression:
2139 case DomType::AstComments:
2140 case DomType::LoadInfo:
2141 case DomType::FileLocationsNode:
2142 case DomType::DomEnvironment:
2143 case DomType::DomUniverse:
2144 qCWarning(domLog) <<
"DomItem::makeCopy " << internalKindStr()
2145 <<
" does not support binding to environment";
2149 qCWarning(domLog) <<
"DomItem::makeCopy(" << internalKindStr()
2150 <<
") is not an known OwningItem";
2162 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
2163 return envPtr->commitToBase(env, validEnvPtr);
2178 case DomType::QmlObject:
2179 f = field(Fields::propertyDefs);
2181 if (!v.visitIndexes(visitor))
2183 f = field(Fields::bindings);
2185 if (!v.visitIndexes(visitor))
2187 f = field(Fields::methods);
2189 if (!v.visitIndexes(visitor))
2195 case DomType::QmlComponent:
2196 f = field(Fields::ids);
2198 if (!v.visitIndexes(visitor))
2201 case DomType::JsResource:
2202 case DomType::GlobalComponent:
2203 case DomType::QmltypesComponent:
2204 f = field(Fields::enumerations);
2206 if (!v.visitIndexes(visitor))
2210 DomItem params = field(Fields::parameters);
2211 if (!params.visitIndexes([name, visitor](
const DomItem &p) {
2213 if (pPtr->name == name && !visitor(p))
2221 f = field(Fields::components);
2223 if (!v.visitIndexes(visitor))
2228 f = field(Fields::imported);
2230 if (!v.visitIndexes(visitor))
2232 f = field(Fields::qualifiedImports);
2234 if (v && !visitor(v))
2247 if (internalKind() == DomType::Map)
2249 return field(cName);
2254 if (internalKind() == DomType::Map)
2255 return key(cName.toString());
2256 return field(cName);
2266 return base()->value();
2271 sink(u"DomItem{ topPtr:");
2272 sink(QString::number((quintptr)topPtr().get(), 16));
2273 sink(u", ownerPtr:");
2274 sink(QString::number((quintptr)owningItemPtr().get(), 16));
2275 sink(u", ownerPath:");
2276 m_ownerPath.dump(sink);
2278 sink(QString::number((quintptr)base(),16));
2283 const Sink &s,
int indent,
2284 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2286 visitEl([
this, s, indent, filter](
auto &&e) { e->dump(*
this, s, indent, filter); });
2290 const QString &path,
2291 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter,
2297 switch (fw->write(path, [
this, indent, filter](QTextStream &ts) {
2298 this->dump([&ts](QStringView s) { ts << s; }, indent, filter);
2301 case FileWriter::Status::ShouldWrite:
2302 case FileWriter::Status::SkippedDueToFailure:
2303 qWarning() <<
"Failure dumping " <<
canonicalPath() <<
" to " << path;
2305 case FileWriter::Status::DidWrite:
2306 case FileWriter::Status::SkippedEqual:
2314 return dumperToString([
this](
const Sink &s){ dump(s); });
2319 return std::visit([](
auto &&ow) {
2320 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2323 return ow->derivedFrom();
2329 return std::visit([](
auto &&ow) {
2330 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2333 return ow->revision();
2339 return std::visit([](
auto &&ow) {
2340 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2341 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2343 return ow->createdAt();
2349 return std::visit([](
auto &&ow) {
2350 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2351 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2353 return ow->frozenAt();
2359 return std::visit([](
auto &&ow) {
2360 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2361 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2363 return ow->lastDataUpdateAt();
2369 std::visit([
this, &msg](
auto &&ow) {
2370 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2385 std::visit([&groups](
auto &&ow) {
2386 if constexpr (!std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2387 ow->clearErrors(groups);
2391 iterateSubOwners([groups](
const DomItem &i){
2392 i.clearErrors(groups,
true);
2399 function_ref<
bool(
const DomItem &,
const ErrorMessage &)> visitor,
bool iterate,
2402 if (!
std::visit([
this, visitor, inPath](
auto &&el) {
2403 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2406 return el->iterateErrors(
owner(), visitor, inPath);
2411 if (iterate && !iterateSubOwners([inPath, visitor](
const DomItem &i) {
2412 return i.iterateErrors(visitor,
true, inPath);
2422 return std::visit([
this, visitor](
auto &&o) {
2423 if constexpr (std::is_same_v<std::decay_t<
decltype(o)>, std::monostate>)
2426 return o->iterateSubOwners(
owner(), visitor);
2433 [
this, v](
auto &&el) {
return el->iterateDirectSubpaths(*
this, v); });
2439 List::fromQList<Path>(pathFromOwner().withComponent(c), paths,
2440 [](
const DomItem &list,
const PathEls::PathComponent &p,
const Path &el) {
2441 return list.subReferenceItem(p, el);
2448 return DomItem(m_top, m_owner, m_ownerPath, Reference(referencedObject, Path(c)));
2450 return DomItem(m_top, m_owner, m_ownerPath,
2451 Reference(referencedObject, pathFromOwner().withComponent(c)));
2457 return std::visit([](
auto &&el) -> shared_ptr<
DomTop> {
2458 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2468 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2476
2477
2478
2481 return visitEl([](
auto &&el) ->
const DomBase * {
return el->domBase(); });
2490 DomItem(universePtr, universePtr,
Path(), universePtr.get())
2495
2496
2497
2498
2499
2500
2501
2510 FileToLoad::fromMemory(env, QString(), code),
2512 std::make_optional(fileType));
2513 return tFile.fileObject();
2540 const DomItem &,
const Sink &s,
int,
2547 const Keys &keys,
const QString &targetType)
2558 QSet<QString> ksSet = keys(self);
2559 QStringList ksList = QStringList(ksSet.begin(), ksSet.end());
2560 std::sort(ksList.begin(), ksList.end());
2561 for (
const QString &k : std::as_const(ksList)) {
2562 if (!visitor(PathEls::Key(k), [&self,
this, k]() {
return key(self, k); }))
2570 return m_keys(self);
2575 return m_lookup(self, name);
2579 const DomItem &self,
const Sink &sink,
int indent,
2580 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2583 DomKind dK = self.domKind();
2585 case DomKind::Object:
2586 sink(u"{ \"~type~\":");
2587 sinkEscaped(sink, typeName());
2590 case DomKind::Value:
2592 sink(QString::fromUtf8(value().toJsonValue().toJson()));
2595 case DomKind::Empty:
2604 case DomKind::ScriptElement:
2608 auto closeParens = qScopeGuard(
2611 case DomKind::Object:
2612 sinkNewline(sink, indent);
2615 case DomKind::Value:
2617 case DomKind::Empty:
2620 sinkNewline(sink, indent);
2624 sinkNewline(sink, indent);
2627 case DomKind::ScriptElement:
2633 self.iterateDirectSubpaths(
2635 function_ref<DomItem()> itemF) {
2637 if (!filter(self, c, i))
2645 sinkNewline(sink, indent + 2);
2646 if (dK != DomKind::Object)
2647 sink(u"UNEXPECTED ENTRY ERROR:");
2648 sinkEscaped(sink, c.name());
2652 sinkNewline(sink, indent + 2);
2653 if (dK != DomKind::Map)
2654 sink(u"UNEXPECTED ENTRY ERROR:");
2655 sinkEscaped(sink, c.name());
2659 sinkNewline(sink, indent + 2);
2660 if (dK != DomKind::List)
2661 sink(u"UNEXPECTED ENTRY ERROR:");
2662 else if (idx++ != c.index())
2663 sink(u"OUT OF ORDER ARRAY:");
2666 sinkNewline(sink, indent + 2);
2667 sink(u"UNEXPECTED PATH KIND ERROR (ignored)");
2671 i.dump(sink, indent + 2, filter);
2673 sink(uR"({ "~type~": "Reference", "immediate": true, "referredObjectPath":")");
2685 const QString &elType):
2696 const DomItem &self,
const Sink &sink,
int indent,
2697 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2701 iterateDirectSubpaths(
2703 [&self, indent, &first, sink, filter](
const PathEls::PathComponent &c,
2704 function_ref<DomItem()> itemF) {
2705 DomItem item = itemF();
2706 if (!filter(self, c, item))
2712 sinkNewline(sink, indent + 2);
2713 item.dump(sink, indent + 2, filter);
2722 return m_iterator(self, [visitor](index_type i, function_ref<DomItem()> itemF) {
2723 return visitor(PathEls::Index(i), itemF);
2726 index_type len = indexes(self);
2727 for (index_type i = 0; i < len; ++i) {
2728 if (!visitor(
PathEls::Index(i), [
this, &self, i]() {
return index(self, i); }))
2736 return m_length(self);
2741 return m_lookup(self, index);
2747 ow.writeRegion(fLoc, LeftBracketRegion);
2749 iterateDirectSubpaths(self,
2750 [&ow, &first, &fLoc, compact](
const PathEls::PathComponent &,
2751 function_ref<DomItem()> elF) {
2755 ow.writeRegion(fLoc, CommaTokenRegion).ensureSpace();
2757 ow.ensureNewline(1);
2762 if (!compact && !first)
2764 ow.writeRegion(fLoc, RightBracketRegion);
2771 Q_ASSERT(m_pathFromOwner &&
"uninitialized DomElement");
2777 Q_ASSERT(m_pathFromOwner &&
"uninitialized DomElement");
2784 m_pathFromOwner = newPath;
2789 for (
const Path &p : referredObjectPath) {
2790 switch (p.headKind()) {
2791 case Path::Kind::Current:
2792 switch (p.headCurrent()) {
2793 case PathCurrent::Lookup:
2794 case PathCurrent::LookupDynamic:
2795 case PathCurrent::LookupStrict:
2796 case PathCurrent::ObjChain:
2797 case PathCurrent::ScopeChain:
2803 case Path::Kind::Empty:
2804 case Path::Kind::Any:
2805 case Path::Kind::Filter:
2827 cont = cont && self.invokeVisitorOnLazyField(visitor, Fields::referredObjectPath, [
this]() {
2828 return referredObjectPath.toString();
2830 cont = cont && visitor(
PathEls::Field(Fields::get), [
this, &self]() {
return this->get(self); });
2836 if (
Fields::referredObjectPath == name) {
2837 return self.subDataItem(
PathEls::Field(Fields::referredObjectPath),
2838 referredObjectPath.toString());
2840 if (Fields::get == name)
2847 return QList<QString>({Fields::referredObjectPath.toString(), Fields::get.toString()});
2863 if (referredObjectPath) {
2871 RefCacheEntry cached = RefCacheEntry::forPath(self, selfPath);
2872 switch (cached.cached) {
2873 case RefCacheEntry::Cached::None:
2875 case RefCacheEntry::Cached::First:
2876 case RefCacheEntry::Cached::All:
2877 if (!cached.canonicalPaths.isEmpty())
2878 cachedPath = cached.canonicalPaths.first();
2886 qCWarning(refLog) <<
"referenceCache outdated, reference at " << selfPath
2887 <<
" leads to invalid path " << cachedPath;
2893 QList<Path> visitedRefsLocal;
2901 (visitedRefs ? visitedRefs : &visitedRefsLocal));
2904 env, selfPath, RefCacheEntry { RefCacheEntry::Cached::First, { cachedPath } });
2913 if (referredObjectPath) {
2916 QList<Path> cachedPaths;
2920 RefCacheEntry cached = RefCacheEntry::forPath(env, selfPath);
2921 switch (cached.cached) {
2922 case RefCacheEntry::Cached::None:
2923 case RefCacheEntry::Cached::First:
2925 case RefCacheEntry::Cached::All:
2926 cachedPaths += cached.canonicalPaths;
2927 if (cachedPaths.isEmpty())
2931 if (!cachedPaths.isEmpty()) {
2932 bool outdated =
false;
2933 for (
const Path &p : cachedPaths) {
2934 DomItem newEl = env.path(p);
2937 qCWarning(refLog) <<
"referenceCache outdated, reference at " << selfPath
2938 <<
" leads to invalid path " << p;
2958 QList<Path> canonicalPaths;
2959 for (
const DomItem &i : res) {
2961 canonicalPaths.append(i.canonicalPath());
2964 <<
"getAll of reference at " << selfPath <<
" visits empty items.";
2968 RefCacheEntry { RefCacheEntry::Cached::All, std::move(canonicalPaths) });
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2992 : m_derivedFrom(derivedFrom),
3000 : m_derivedFrom(derivedFrom),
3014 QMultiMap<Path, ErrorMessage> my_errors;
3016 QMutexLocker l1(o.mutex());
3017 my_errors = o.m_errors;
3021 QMutexLocker l2(mutex());
3022 m_errors = my_errors;
3029 static QAtomicInt nextRev(0);
3036 cont = cont && visitor(
PathEls::Field(Fields::errors), [&self,
this]() {
3037 QMultiMap<Path, ErrorMessage> myErrors = localErrors();
3038 return self.subMapItem(Map(
3039 self.pathFromOwner().withField(Fields::errors),
3040 [myErrors](
const DomItem &map,
const QString &key) {
3041 auto it = myErrors.find(Path::fromString(key));
3042 if (it != myErrors.end())
3043 return map.subDataItem(PathEls::Key(key), it->toCbor(),
3044 ConstantData::Options::FirstMapIsFields);
3048 [myErrors](
const DomItem &) {
3050 auto it = myErrors.keyBegin();
3051 auto end = myErrors.keyEnd();
3053 res.insert(it++->toString());
3056 QLatin1String(
"ErrorMessages")));
3064 if (s.pathFromSource) {
3065 if (!s.pathToSource)
3067 return self
.path(s.pathToSource
);
3074 return m_derivedFrom;
3084 return m_frozenAt > m_createdAt;
3090 m_frozenAt = QDateTime::currentDateTimeUtc();
3091 if (m_frozenAt <= m_createdAt)
3092 m_frozenAt = m_createdAt.addSecs(1);
3105 return m_lastDataUpdateAt;
3115 if (m_lastDataUpdateAt < tNew)
3116 m_lastDataUpdateAt = tNew;
3126 QMutexLocker l(mutex());
3127 quint32 &c = m_errorsCounts[msg];
3130 m_errors.insert(msg.path, msg);
3135 QMutexLocker l(mutex());
3136 auto it = m_errors.begin();
3137 while (it != m_errors.end()) {
3138 if (it->errorGroups == groups)
3139 it = m_errors.erase(it);
3146 const DomItem &self, function_ref<
bool(
const DomItem &,
const ErrorMessage &)> visitor,
3149 QMultiMap<Path, ErrorMessage> myErrors;
3151 QMutexLocker l(mutex());
3152 myErrors = m_errors;
3154 auto it = myErrors.lowerBound(inPath);
3155 auto end = myErrors.end();
3156 while (it != end && it.key().mid(0, inPath
.length()) == inPath) {
3157 if (!visitor(self, *it++))
3165 return self.iterateDirectSubpaths(
3168 if (i.owningItemPtr() != self.owningItemPtr()) {
3170 if (container.id() == self.id())
3179 if (o1.m_kind != o2.m_kind)
3181 return o1.visitEl([&o1, &o2](
auto &&el1) {
3182 auto &&el2 = std::get<std::decay_t<
decltype(el1)>>(o2.m_element);
3183 auto id1 = el1->id();
3184 auto id2 = el2->id();
3187 if (id1 != quintptr(0))
3189 if (o1.m_owner != o2.m_owner)
3191 Path p1 = el1->pathFromOwner();
3192 Path p2 = el2->pathFromOwner();
3211 Q_ASSERT(
false &&
"addPropertyDef on non qml scope");
3220 Q_ASSERT(
false &&
"addBinding on non qml scope");
3229 Q_ASSERT(
false &&
"addMethod on non qml scope");
3237 }
else if (QmlComponent *el = mutableAs<QmlComponent>()) {
3241 Q_ASSERT(
false &&
"addChild on non qml scope");
3249 dumperToQDebug([&c](
const Sink &s) { c.dump(s); }, debug);
3256 return debug.noquote().nospace() <<
"MutableDomItem(" << domTypeToString(cc.internalKind())
3257 <<
", " << cc.canonicalPath().toString() <<
")";
3262 index_type len = index_type(m_pList.size());
3263 for (index_type i = 0; i < len; ++i) {
3264 if (!v(
PathEls::Index(i), [
this, &self, i] {
return this->index(self, i); }))
3273 ow.writeRegion(fLoc, LeftBracketRegion);
3275 index_type len = index_type(m_pList.size());
3276 for (index_type i = 0; i < len; ++i) {
3280 ow.writeRegion(fLoc, CommaTokenRegion).ensureSpace();
3282 ow.ensureNewline(1);
3286 if (!compact && !first)
3288 ow.writeRegion(fLoc, RightBracketRegion);
3301
3302
3303
3304
3305
3324 return fileItem.ownerAs<JsFile>();
3326 return fileItem.ownerAs<QmlFile>();
3328 Q_UNREACHABLE_RETURN({});
3337#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 globalScope() 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()