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.dvValue(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.dvValue(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>)
512 return DomItem(el, el, Path(), el.get());
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 QMap<LookupType, QString> map = []() {
762 QMetaEnum metaEnum = QMetaEnum::fromType<LookupType>();
763 QMap<LookupType, QString> res;
764 for (
int i = 0; i < metaEnum.keyCount(); ++i) {
765 res[LookupType(metaEnum.value(i))] = QString::fromUtf8(metaEnum.key(i));
773 ResolveOptions options,
const Path &fullPath, QList<Path> *visitedRefs)
const
776 Path fPath = fullPath;
780 return visitor(fPath, *
this);
781 QList<QSet<quintptr>> visited(path.length() + 1);
783 QVector<ResolveToDo> toDos(1);
810 toDos[0] = {std::move(root), 1};
812 toDos[0] = {*
this, 0};
814 while (!toDos.isEmpty()) {
817 auto idNow = toDo.item.id();
818 if (idNow == quintptr(0) && toDo.item == *
this)
819 idNow = quintptr(
this);
820 if (idNow != quintptr(0) && visited[0].contains(idNow))
825 bool branchExhausted =
false;
826 while (iPath < path
.length() && it && !branchExhausted) {
827 auto idNow = it.id();
828 if (idNow == quintptr() && toDo.item == *
this)
829 idNow = quintptr(
this);
830 if (idNow != quintptr(0)) {
831 auto vPair = std::make_pair(idNow, iPath);
832 if (visited[vPair.second].contains(vPair.first))
834 visited[vPair.second].insert(vPair.first);
838 auto cNow = path
[iPath++
];
841 it = it.key(cNow.headName());
847 if (visitedRefs ==
nullptr) {
848 visitedRefs = &vRefs;
850 if (visitedRefs->contains(refRef)) {
852 .error([visitedRefs, refRef](
const Sink &sink) {
853 const QString msg = tr(
"Circular reference:") + QLatin1Char(
'\n');
854 sink(QStringView{msg});
855 for (
const Path &vPath : *visitedRefs) {
865 visitedRefs->append(refRef);
877 it = it.field(cNow.headName());
881 it = it.index(cNow.headIndex());
890 .handle(errorHandler);
891 branchExhausted =
true;
894 toFind = path
[iPath++
];
896 QVector<Path::Kind> validFind({Path::Kind::Key, Path::Kind::Field, Path::Kind::Field, Path::Kind::Index});
897 if (!validFind.contains(toFind.headKind())) {
898 myResolveErrors().error(tr(
"After an empty path only key, field or indexes are supported, not %1.").arg(toFind.toString())
)
899 .handle(errorHandler);
900 branchExhausted =
true;
903 if (!branchExhausted)
906 [&toFind, &toDos, iPath](Path,
const DomItem &item,
bool) {
908 DomItem newItem = item[toFind];
910 toDos.append({ std::move(newItem), iPath });
913 VisitOption::VisitSelf | VisitOption::Recurse
914 | VisitOption::VisitAdopted | VisitOption::NoPath);
915 branchExhausted =
true;
920 .arg(cNow.toString()).arg(iPath -1).arg(path.toString())
).handle(errorHandler);
929 if (domKind() != DomKind::Object)
933 bool cont = it.visitPrototypeChain(
934 [&toDos, iPath](
const DomItem &subEl) {
935 toDos.append({ subEl, iPath });
942 branchExhausted =
true;
946 bool cont = it.visitScopeChain(
947 [&toDos, iPath](
const DomItem &subEl) {
948 toDos.append({ subEl, iPath });
951 LookupOption::Normal, errorHandler);
954 branchExhausted =
true;
962 it = it.component().ids();
965 it = it.component()[Fields::exports];
970 LookupOptions opt = LookupOption::Normal;
973 DomItem strict = comp.field(u"~strictLookup~");
976 strict = env.field(u"defaultStrictLookup");
978 if (strict && strict.value().toBool())
979 opt = opt | LookupOption::Strict;
981 opt = opt | LookupOption::Strict;
985 .error(tr(
"Javascript lookups not yet implemented")
)
986 .handle(errorHandler);
990 auto idNow = it.id();
991 if (idNow == quintptr(0) && toDo.item == *
this)
992 idNow = quintptr(
this);
993 if (idNow != quintptr(0)) {
994 auto vPair = std::make_pair(idNow, iPath);
995 if (visited[vPair.second].contains(vPair.first))
997 visited[vPair.second].insert(vPair.first);
1003 .error(tr(
"Premature end of path, expected a field specifying the "
1004 "type, and a key specifying the name to search after a "
1005 "lookup directive in %2")
1006 .arg(path.toString())
)
1007 .handle(errorHandler);
1010 Path cNow = path
[iPath++
];
1013 .error(tr(
"Expected a key path specifying the type to search after "
1014 "a lookup directive, not %1 at component %2 of %3")
1015 .arg(cNow.toString())
1017 .arg(path.toString())
)
1018 .handle(errorHandler);
1021 QString expectedType = cNow.headName();
1022 LookupType lookupType = LookupType::Symbol;
1025 auto m = lookupTypeToStringMap();
1026 auto it = m.begin();
1029 if (it.value().compare(expectedType, Qt::CaseInsensitive) == 0) {
1030 lookupType = it.key();
1037 it = lookupTypeToStringMap().begin();
1039 if (!types.isEmpty())
1040 types += QLatin1String(
"', '");
1041 types += it.value();
1045 .error(tr(
"Type for lookup was expected to be one of '%1', not "
1047 .arg(types, expectedType)
)
1048 .handle(errorHandler);
1052 cNow = path
[iPath++
];
1055 .error(tr(
"Expected a key specifying the path to search after the "
1056 "@lookup directive and type, not %1 at component %2 of "
1058 .arg(cNow.toString())
1060 .arg(path.toString())
)
1061 .handle(errorHandler);
1064 QString target = cNow.headName();
1065 if (target.isEmpty()) {
1067 .warning(tr(
"Path with empty lookup at component %1 of %2 will "
1068 "match nothing in %3.")
1070 .arg(path.toString())
1072 .handle(errorHandler);
1077 [&toDos, iPath](
const DomItem &subEl) {
1078 toDos.append({ subEl, iPath });
1081 lookupType, opt, errorHandler, &(visited[iPath]), visitedRefs);
1082 branchExhausted =
true;
1088 case Path::Kind::Any:
1091 [&toDos, iPath](Path,
const DomItem &item,
bool) {
1092 toDos.append({ item, iPath });
1095 VisitOption::VisitSelf | VisitOption::Recurse | VisitOption::VisitAdopted);
1096 branchExhausted =
true;
1100 branchExhausted =
true;
1105 if (!branchExhausted && iPath == path
.length() && !visitor(fPath, it))
1116 resolve(p, [&res](
const Path &,
const DomItem &it) {
1135 return visitEl([
this](
auto &&el) {
return el->fields(*
this); });
1140 return visitEl([
this, name](
auto &&el) {
return el->field(*
this, name); });
1145 return visitEl([
this](
auto &&el) {
return el->indexes(*
this); });
1150 return visitEl([
this, i](
auto &&el) {
return el->index(*
this, i); });
1156 int nIndexes = indexes();
1157 for (
int i = 0; i < nIndexes; ++i) {
1167 return visitEl([
this](
auto &&el) {
return el->keys(*
this); });
1172 QSet<QString> ks = keys();
1173 QStringList sortedKs(ks.begin(), ks.end());
1174 std::sort(sortedKs.begin(), sortedKs.end());
1180 return visitEl([
this, name](
auto &&el) {
return el->key(*
this, name); });
1186 const QStringList keys = sortedKeys();
1187 for (
const QString &k : keys) {
1198 iterateDirectSubpaths([&res](
const PathEls::PathComponent &, function_ref<DomItem()> item) {
1208 DomItem anns = field(Fields::annotations);
1209 for (
const auto &ann : anns.values()) {
1210 if (ann.annotations().indexes() == 0) {
1215 DomItem annAnn = ann.annotations();
1216 Q_ASSERT_X(annAnn.indexes() == 1 && annAnn.index(0).name() == u"duplicate",
1217 "DomItem::writeOutPre",
"Unexpected annotation of annotation");
1221 ow.itemStart(*
this);
1227 visitEl([
this, &ow](
auto &&el) { el->writeOut(*
this, ow); });
1238 WriteOutChecks extraChecks)
const
1240 auto compare = [
this](
const DomItem &obj1,
const DomItem &obj2, QStringView obj2Name,
1242 const auto diffList = domCompareStrList(obj1, obj2, filter, DomCompareStrList::AllDiffs);
1243 if (!diffList.isEmpty()) {
1244 qCWarning(writeOutLog).noquote().nospace()
1245 << obj2Name <<
" writeOut of " <<
this->canonicalFilePath() <<
" has changes:\n"
1246 << diffList.join(QString());
1251 auto checkStability = [&ow,
this](
const QString &expected,
const DomItem &obj,
1252 QStringView objName) {
1255 ow2.indentNextlines =
true;
1258 if (ow2.writtenStr != expected) {
1259 qCWarning(writeOutLog).noquote().nospace()
1260 << objName <<
" non stable writeOut of " <<
this->canonicalFilePath() <<
":"
1261 << lineDiff(expected, ow2.writtenStr, 2);
1270 std::shared_ptr<DomEnvironment> newEnvPtr = newEnv.ownerAs<DomEnvironment>();
1272 return WriteOutCheckResult::Failed;
1274 auto newFilePtr = std::make_shared<QmlFile>(canonicalFilePath(), ow.writtenStr);
1278 if (newFilePtr->isValid()) {
1280 newEnvPtr->populateFromQmlFile(newFile);
1282 && !compare(reformatted, newFile, u"reparsed",
1284 return WriteOutCheckResult::Failed;
1286 checkStability(ow.writtenStr, newFile, u"reparsed");
1289 const auto iterateErrors = [&newFile](
const Sink &s) {
1290 newFile.iterateErrors(
1299 qCWarning(writeOutLog).noquote().nospace()
1300 <<
"writeOut of " << canonicalFilePath()
1301 <<
" created invalid code:\n----------\n"
1302 << ow.writtenStr <<
"\n----------" << iterateErrors;
1303 return WriteOutCheckResult::Failed;
1306 return WriteOutCheckResult::Success;
1310
1311
1312
1313
1314
1315
1316
1317
1318
1321 ow.indentNextlines =
true;
1322 auto currentFileItem = fileObject();
1325 WriteOutCheckResult result = WriteOutCheckResult::Success;
1327 result = performWriteOutChecks(currentFileItem, ow, extraChecks);
1328 return result == WriteOutCheckResult::Success ?
bool(currentFileItem) :
false;
1332 FileWriter *fw, WriteOutChecks extraChecks)
const
1337 auto status = fw->write(
1339 [
this, path, &options, extraChecks](QTextStream &ts) {
1340 auto lw = createLineWriter([&ts](QStringView s) { ts << s; }, path, options);
1341 OutWriter ow(getFileItemOwner(fileObject()), *lw);
1342 return writeOutForFile(ow, extraChecks);
1346 case FileWriter::Status::DidWrite:
1347 case FileWriter::Status::SkippedEqual:
1349 case FileWriter::Status::ShouldWrite:
1350 case FileWriter::Status::SkippedDueToFailure:
1351 qCWarning(writeOutLog) <<
"failure reformatting " << path;
1354 qCWarning(writeOutLog) <<
"Unknown FileWriter::Status ";
1362 bool isChild =
false;
1375 bool hasAnnotations =
false;
1379 if (
const Id *myPtr = as<
Id>())
1380 hasAnnotations = !myPtr->annotations.isEmpty();
1384 hasAnnotations = !myPtr->annotations.isEmpty();
1388 hasAnnotations = !myPtr->annotations.isEmpty();
1392 hasAnnotations = !myPtr->annotations().isEmpty();
1396 hasAnnotations = !myPtr->annotations().isEmpty();
1401 return hasAnnotations;
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1427 VisitOptions options, DomItem::ChildrenVisitor openingVisitor,
1428 DomItem::ChildrenVisitor closingVisitor,
const FieldFilter &filter)
const
1432 if (options & VisitOption::VisitSelf && !visitor(basePath, *
this,
true))
1434 if (options & VisitOption::VisitSelf && !openingVisitor(basePath, *
this,
true))
1436 auto atEnd = qScopeGuard([closingVisitor, basePath,
this, options]() {
1437 if (options & VisitOption::VisitSelf) {
1438 closingVisitor(basePath, *
this,
true);
1441 return iterateDirectSubpaths(
1442 [
this, basePath, visitor, openingVisitor, closingVisitor, options,
1443 &filter](
const PathEls::PathComponent &c, function_ref<DomItem()> itemF) {
1445 if (!(options & VisitOption::NoPath)) {
1447 pNow = pNow.withComponent(c);
1449 if (!filter(*
this, c, DomItem{}))
1451 DomItem item = itemF();
1452 bool directChild = isCanonicalChild(item);
1453 if (!directChild && !(options & VisitOption::VisitAdopted))
1455 if (!directChild || !(options & VisitOption::Recurse)) {
1456 if (!visitor(pNow, item, directChild))
1461 if (!openingVisitor(pNow, item, directChild))
1463 closingVisitor(pNow, item, directChild);
1465 return item.visitTree(pNow, visitor, options | VisitOption::VisitSelf,
1466 openingVisitor, closingVisitor, filter);
1473 QList<Path> *visitedRefs, VisitPrototypesOptions options,
1477 if (visitedRefs->contains(elId))
1480 visitedRefs->append(elId);
1481 QList<DomItem> protos = prototype.getAll(h, visitedRefs);
1482 if (protos.isEmpty()) {
1483 if (std::shared_ptr<DomEnvironment> envPtr =
1484 derivedFromPrototype.environment().ownerAs<DomEnvironment>())
1487 .warning(derivedFromPrototype.tr(
"could not resolve prototype %1 (%2)")
1489 prototype.field(Fields::referredObjectPath)
1492 .withItem(derivedFromPrototype)
1495 if (protos.size() > 1) {
1496 QStringList protoPaths;
1497 for (
const DomItem &p : protos)
1498 protoPaths.append(p.canonicalPath().toString());
1501 .tr(
"Multiple definitions found, using first only, resolving "
1502 "prototype %1 (%2): %3")
1504 prototype.field(Fields::referredObjectPath)
1507 protoPaths.join(QLatin1String(
", ")))
)
1508 .withItem(derivedFromPrototype)
1513 for (
int i = nProtos; i != 0;) {
1514 DomItem proto = protos.at(--i);
1517 proto = proto.proceedToScope(h, visitedRefs);
1524 .warning(derivedFromPrototype.tr(
"Unexpected prototype type %1 (%2)")
1526 prototype.field(Fields::referredObjectPath)
1529 .withItem(derivedFromPrototype)
1539 QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1541 QSet<quintptr> visitedLocal;
1543 visited = &visitedLocal;
1544 QList<Path> refsLocal;
1546 visitedRefs = &refsLocal;
1548 DomItem current = qmlObject();
1553 QList<DomItem> toDo({ current });
1554 while (!toDo.isEmpty()) {
1555 current = toDo.takeLast();
1556 current = current.proceedToScope(h, visitedRefs);
1557 if (visited->contains(current.id())) {
1563 .warning(tr(
"Detected multiple visit of %1 visiting prototypes of %2")
1570 visited->insert(current.id());
1571 if (shouldVisit && !visitor(current))
1574 current.field(Fields::prototypes)
1575 .visitIndexes([&toDo, ¤t,
this, &h, visitedRefs, options](
const DomItem &el) {
1576 return visitPrototypeIndex(toDo, current, *
this, h, visitedRefs, options, el);
1583 function_ref<
bool(
const DomItem &)> visitor, VisitPrototypesOptions options,
1584 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1589 if (k == DomType::QmlObject)
1590 return visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1591 if (visited && id() != 0) {
1592 if (visited->contains(id()))
1594 visited->insert(id());
1598 DomItem v = proceedToScope(h, visitedRefs);
1600 return v.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1604 DomItem v = field(Fields::value);
1606 return v.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1610 DomItem t = field(Fields::type).proceedToScope(h, visitedRefs);
1612 return t.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1620
1621
1622
1623
1624
1625
1626
1627
1628
1630 function_ref<
bool(
const DomItem &)> visitor, VisitPrototypesOptions options,
1631 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1633 QSet<quintptr> visitedLocal;
1635 visited = &visitedLocal;
1636 DomItem current = qmlObject();
1637 DomItem comp = current.component();
1638 if (comp.field(Fields::isSingleton).value().toBool(
false)
1639 && !current.visitPrototypeChain(visitor, options, h, visited, visitedRefs))
1641 if (
DomItem attachedT = current.component().field(Fields::attachedType).field(Fields::get))
1642 if (!attachedT.visitPrototypeChain(
1644 visited, visitedRefs))
1650
1651
1657 if (!visitor(current))
1665
1666
1668 function_ref<
bool(
const DomItem &)> visitor, LookupOptions options,
const ErrorHandler &h,
1669 QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1671 QSet<quintptr> visitedLocal;
1673 visited = &visitedLocal;
1674 QList<Path> visitedRefsLocal;
1676 visitedRefs = &visitedRefsLocal;
1682 QList<DomItem> toDo { current };
1683 bool visitFirst = !(options & LookupOption::SkipFirstScope);
1684 bool visitCurrent = visitFirst;
1686 QSet<quintptr> alreadyAddedComponentMaps;
1687 while (!toDo.isEmpty()) {
1688 DomItem current = toDo.takeLast();
1689 if (visited->contains(current.id()))
1691 visited->insert(current.id());
1692 if (visitCurrent && !visitor(current))
1694 visitCurrent =
true;
1700 DomItem root = current.rootQmlObject();
1701 if (root && root
!= current) {
1715 if ((options & LookupOption::Strict) == 0) {
1716 if (
DomItem comp = current.field(Fields::nextComponent))
1719 if (first && visitFirst && (options & LookupOption::VisitTopClassType)
1720 && *
this == current) {
1721 if (
DomItem attachedT = current.field(Fields::attachedType).field(Fields::get))
1722 toDo.append(attachedT);
1730 if (alreadyAddedComponentMaps.contains(componentMap.id()))
1732 alreadyAddedComponentMaps.insert(componentMap.id());
1733 const auto keys = componentMap.keys();
1734 for (
const QString &x : keys) {
1735 DomItem componentList = componentMap.key(x);
1736 for (
int i = 0; i < componentList.indexes(); ++i) {
1737 DomItem component = componentList.index(i);
1738 if (component != current && !visited->contains(component.id()))
1739 toDo.append(component);
1747 current.field(Fields::importScope))
1748 toDo.append(iScope);
1758 if (
auto globalC = globalScope().field(Fields::rootComponent))
1759 toDo.append(globalC);
1764 if (
DomItem next = current.field(Fields::objects).index(0))
1773 .error(tr(
"Unexpected non scope object %1 (%2) reached in visitScopeChain")
1774 .arg(domTypeToString(current.internalKind()),
1775 current.canonicalPath().toString()))
1785 const QString &symbolName, function_ref<
bool(
const DomItem &)> visitor, LookupOptions opts,
1786 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1788 return visitScopeChain(
1789 [symbolName, visitor](
const DomItem &obj) {
1790 return obj.visitLocalSymbolsNamed(symbolName,
1791 [visitor](
const DomItem &el) {
return visitor(el); });
1793 opts, h, visited, visitedRefs);
1805 QRegularExpression reTarget = QRegularExpression(QRegularExpression::anchoredPattern(
1806 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>\*?))"));
1808 QRegularExpressionMatch m = reTarget.matchView(target);
1809 if (!m.hasMatch()) {
1811 .error(tr(
"Unexpected complex CppType %1").arg(target)
)
1814 res.baseType = m.captured(u"baseType");
1815 res
.isPointer = !m.captured(u"ptr").isEmpty();
1816 if (!m.captured(u"list").isEmpty()) {
1818 res.baseType = m.captured(u"list");
1819 res
.isPointer = !m.captured(u"listPtr").isEmpty();
1821 if (!m.captured(u"mapValue").isEmpty()) {
1823 if (m.captured(u"mapKey") != u"QString") {
1825 .error(tr(
"Unexpected complex CppType %1 (map with non QString key)")
1829 res.baseType = m.captured(u"mapValue");
1830 res
.isPointer = !m.captured(u"mapPtr").isEmpty();
1842 function_ref<
bool(
const DomItem &)> visitor)
1844 bool correctType =
false;
1846 switch (lookupType) {
1847 case LookupType::Binding:
1850 case LookupType::Method:
1853 case LookupType::Property:
1856 case LookupType::PropertyDef:
1859 case LookupType::Type:
1872 const DomItem &newIt,
const QStringList &subpath,
1873 function_ref<
bool(
const DomItem &)> visitor, LookupType lookupType,
1874 const ErrorHandler &errorHandler, QList<Path> *visitedRefs)
1876 QVector<ResolveToDo> lookupToDos(
1877 { ResolveToDo{ newIt, 1 } });
1879 QList<QSet<quintptr>> lookupVisited(subpath.size() + 1);
1880 while (!lookupToDos.isEmpty()) {
1882 auto vNow = std::make_pair(tNow.item.id(), tNow.pathIndex);
1885 Q_ASSERT(iSubPath < subpath.size());
1886 QString subPathNow = subpath[iSubPath++];
1887 DomItem scope = subNow.proceedToScope();
1888 if (iSubPath < subpath.size()) {
1889 if (vNow.first != 0) {
1890 if (lookupVisited[vNow.second].contains(vNow.first))
1893 lookupVisited[vNow.second].insert(vNow.first);
1895 if (scope.internalKind() == DomType::QmlObject)
1896 scope.visitDirectAccessibleScopes(
1897 [&lookupToDos, &subPathNow, iSubPath](
const DomItem &el) {
1898 return el.visitLocalSymbolsNamed(
1899 subPathNow, [&lookupToDos, iSubPath](
const DomItem &subEl) {
1900 lookupToDos.append({ subEl, iSubPath });
1904 VisitPrototypesOption::Normal, errorHandler, &(lookupVisited[vNow.second]),
1907 bool cont = scope.visitDirectAccessibleScopes(
1908 [&visitor, &subPathNow, lookupType](
const DomItem &el) ->
bool {
1909 if (lookupType == LookupType::Symbol)
1910 return el.visitLocalSymbolsNamed(subPathNow, visitor);
1912 return el.visitLocalSymbolsNamed(
1913 subPathNow, [lookupType, &visitor](
const DomItem &el) ->
bool {
1914 return visitForLookupType(el, lookupType, visitor);
1917 VisitPrototypesOption::Normal, errorHandler, &(lookupVisited[vNow.second]),
1927 const QString &target, function_ref<
bool(
const DomItem &)> visitor, LookupType lookupType,
1928 LookupOptions opts,
const ErrorHandler &errorHandler, QSet<quintptr> *visited,
1929 QList<Path> *visitedRefs)
const
1931 if (target.isEmpty())
1933 switch (lookupType) {
1934 case LookupType::Binding:
1935 case LookupType::Method:
1936 case LookupType::Property:
1937 case LookupType::PropertyDef:
1938 case LookupType::Symbol:
1939 case LookupType::Type: {
1940 QStringList subpath = target.split(QChar::fromLatin1(
'.'));
1941 if (subpath.size() == 1) {
1942 return visitLookup1(subpath.first(), visitor, opts, errorHandler, visited, visitedRefs);
1944 return visitLookup1(
1946 [&subpath, visitor, lookupType, &errorHandler,
1947 visitedRefs](
const DomItem &newIt) ->
bool {
1948 return visitQualifiedNameLookup(newIt, subpath, visitor, lookupType,
1949 errorHandler, visitedRefs);
1951 opts, errorHandler, visited, visitedRefs);
1955 case LookupType::CppType: {
1956 QString baseTarget = CppTypeInfo::fromString(target, errorHandler).baseType;
1960 localQmltypes = localQmltypes
.owner();
1962 if (localQmltypes) {
1963 if (
DomItem localTypes = localQmltypes.field(Fields::components).key(baseTarget)) {
1964 bool cont = localTypes.visitIndexes([&visitor](
const DomItem &els) {
1965 return els.visitIndexes([&visitor](
const DomItem &el) {
1966 if (DomItem obj = el.field(Fields::objects).index(0))
1967 return visitor(obj);
1976 return qmltypes.visitKeys([baseTarget, &visitor](
const QString &,
const DomItem &els) {
1978 els.field(Fields::currentItem).field(Fields::components).key(baseTarget);
1979 return comps.visitIndexes([&visitor](
const DomItem &el) {
1980 if (DomItem obj = el.field(Fields::objects).index(0))
1981 return visitor(obj);
1993
1994
1995
1996
1997
1998
1999
2008 current = current.get(h, visitedRefs);
2012 current = current.field(Fields::type);
2015 current = current.field(Fields::referredObject);
2031 [&res](
const DomItem &el) {
2035 type, opts, errorHandler);
2045 [&res](
const DomItem &el) {
2049 type, opts, errorHandler);
2055 return visitEl([](
auto &&b) {
return b->id(); });
2060 return visitEl([](
auto &&e) {
return e->pathFromOwner(); });
2065 return visitEl([
this](
auto &&e) {
return e->canonicalFilePath(*
this); });
2074 DomItem newItem = std::visit([
this, &o](
auto &&el) {
2075 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>) {
2078 auto copyPtr = el->makeCopy(o);
2079 return DomItem(m_top, copyPtr, m_ownerPath, copyPtr.get());
2085 std::shared_ptr<DomEnvironment> newEnvPtr;
2086 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
2087 newEnvPtr =
std::make_shared<DomEnvironment>(envPtr, envPtr->loadPaths(), envPtr->options(),
2088 envPtr->domCreationOption());
2089 DomBase *eBase = envPtr.get();
2090 if (std::holds_alternative<
const DomEnvironment *>(m_element) && eBase
2091 && std::get<
const DomEnvironment *>(m_element) == eBase)
2093 }
else if (std::shared_ptr<DomUniverse> univPtr = top().ownerAs<DomUniverse>()) {
2094 newEnvPtr =
std::make_shared<DomEnvironment>(
2103 [
this, newEnvPtr, &o](
auto &&el) {
2104 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>) {
2107 auto copyPtr = el->makeCopy(o);
2108 return DomItem(newEnvPtr, copyPtr, m_ownerPath, copyPtr.get());
2129 case DomType::ModuleIndex:
2130 case DomType::MockOwner:
2131 case DomType::ScriptExpression:
2132 case DomType::AstComments:
2133 case DomType::LoadInfo:
2134 case DomType::FileLocationsNode:
2135 case DomType::DomEnvironment:
2136 case DomType::DomUniverse:
2137 qCWarning(domLog) <<
"DomItem::makeCopy " << internalKindStr()
2138 <<
" does not support binding to environment";
2142 qCWarning(domLog) <<
"DomItem::makeCopy(" << internalKindStr()
2143 <<
") is not an known OwningItem";
2155 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
2156 return envPtr->commitToBase(env, validEnvPtr);
2171 case DomType::QmlObject:
2172 f = field(Fields::propertyDefs);
2174 if (!v.visitIndexes(visitor))
2176 f = field(Fields::bindings);
2178 if (!v.visitIndexes(visitor))
2180 f = field(Fields::methods);
2182 if (!v.visitIndexes(visitor))
2188 case DomType::QmlComponent:
2189 f = field(Fields::ids);
2191 if (!v.visitIndexes(visitor))
2194 case DomType::JsResource:
2195 case DomType::GlobalComponent:
2196 case DomType::QmltypesComponent:
2197 f = field(Fields::enumerations);
2199 if (!v.visitIndexes(visitor))
2203 DomItem params = field(Fields::parameters);
2204 if (!params.visitIndexes([name, visitor](
const DomItem &p) {
2206 if (pPtr->name == name && !visitor(p))
2214 f = field(Fields::components);
2216 if (!v.visitIndexes(visitor))
2221 f = field(Fields::imported);
2223 if (!v.visitIndexes(visitor))
2225 f = field(Fields::qualifiedImports);
2227 if (v && !visitor(v))
2240 if (internalKind() == DomType::Map)
2242 return field(cName);
2247 if (internalKind() == DomType::Map)
2248 return key(cName.toString());
2249 return field(cName);
2259 return base()->value();
2264 sink(u"DomItem{ topPtr:");
2265 sink(QString::number((quintptr)topPtr().get(), 16));
2266 sink(u", ownerPtr:");
2267 sink(QString::number((quintptr)owningItemPtr().get(), 16));
2268 sink(u", ownerPath:");
2269 m_ownerPath.dump(sink);
2271 sink(QString::number((quintptr)base(),16));
2276 const Sink &s,
int indent,
2277 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2279 visitEl([
this, s, indent, filter](
auto &&e) { e->dump(*
this, s, indent, filter); });
2284 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter,
2285 int nBackups,
int indent,
FileWriter *fw)
const
2292 [
this, indent, filter](QTextStream &ts) {
2293 this->dump([&ts](QStringView s) { ts << s; }, indent, filter);
2297 case FileWriter::Status::ShouldWrite:
2298 case FileWriter::Status::SkippedDueToFailure:
2299 qWarning() <<
"Failure dumping " <<
canonicalPath() <<
" to " << path;
2301 case FileWriter::Status::DidWrite:
2302 case FileWriter::Status::SkippedEqual:
2310 return dumperToString([
this](
const Sink &s){ dump(s); });
2315 return std::visit([](
auto &&ow) {
2316 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2319 return ow->derivedFrom();
2325 return std::visit([](
auto &&ow) {
2326 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2329 return ow->revision();
2335 return std::visit([](
auto &&ow) {
2336 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2337 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2339 return ow->createdAt();
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->frozenAt();
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->lastDataUpdateAt();
2365 std::visit([
this, &msg](
auto &&ow) {
2366 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2367 defaultErrorHandler(msg.withItem(*
this));
2369 ow->addError(owner(), std::move(msg.withItem(*
this)));
2381 std::visit([&groups](
auto &&ow) {
2382 if constexpr (!std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2383 ow->clearErrors(groups);
2387 iterateSubOwners([groups](
const DomItem &i){
2388 i.clearErrors(groups,
true);
2395 function_ref<
bool(
const DomItem &,
const ErrorMessage &)> visitor,
bool iterate,
2398 if (!std::visit([
this, visitor, inPath](
auto &&el) {
2399 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2402 return el->iterateErrors(owner(), visitor, inPath);
2407 if (iterate && !iterateSubOwners([inPath, visitor](
const DomItem &i) {
2408 return i.iterateErrors(visitor,
true, inPath);
2418 return std::visit([
this, visitor](
auto &&o) {
2419 if constexpr (std::is_same_v<std::decay_t<
decltype(o)>, std::monostate>)
2422 return o->iterateSubOwners(owner(), visitor);
2429 [
this, v](
auto &&el) {
return el->iterateDirectSubpaths(*
this, v); });
2435 List::fromQList<Path>(pathFromOwner().withComponent(c), paths,
2436 [](
const DomItem &list,
const PathEls::PathComponent &p,
const Path &el) {
2437 return list.subReferenceItem(p, el);
2444 return DomItem(m_top, m_owner, m_ownerPath, Reference(referencedObject, Path(c)));
2446 return DomItem(m_top, m_owner, m_ownerPath,
2447 Reference(referencedObject, pathFromOwner().withComponent(c)));
2453 return std::visit([](
auto &&el) -> shared_ptr<DomTop> {
2454 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2463 return std::visit([](
auto &&el) -> shared_ptr<OwningItem> {
2464 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2472
2473
2474
2477 return visitEl([](
auto &&el) ->
const DomBase * {
return el->domBase(); });
2486 DomItem(universePtr, universePtr,
Path(), universePtr.get())
2491
2492
2493
2494
2495
2496
2497
2506 FileToLoad::fromMemory(env, QString(), code),
2507 [&tFile](Path,
const DomItem &,
const DomItem &newIt) { tFile = newIt; },
2508 std::make_optional(fileType));
2509 return tFile.fileObject();
2536 const DomItem &,
const Sink &s,
int,
2543 const Keys &keys,
const QString &targetType)
2554 QSet<QString> ksSet = keys(self);
2555 QStringList ksList = QStringList(ksSet.begin(), ksSet.end());
2556 std::sort(ksList.begin(), ksList.end());
2557 for (
const QString &k : std::as_const(ksList)) {
2558 if (!visitor(PathEls::Key(k), [&self,
this, k]() {
return key(self, k); }))
2566 return m_keys(self);
2571 return m_lookup(self, name);
2575 const DomItem &self,
const Sink &sink,
int indent,
2576 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2579 DomKind dK = self.domKind();
2581 case DomKind::Object:
2582 sink(u"{ \"~type~\":");
2583 sinkEscaped(sink, typeName());
2586 case DomKind::Value:
2588 sink(QString::fromUtf8(value().toJsonValue().toJson()));
2591 case DomKind::Empty:
2600 case DomKind::ScriptElement:
2604 auto closeParens = qScopeGuard(
2607 case DomKind::Object:
2608 sinkNewline(sink, indent);
2611 case DomKind::Value:
2613 case DomKind::Empty:
2616 sinkNewline(sink, indent);
2620 sinkNewline(sink, indent);
2623 case DomKind::ScriptElement:
2629 self.iterateDirectSubpaths(
2631 function_ref<DomItem()> itemF) {
2633 if (!filter(self, c, i))
2641 sinkNewline(sink, indent + 2);
2642 if (dK != DomKind::Object)
2643 sink(u"UNEXPECTED ENTRY ERROR:");
2644 sinkEscaped(sink, c.name());
2648 sinkNewline(sink, indent + 2);
2649 if (dK != DomKind::Map)
2650 sink(u"UNEXPECTED ENTRY ERROR:");
2651 sinkEscaped(sink, c.name());
2655 sinkNewline(sink, indent + 2);
2656 if (dK != DomKind::List)
2657 sink(u"UNEXPECTED ENTRY ERROR:");
2658 else if (idx++ != c.index())
2659 sink(u"OUT OF ORDER ARRAY:");
2662 sinkNewline(sink, indent + 2);
2663 sink(u"UNEXPECTED PATH KIND ERROR (ignored)");
2667 i.dump(sink, indent + 2, filter);
2669 sink(uR"({ "~type~": "Reference", "immediate": true, "referredObjectPath":")");
2681 const QString &elType):
2692 const DomItem &self,
const Sink &sink,
int indent,
2693 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2697 iterateDirectSubpaths(
2699 [&self, indent, &first, sink, filter](
const PathEls::PathComponent &c,
2700 function_ref<DomItem()> itemF) {
2701 DomItem item = itemF();
2702 if (!filter(self, c, item))
2708 sinkNewline(sink, indent + 2);
2709 item.dump(sink, indent + 2, filter);
2718 return m_iterator(self, [visitor](index_type i, function_ref<DomItem()> itemF) {
2719 return visitor(PathEls::Index(i), itemF);
2722 index_type len = indexes(self);
2723 for (index_type i = 0; i < len; ++i) {
2724 if (!visitor(
PathEls::Index(i), [
this, &self, i]() {
return index(self, i); }))
2732 return m_length(self);
2737 return m_lookup(self, index);
2743 ow.writeRegion(fLoc, LeftBracketRegion);
2745 iterateDirectSubpaths(self,
2746 [&ow, &first, &fLoc, compact](
const PathEls::PathComponent &,
2747 function_ref<DomItem()> elF) {
2751 ow.writeRegion(fLoc, CommaTokenRegion).ensureSpace();
2753 ow.ensureNewline(1);
2758 if (!compact && !first)
2760 ow.writeRegion(fLoc, RightBracketRegion);
2767 Q_ASSERT(m_pathFromOwner &&
"uninitialized DomElement");
2768 return self.owner().canonicalPath().withPath(m_pathFromOwner);
2773 Q_ASSERT(m_pathFromOwner &&
"uninitialized DomElement");
2780 m_pathFromOwner = newPath;
2785 for (
const Path &p : referredObjectPath) {
2786 switch (p.headKind()) {
2787 case Path::Kind::Current:
2788 switch (p.headCurrent()) {
2789 case PathCurrent::Lookup:
2790 case PathCurrent::LookupDynamic:
2791 case PathCurrent::LookupStrict:
2792 case PathCurrent::ObjChain:
2793 case PathCurrent::ScopeChain:
2799 case Path::Kind::Empty:
2800 case Path::Kind::Any:
2801 case Path::Kind::Filter:
2823 cont = cont && self.dvValueLazyField(visitor, Fields::referredObjectPath, [
this]() {
2824 return referredObjectPath.toString();
2827 && self.dvItemField(visitor, Fields::get, [
this, &self]() {
return this->get(self); });
2833 if (Fields::referredObjectPath == name)
2834 return self.subDataItemField(Fields::referredObjectPath, referredObjectPath.toString());
2835 if (Fields::get == name)
2842 return QList<QString>({Fields::referredObjectPath.toString(), Fields::get.toString()});
2858 if (referredObjectPath) {
2866 RefCacheEntry cached = RefCacheEntry::forPath(self, selfPath);
2867 switch (cached.cached) {
2868 case RefCacheEntry::Cached::None:
2870 case RefCacheEntry::Cached::First:
2871 case RefCacheEntry::Cached::All:
2872 if (!cached.canonicalPaths.isEmpty())
2873 cachedPath = cached.canonicalPaths.first();
2881 qCWarning(refLog) <<
"referenceCache outdated, reference at " << selfPath
2882 <<
" leads to invalid path " << cachedPath;
2888 QList<Path> visitedRefsLocal;
2891 [&res](Path,
const DomItem &el) {
2895 h, ResolveOption::None, referredObjectPath,
2896 (visitedRefs ? visitedRefs : &visitedRefsLocal));
2898 RefCacheEntry::addForPath(
2899 env, selfPath, RefCacheEntry { RefCacheEntry::Cached::First, { cachedPath } });
2908 if (referredObjectPath) {
2911 QList<Path> cachedPaths;
2915 RefCacheEntry cached = RefCacheEntry::forPath(env, selfPath);
2916 switch (cached.cached) {
2917 case RefCacheEntry::Cached::None:
2918 case RefCacheEntry::Cached::First:
2920 case RefCacheEntry::Cached::All:
2921 cachedPaths += cached.canonicalPaths;
2922 if (cachedPaths.isEmpty())
2926 if (!cachedPaths.isEmpty()) {
2927 bool outdated =
false;
2928 for (
const Path &p : cachedPaths) {
2929 DomItem newEl = env.path(p);
2932 qCWarning(refLog) <<
"referenceCache outdated, reference at " << selfPath
2933 <<
" leads to invalid path " << p;
2947 [&res](Path,
const DomItem &el) {
2951 h, ResolveOption::None, referredObjectPath, visitedRefs);
2953 QList<Path> canonicalPaths;
2954 for (
const DomItem &i : res) {
2956 canonicalPaths.append(i.canonicalPath());
2959 <<
"getAll of reference at " << selfPath <<
" visits empty items.";
2961 RefCacheEntry::addForPath(
2963 RefCacheEntry { RefCacheEntry::Cached::All, std::move(canonicalPaths) });
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2987 : m_derivedFrom(derivedFrom),
2995 : m_derivedFrom(derivedFrom),
3009 QMultiMap<Path, ErrorMessage> my_errors;
3011 QMutexLocker l1(o.mutex());
3012 my_errors = o.m_errors;
3016 QMutexLocker l2(mutex());
3017 m_errors = my_errors;
3024 static QAtomicInt nextRev(0);
3031 cont = cont && self.dvItemField(visitor, Fields::errors, [&self,
this]() {
3032 QMultiMap<Path, ErrorMessage> myErrors = localErrors();
3033 return self.subMapItem(Map(
3034 self.pathFromOwner().withField(Fields::errors),
3035 [myErrors](
const DomItem &map,
const QString &key) {
3036 auto it = myErrors.find(Path::fromString(key));
3037 if (it != myErrors.end())
3038 return map.subDataItem(PathEls::Key(key), it->toCbor(),
3039 ConstantData::Options::FirstMapIsFields);
3043 [myErrors](
const DomItem &) {
3045 auto it = myErrors.keyBegin();
3046 auto end = myErrors.keyEnd();
3048 res.insert(it++->toString());
3051 QLatin1String(
"ErrorMessages")));
3059 if (s.pathFromSource) {
3060 if (!s.pathToSource)
3062 return self
.path(s.pathToSource
);
3069 return m_derivedFrom;
3079 return m_frozenAt > m_createdAt;
3085 m_frozenAt = QDateTime::currentDateTimeUtc();
3086 if (m_frozenAt <= m_createdAt)
3087 m_frozenAt = m_createdAt.addSecs(1);
3100 return m_lastDataUpdateAt;
3110 if (m_lastDataUpdateAt < tNew)
3111 m_lastDataUpdateAt = tNew;
3121 QMutexLocker l(mutex());
3122 quint32 &c = m_errorsCounts[msg];
3125 m_errors.insert(msg.path, msg);
3130 QMutexLocker l(mutex());
3131 auto it = m_errors.begin();
3132 while (it != m_errors.end()) {
3133 if (it->errorGroups == groups)
3134 it = m_errors.erase(it);
3141 const DomItem &self, function_ref<
bool(
const DomItem &,
const ErrorMessage &)> visitor,
3144 QMultiMap<Path, ErrorMessage> myErrors;
3146 QMutexLocker l(mutex());
3147 myErrors = m_errors;
3149 auto it = myErrors.lowerBound(inPath);
3150 auto end = myErrors.end();
3151 while (it != end && it.key().mid(0, inPath
.length()) == inPath) {
3152 if (!visitor(self, *it++))
3160 return self.iterateDirectSubpaths(
3163 if (i.owningItemPtr() != self.owningItemPtr()) {
3165 if (container.id() == self.id())
3174 if (o1.m_kind != o2.m_kind)
3176 return o1.visitEl([&o1, &o2](
auto &&el1) {
3177 auto &&el2 = std::get<std::decay_t<
decltype(el1)>>(o2.m_element);
3178 auto id1 = el1->id();
3179 auto id2 = el2->id();
3182 if (id1 != quintptr(0))
3184 if (o1.m_owner != o2.m_owner)
3186 Path p1 = el1->pathFromOwner();
3187 Path p2 = el2->pathFromOwner();
3206 Q_ASSERT(
false &&
"addPropertyDef on non qml scope");
3215 Q_ASSERT(
false &&
"addBinding on non qml scope");
3224 Q_ASSERT(
false &&
"addMethod on non qml scope");
3232 }
else if (QmlComponent *el = mutableAs<QmlComponent>()) {
3236 Q_ASSERT(
false &&
"addChild on non qml scope");
3244 dumperToQDebug([&c](
const Sink &s) { c.dump(s); }, debug);
3251 return debug.noquote().nospace() <<
"MutableDomItem(" << domTypeToString(cc.internalKind())
3252 <<
", " << cc.canonicalPath().toString() <<
")";
3257 index_type len = index_type(m_pList.size());
3258 for (index_type i = 0; i < len; ++i) {
3259 if (!v(
PathEls::Index(i), [
this, &self, i] {
return this->index(self, i); }))
3268 ow.writeRegion(fLoc, LeftBracketRegion);
3270 index_type len = index_type(m_pList.size());
3271 for (index_type i = 0; i < len; ++i) {
3275 ow.writeRegion(fLoc, CommaTokenRegion).ensureSpace();
3277 ow.ensureNewline(1);
3281 if (!compact && !first)
3283 ow.writeRegion(fLoc, RightBracketRegion);
3296
3297
3298
3299
3300
3309 return std::shared_ptr<ScriptElement>(
3310 e,
static_cast<ScriptElement *>(e.get()));
3319 return fileItem.ownerAs<JsFile>();
3321 return fileItem.ownerAs<QmlFile>();
3323 Q_UNREACHABLE_RETURN({});
3332#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 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)
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
List(const Path &pathFromOwner, const LookupFunction &lookup, const Length &length, const IteratorFunction &iterator, const QString &elType)
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override
std::function< bool(const DomItem &, function_ref< bool(index_type, function_ref< DomItem()>)>)> IteratorFunction
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
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)
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 &)
static QMap< LookupType, QString > lookupTypeToStringMap()
QMLDOM_EXPORT bool domTypeIsContainer(DomType k)
constexpr bool domTypeIsOwningItem(DomType)
static bool visitForLookupType(const DomItem &el, LookupType lookupType, function_ref< bool(const DomItem &)> visitor)
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)
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)
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)
Combined button and popup list for selecting options.
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
#define NewErrorGroup(name)
A common base class for all the script elements.
void setSemanticScope(const QQmlJSScope::ConstPtr &scope)
QQmlJSScope::ConstPtr semanticScope()