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();
377 const QString canonicalPath = QFileInfo(path).canonicalFilePath();
403 Path res = visitEl([
this](
auto &&el) {
return el->canonicalPath(*
this); });
405 qCWarning(domLog) <<
"non anchored canonical path:" << res.toString();
414 return visitEl([
this](
auto &&el) {
return el->containingObject(*
this); });
418
419
420
421
422
425 if (
DomItem res = filterUp([](DomType k,
const DomItem &) {
return k == DomType::QmlObject; },
428 if (options == GoTo::MostLikely) {
429 if (
DomItem comp = component(options))
430 return comp.field(Fields::objects).index(0);
443 if (k == DomType::ExternalItemInfo || (options == GoTo::MostLikely && k == DomType::ExternalItemPair))
444 return field(Fields::currentItem);
460 return qmlObject(options, FilterUpOptions::ReturnInner);
469 if (s.pathFromSource.length() > 1)
479 if (shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
480 return env.copy(envPtr->ensureGlobalScopeWithName(env, envPtr->globalScopeName())->current,
487
488
489
494 return std::visit([
this](
auto &&el) {
495 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
498 return DomItem(
this->m_top, el,
this->m_ownerPath, el.get());
506 return std::visit([](
auto &&el) {
507 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
510 return DomItem(el, el, Path(), el.get());
528 return res.field(Fields::universe);
533
534
535
536
537
540 if (
DomItem res = filterUp([](DomType k,
const DomItem &) {
return k == DomType::ScriptExpression; },
541 FilterUpOptions::ReturnOuter))
547
548
549
550
551
554 if (
DomItem res = filterUp([](DomType k,
const DomItem &) {
return k == DomType::QmlFile; },
555 FilterUpOptions::ReturnOuter))
561
562
563
564
567 Q_UNUSED(canonicalPath);
569 top().field(Fields::qmlFileWithPath).key(canonicalPath).field(Fields::currentItem);
574
575
576
589
590
591
598
599
600
601
623 current = current
.path(currentPath
);
635 DomItem res = filterUp([](DomType,
const DomItem &el) {
return el.isScope(); }, options);
641 QQmlJSScope::ConstPtr scope;
642 visitUp([&scope](
const DomItem &item) {
643 scope = item.semanticScope();
651 QQmlJSScope::ConstPtr scope = std::visit(
652 [](
auto &&e) -> QQmlJSScope::ConstPtr {
653 using T = std::remove_cv_t<std::remove_reference_t<
decltype(e)>>;
654 if constexpr (std::is_same_v<T,
const QmlObject *>) {
655 return e->semanticScope();
656 }
else if constexpr (std::is_same_v<T,
const QmlComponent *>) {
657 return e->semanticScope();
658 }
else if constexpr (std::is_same_v<T,
const QmltypesComponent *>) {
659 return e->semanticScope();
660 }
else if constexpr (std::is_same_v<T, SimpleObjectWrap>) {
661 if (
const MethodInfo *mi = e->
template as<MethodInfo>()) {
662 return mi->semanticScope();
664 if (
const auto *propertyDefinition = e->
template as<PropertyDefinition>()) {
665 return propertyDefinition->semanticScope();
667 }
else if constexpr (std::is_same_v<T, ScriptElementDomWrapper>) {
668 return e.element().base()->semanticScope();
679 return refPtr->get(*
this, h, visitedRefs);
686 return refPtr->getAll(*
this, h, visitedRefs);
693 visitPrototypeChain([&pInfo, name](
const DomItem &obj) {
694 return obj.visitLocalSymbolsNamed(name, [&pInfo, name](
const DomItem &el) {
695 switch (el.internalKind()) {
696 case DomType::Binding:
697 pInfo.bindings.append(el);
699 case DomType::PropertyDefinition:
700 pInfo.propertyDefs.append(el);
714 visitPrototypeChain([&res](
const DomItem &obj) {
715 res += obj.propertyDefs().keys();
716 res += obj.bindings().keys();
725 [](DomType kind,
const DomItem &) {
726 return kind == DomType::QmlComponent || kind == DomType::QmltypesComponent
727 || kind == DomType::GlobalComponent;
729 FilterUpOptions::ReturnInner))
731 if (options == GoTo::MostLikely) {
739 case DomType::ExternalItemPair:
740 case DomType::ExternalItemInfo:
741 item = fileObject(options);
744 return item.field(Fields::components).key(QString()).index(0);
759 static QMap<LookupType, QString> map = []() {
760 QMetaEnum metaEnum = QMetaEnum::fromType<LookupType>();
761 QMap<LookupType, QString> res;
762 for (
int i = 0; i < metaEnum.keyCount(); ++i) {
763 res[LookupType(metaEnum.value(i))] = QString::fromUtf8(metaEnum.key(i));
771 ResolveOptions options,
const Path &fullPath, QList<Path> *visitedRefs)
const
774 Path fPath = fullPath;
778 return visitor(fPath, *
this);
779 QList<QSet<quintptr>> visited(path.length() + 1);
781 QVector<ResolveToDo> toDos(1);
808 toDos[0] = {std::move(root), 1};
810 toDos[0] = {*
this, 0};
812 while (!toDos.isEmpty()) {
815 auto idNow = toDo.item.id();
816 if (idNow == quintptr(0) && toDo.item == *
this)
817 idNow = quintptr(
this);
818 if (idNow != quintptr(0) && visited[0].contains(idNow))
823 bool branchExhausted =
false;
824 while (iPath < path
.length() && it && !branchExhausted) {
825 auto idNow = it.id();
826 if (idNow == quintptr() && toDo.item == *
this)
827 idNow = quintptr(
this);
828 if (idNow != quintptr(0)) {
829 auto vPair = std::make_pair(idNow, iPath);
830 if (visited[vPair.second].contains(vPair.first))
832 visited[vPair.second].insert(vPair.first);
836 auto cNow = path
[iPath++
];
839 it = it.key(cNow.headName());
845 if (visitedRefs ==
nullptr) {
846 visitedRefs = &vRefs;
848 if (visitedRefs->contains(refRef)) {
850 .error([visitedRefs, refRef](
const Sink &sink) {
851 const QString msg = tr(
"Circular reference:") + QLatin1Char(
'\n');
852 sink(QStringView{msg});
853 for (
const Path &vPath : *visitedRefs) {
863 visitedRefs->append(refRef);
875 it = it.field(cNow.headName());
879 it = it.index(cNow.headIndex());
888 .handle(errorHandler);
889 branchExhausted =
true;
892 toFind = path
[iPath++
];
894 QVector<Path::Kind> validFind({Path::Kind::Key, Path::Kind::Field, Path::Kind::Field, Path::Kind::Index});
895 if (!validFind.contains(toFind.headKind())) {
896 myResolveErrors().error(tr(
"After an empty path only key, field or indexes are supported, not %1.").arg(toFind.toString())
)
897 .handle(errorHandler);
898 branchExhausted =
true;
901 if (!branchExhausted)
904 [&toFind, &toDos, iPath](Path,
const DomItem &item,
bool) {
906 DomItem newItem = item[toFind];
908 toDos.append({ std::move(newItem), iPath });
911 VisitOption::VisitSelf | VisitOption::Recurse
912 | VisitOption::VisitAdopted | VisitOption::NoPath);
913 branchExhausted =
true;
918 .arg(cNow.toString()).arg(iPath -1).arg(path.toString())
).handle(errorHandler);
927 if (domKind() != DomKind::Object)
931 bool cont = it.visitPrototypeChain(
932 [&toDos, iPath](
const DomItem &subEl) {
933 toDos.append({ subEl, iPath });
940 branchExhausted =
true;
944 bool cont = it.visitScopeChain(
945 [&toDos, iPath](
const DomItem &subEl) {
946 toDos.append({ subEl, iPath });
949 LookupOption::Normal, errorHandler);
952 branchExhausted =
true;
960 it = it.component().ids();
963 it = it.component()[Fields::exports];
968 LookupOptions opt = LookupOption::Normal;
971 DomItem strict = comp.field(u"~strictLookup~");
974 strict = env.field(u"defaultStrictLookup");
976 if (strict && strict.value().toBool())
977 opt = opt | LookupOption::Strict;
979 opt = opt | LookupOption::Strict;
983 .error(tr(
"Javascript lookups not yet implemented")
)
984 .handle(errorHandler);
988 auto idNow = it.id();
989 if (idNow == quintptr(0) && toDo.item == *
this)
990 idNow = quintptr(
this);
991 if (idNow != quintptr(0)) {
992 auto vPair = std::make_pair(idNow, iPath);
993 if (visited[vPair.second].contains(vPair.first))
995 visited[vPair.second].insert(vPair.first);
1001 .error(tr(
"Premature end of path, expected a field specifying the "
1002 "type, and a key specifying the name to search after a "
1003 "lookup directive in %2")
1004 .arg(path.toString())
)
1005 .handle(errorHandler);
1008 Path cNow = path
[iPath++
];
1011 .error(tr(
"Expected a key path specifying the type to search after "
1012 "a lookup directive, not %1 at component %2 of %3")
1013 .arg(cNow.toString())
1015 .arg(path.toString())
)
1016 .handle(errorHandler);
1019 QString expectedType = cNow.headName();
1020 LookupType lookupType = LookupType::Symbol;
1023 auto m = lookupTypeToStringMap();
1024 auto it = m.begin();
1027 if (it.value().compare(expectedType, Qt::CaseInsensitive) == 0) {
1028 lookupType = it.key();
1035 it = lookupTypeToStringMap().begin();
1037 if (!types.isEmpty())
1038 types += QLatin1String(
"', '");
1039 types += it.value();
1043 .error(tr(
"Type for lookup was expected to be one of '%1', not "
1045 .arg(types, expectedType)
)
1046 .handle(errorHandler);
1050 cNow = path
[iPath++
];
1053 .error(tr(
"Expected a key specifying the path to search after the "
1054 "@lookup directive and type, not %1 at component %2 of "
1056 .arg(cNow.toString())
1058 .arg(path.toString())
)
1059 .handle(errorHandler);
1062 QString target = cNow.headName();
1063 if (target.isEmpty()) {
1065 .warning(tr(
"Path with empty lookup at component %1 of %2 will "
1066 "match nothing in %3.")
1068 .arg(path.toString())
1070 .handle(errorHandler);
1075 [&toDos, iPath](
const DomItem &subEl) {
1076 toDos.append({ subEl, iPath });
1079 lookupType, opt, errorHandler, &(visited[iPath]), visitedRefs);
1080 branchExhausted =
true;
1086 case Path::Kind::Any:
1089 [&toDos, iPath](Path,
const DomItem &item,
bool) {
1090 toDos.append({ item, iPath });
1093 VisitOption::VisitSelf | VisitOption::Recurse | VisitOption::VisitAdopted);
1094 branchExhausted =
true;
1098 branchExhausted =
true;
1103 if (!branchExhausted && iPath == path
.length() && !visitor(fPath, it))
1114 resolve(p, [&res](
const Path &,
const DomItem &it) {
1133 return visitEl([
this](
auto &&el) {
return el->fields(*
this); });
1138 return visitEl([
this, name](
auto &&el) {
return el->field(*
this, name); });
1143 return visitEl([
this](
auto &&el) {
return el->indexes(*
this); });
1148 return visitEl([
this, i](
auto &&el) {
return el->index(*
this, i); });
1154 int nIndexes = indexes();
1155 for (
int i = 0; i < nIndexes; ++i) {
1165 return visitEl([
this](
auto &&el) {
return el->keys(*
this); });
1170 QSet<QString> ks = keys();
1171 QStringList sortedKs(ks.begin(), ks.end());
1172 std::sort(sortedKs.begin(), sortedKs.end());
1178 return visitEl([
this, name](
auto &&el) {
return el->key(*
this, name); });
1184 const QStringList keys = sortedKeys();
1185 for (
const QString &k : keys) {
1196 iterateDirectSubpaths([&res](
const PathEls::PathComponent &, function_ref<DomItem()> item) {
1206 DomItem anns = field(Fields::annotations);
1207 for (
const auto &ann : anns.values()) {
1208 if (ann.annotations().indexes() == 0) {
1213 DomItem annAnn = ann.annotations();
1214 Q_ASSERT_X(annAnn.indexes() == 1 && annAnn.index(0).name() == u"duplicate",
1215 "DomItem::writeOutPre",
"Unexpected annotation of annotation");
1219 ow.itemStart(*
this);
1225 visitEl([
this, &ow](
auto &&el) { el->writeOut(*
this, ow); });
1236 WriteOutChecks extraChecks)
const
1238 auto compare = [
this](
const DomItem &obj1,
const DomItem &obj2, QStringView obj2Name,
1240 const auto diffList = domCompareStrList(obj1, obj2, filter, DomCompareStrList::AllDiffs);
1241 if (!diffList.isEmpty()) {
1242 qCWarning(writeOutLog).noquote().nospace()
1243 << obj2Name <<
" writeOut of " <<
this->canonicalFilePath() <<
" has changes:\n"
1244 << diffList.join(QString());
1249 auto checkStability = [&ow,
this](
const QString &expected,
const DomItem &obj,
1250 QStringView objName) {
1253 ow2.indentNextlines =
true;
1256 if (ow2.writtenStr != expected) {
1257 qCWarning(writeOutLog).noquote().nospace()
1258 << objName <<
" non stable writeOut of " <<
this->canonicalFilePath() <<
":"
1259 << lineDiff(expected, ow2.writtenStr, 2);
1268 std::shared_ptr<DomEnvironment> newEnvPtr = newEnv.ownerAs<DomEnvironment>();
1270 return WriteOutCheckResult::Failed;
1272 auto newFilePtr = std::make_shared<QmlFile>(canonicalFilePath(), ow.writtenStr);
1276 if (newFilePtr->isValid()) {
1278 newEnvPtr->populateFromQmlFile(newFile);
1280 && !compare(reformatted, newFile, u"reparsed",
1282 return WriteOutCheckResult::Failed;
1284 checkStability(ow.writtenStr, newFile, u"reparsed");
1287 const auto iterateErrors = [&newFile](
const Sink &s) {
1288 newFile.iterateErrors(
1297 qCWarning(writeOutLog).noquote().nospace()
1298 <<
"writeOut of " << canonicalFilePath()
1299 <<
" created invalid code:\n----------\n"
1300 << ow.writtenStr <<
"\n----------" << iterateErrors;
1301 return WriteOutCheckResult::Failed;
1304 return WriteOutCheckResult::Success;
1308
1309
1310
1311
1312
1313
1314
1315
1316
1319 ow.indentNextlines =
true;
1320 auto currentFileItem = fileObject();
1323 WriteOutCheckResult result = WriteOutCheckResult::Success;
1325 result = performWriteOutChecks(currentFileItem, ow, extraChecks);
1326 return result == WriteOutCheckResult::Success ?
bool(currentFileItem) :
false;
1330 FileWriter *fw, WriteOutChecks extraChecks)
const
1335 auto status = fw->write(
1337 [
this, path, &options, extraChecks](QTextStream &ts) {
1338 auto lw = createLineWriter([&ts](QStringView s) { ts << s; }, path, options);
1339 OutWriter ow(getFileItemOwner(fileObject()), *lw);
1340 return writeOutForFile(ow, extraChecks);
1344 case FileWriter::Status::DidWrite:
1345 case FileWriter::Status::SkippedEqual:
1347 case FileWriter::Status::ShouldWrite:
1348 case FileWriter::Status::SkippedDueToFailure:
1349 qCWarning(writeOutLog) <<
"failure reformatting " << path;
1352 qCWarning(writeOutLog) <<
"Unknown FileWriter::Status ";
1360 bool isChild =
false;
1373 bool hasAnnotations =
false;
1377 if (
const Id *myPtr = as<
Id>())
1378 hasAnnotations = !myPtr->annotations.isEmpty();
1382 hasAnnotations = !myPtr->annotations.isEmpty();
1386 hasAnnotations = !myPtr->annotations.isEmpty();
1390 hasAnnotations = !myPtr->annotations().isEmpty();
1394 hasAnnotations = !myPtr->annotations().isEmpty();
1399 return hasAnnotations;
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1425 VisitOptions options, DomItem::ChildrenVisitor openingVisitor,
1426 DomItem::ChildrenVisitor closingVisitor,
const FieldFilter &filter)
const
1430 if (options & VisitOption::VisitSelf && !visitor(basePath, *
this,
true))
1432 if (options & VisitOption::VisitSelf && !openingVisitor(basePath, *
this,
true))
1434 auto atEnd = qScopeGuard([closingVisitor, basePath,
this, options]() {
1435 if (options & VisitOption::VisitSelf) {
1436 closingVisitor(basePath, *
this,
true);
1439 return iterateDirectSubpaths(
1440 [
this, basePath, visitor, openingVisitor, closingVisitor, options,
1441 &filter](
const PathEls::PathComponent &c, function_ref<DomItem()> itemF) {
1443 if (!(options & VisitOption::NoPath)) {
1445 pNow = pNow.withComponent(c);
1447 if (!filter(*
this, c, DomItem{}))
1449 DomItem item = itemF();
1450 bool directChild = isCanonicalChild(item);
1451 if (!directChild && !(options & VisitOption::VisitAdopted))
1453 if (!directChild || !(options & VisitOption::Recurse)) {
1454 if (!visitor(pNow, item, directChild))
1459 if (!openingVisitor(pNow, item, directChild))
1461 closingVisitor(pNow, item, directChild);
1463 return item.visitTree(pNow, visitor, options | VisitOption::VisitSelf,
1464 openingVisitor, closingVisitor, filter);
1471 QList<Path> *visitedRefs, VisitPrototypesOptions options,
1475 if (visitedRefs->contains(elId))
1478 visitedRefs->append(elId);
1479 QList<DomItem> protos = prototype.getAll(h, visitedRefs);
1480 if (protos.isEmpty()) {
1481 if (std::shared_ptr<DomEnvironment> envPtr =
1482 derivedFromPrototype.environment().ownerAs<DomEnvironment>())
1485 .warning(derivedFromPrototype.tr(
"could not resolve prototype %1 (%2)")
1487 prototype.field(Fields::referredObjectPath)
1490 .withItem(derivedFromPrototype)
1493 if (protos.size() > 1) {
1494 QStringList protoPaths;
1495 for (
const DomItem &p : protos)
1496 protoPaths.append(p.canonicalPath().toString());
1499 .tr(
"Multiple definitions found, using first only, resolving "
1500 "prototype %1 (%2): %3")
1502 prototype.field(Fields::referredObjectPath)
1505 protoPaths.join(QLatin1String(
", ")))
)
1506 .withItem(derivedFromPrototype)
1511 for (
int i = nProtos; i != 0;) {
1512 DomItem proto = protos.at(--i);
1515 proto = proto.proceedToScope(h, visitedRefs);
1522 .warning(derivedFromPrototype.tr(
"Unexpected prototype type %1 (%2)")
1524 prototype.field(Fields::referredObjectPath)
1527 .withItem(derivedFromPrototype)
1537 QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1539 QSet<quintptr> visitedLocal;
1541 visited = &visitedLocal;
1542 QList<Path> refsLocal;
1544 visitedRefs = &refsLocal;
1546 DomItem current = qmlObject();
1551 QList<DomItem> toDo({ current });
1552 while (!toDo.isEmpty()) {
1553 current = toDo.takeLast();
1554 current = current.proceedToScope(h, visitedRefs);
1555 if (visited->contains(current.id())) {
1561 .warning(tr(
"Detected multiple visit of %1 visiting prototypes of %2")
1568 visited->insert(current.id());
1569 if (shouldVisit && !visitor(current))
1572 current.field(Fields::prototypes)
1573 .visitIndexes([&toDo, ¤t,
this, &h, visitedRefs, options](
const DomItem &el) {
1574 return visitPrototypeIndex(toDo, current, *
this, h, visitedRefs, options, el);
1581 function_ref<
bool(
const DomItem &)> visitor, VisitPrototypesOptions options,
1582 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1587 if (k == DomType::QmlObject)
1588 return visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1589 if (visited && id() != 0) {
1590 if (visited->contains(id()))
1592 visited->insert(id());
1596 DomItem v = proceedToScope(h, visitedRefs);
1598 return v.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1602 DomItem v = field(Fields::value);
1604 return v.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1608 DomItem t = field(Fields::type).proceedToScope(h, visitedRefs);
1610 return t.visitPrototypeChain(visitor, options, h, visited, visitedRefs);
1618
1619
1620
1621
1622
1623
1624
1625
1626
1628 function_ref<
bool(
const DomItem &)> visitor, VisitPrototypesOptions options,
1629 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1631 QSet<quintptr> visitedLocal;
1633 visited = &visitedLocal;
1634 DomItem current = qmlObject();
1635 DomItem comp = current.component();
1636 if (comp.field(Fields::isSingleton).value().toBool(
false)
1637 && !current.visitPrototypeChain(visitor, options, h, visited, visitedRefs))
1639 if (
DomItem attachedT = current.component().field(Fields::attachedType).field(Fields::get))
1640 if (!attachedT.visitPrototypeChain(
1642 visited, visitedRefs))
1648
1649
1655 if (!visitor(current))
1663
1664
1666 function_ref<
bool(
const DomItem &)> visitor, LookupOptions options,
const ErrorHandler &h,
1667 QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1669 QSet<quintptr> visitedLocal;
1671 visited = &visitedLocal;
1672 QList<Path> visitedRefsLocal;
1674 visitedRefs = &visitedRefsLocal;
1680 QList<DomItem> toDo { current };
1681 bool visitFirst = !(options & LookupOption::SkipFirstScope);
1682 bool visitCurrent = visitFirst;
1684 QSet<quintptr> alreadyAddedComponentMaps;
1685 while (!toDo.isEmpty()) {
1686 DomItem current = toDo.takeLast();
1687 if (visited->contains(current.id()))
1689 visited->insert(current.id());
1690 if (visitCurrent && !visitor(current))
1692 visitCurrent =
true;
1698 DomItem root = current.rootQmlObject();
1699 if (root && root
!= current) {
1713 if ((options & LookupOption::Strict) == 0) {
1714 if (
DomItem comp = current.field(Fields::nextComponent))
1717 if (first && visitFirst && (options & LookupOption::VisitTopClassType)
1718 && *
this == current) {
1719 if (
DomItem attachedT = current.field(Fields::attachedType).field(Fields::get))
1720 toDo.append(attachedT);
1728 if (alreadyAddedComponentMaps.contains(componentMap.id()))
1730 alreadyAddedComponentMaps.insert(componentMap.id());
1731 const auto keys = componentMap.keys();
1732 for (
const QString &x : keys) {
1733 DomItem componentList = componentMap.key(x);
1734 for (
int i = 0; i < componentList.indexes(); ++i) {
1735 DomItem component = componentList.index(i);
1736 if (component != current && !visited->contains(component.id()))
1737 toDo.append(component);
1745 current.field(Fields::importScope))
1746 toDo.append(iScope);
1756 if (
auto globalC = globalScope().field(Fields::rootComponent))
1757 toDo.append(globalC);
1762 if (
DomItem next = current.field(Fields::objects).index(0))
1771 .error(tr(
"Unexpected non scope object %1 (%2) reached in visitScopeChain")
1772 .arg(domTypeToString(current.internalKind()),
1773 current.canonicalPath().toString()))
1783 const QString &symbolName, function_ref<
bool(
const DomItem &)> visitor, LookupOptions opts,
1784 const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
const
1786 return visitScopeChain(
1787 [symbolName, visitor](
const DomItem &obj) {
1788 return obj.visitLocalSymbolsNamed(symbolName,
1789 [visitor](
const DomItem &el) {
return visitor(el); });
1791 opts, h, visited, visitedRefs);
1803 QRegularExpression reTarget = QRegularExpression(QRegularExpression::anchoredPattern(
1804 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>\*?))"));
1806 QRegularExpressionMatch m = reTarget.matchView(target);
1807 if (!m.hasMatch()) {
1809 .error(tr(
"Unexpected complex CppType %1").arg(target)
)
1812 res.baseType = m.captured(u"baseType");
1813 res
.isPointer = !m.captured(u"ptr").isEmpty();
1814 if (!m.captured(u"list").isEmpty()) {
1816 res.baseType = m.captured(u"list");
1817 res
.isPointer = !m.captured(u"listPtr").isEmpty();
1819 if (!m.captured(u"mapValue").isEmpty()) {
1821 if (m.captured(u"mapKey") != u"QString") {
1823 .error(tr(
"Unexpected complex CppType %1 (map with non QString key)")
1827 res.baseType = m.captured(u"mapValue");
1828 res
.isPointer = !m.captured(u"mapPtr").isEmpty();
1840 function_ref<
bool(
const DomItem &)> visitor)
1842 bool correctType =
false;
1844 switch (lookupType) {
1845 case LookupType::Binding:
1848 case LookupType::Method:
1851 case LookupType::Property:
1854 case LookupType::PropertyDef:
1857 case LookupType::Type:
1870 const DomItem &newIt,
const QStringList &subpath,
1871 function_ref<
bool(
const DomItem &)> visitor, LookupType lookupType,
1872 const ErrorHandler &errorHandler, QList<Path> *visitedRefs)
1874 QVector<ResolveToDo> lookupToDos(
1875 { ResolveToDo{ newIt, 1 } });
1877 QList<QSet<quintptr>> lookupVisited(subpath.size() + 1);
1878 while (!lookupToDos.isEmpty()) {
1880 auto vNow = std::make_pair(tNow.item.id(), tNow.pathIndex);
1883 Q_ASSERT(iSubPath < subpath.size());
1884 QString subPathNow = subpath[iSubPath++];
1885 DomItem scope = subNow.proceedToScope();
1886 if (iSubPath < subpath.size()) {
1887 if (vNow.first != 0) {
1888 if (lookupVisited[vNow.second].contains(vNow.first))
1891 lookupVisited[vNow.second].insert(vNow.first);
1893 if (scope.internalKind() == DomType::QmlObject)
1894 scope.visitDirectAccessibleScopes(
1895 [&lookupToDos, &subPathNow, iSubPath](
const DomItem &el) {
1896 return el.visitLocalSymbolsNamed(
1897 subPathNow, [&lookupToDos, iSubPath](
const DomItem &subEl) {
1898 lookupToDos.append({ subEl, iSubPath });
1902 VisitPrototypesOption::Normal, errorHandler, &(lookupVisited[vNow.second]),
1905 bool cont = scope.visitDirectAccessibleScopes(
1906 [&visitor, &subPathNow, lookupType](
const DomItem &el) ->
bool {
1907 if (lookupType == LookupType::Symbol)
1908 return el.visitLocalSymbolsNamed(subPathNow, visitor);
1910 return el.visitLocalSymbolsNamed(
1911 subPathNow, [lookupType, &visitor](
const DomItem &el) ->
bool {
1912 return visitForLookupType(el, lookupType, visitor);
1915 VisitPrototypesOption::Normal, errorHandler, &(lookupVisited[vNow.second]),
1925 const QString &target, function_ref<
bool(
const DomItem &)> visitor, LookupType lookupType,
1926 LookupOptions opts,
const ErrorHandler &errorHandler, QSet<quintptr> *visited,
1927 QList<Path> *visitedRefs)
const
1929 if (target.isEmpty())
1931 switch (lookupType) {
1932 case LookupType::Binding:
1933 case LookupType::Method:
1934 case LookupType::Property:
1935 case LookupType::PropertyDef:
1936 case LookupType::Symbol:
1937 case LookupType::Type: {
1938 QStringList subpath = target.split(QChar::fromLatin1(
'.'));
1939 if (subpath.size() == 1) {
1940 return visitLookup1(subpath.first(), visitor, opts, errorHandler, visited, visitedRefs);
1942 return visitLookup1(
1944 [&subpath, visitor, lookupType, &errorHandler,
1945 visitedRefs](
const DomItem &newIt) ->
bool {
1946 return visitQualifiedNameLookup(newIt, subpath, visitor, lookupType,
1947 errorHandler, visitedRefs);
1949 opts, errorHandler, visited, visitedRefs);
1953 case LookupType::CppType: {
1954 QString baseTarget = CppTypeInfo::fromString(target, errorHandler).baseType;
1958 localQmltypes = localQmltypes
.owner();
1960 if (localQmltypes) {
1961 if (
DomItem localTypes = localQmltypes.field(Fields::components).key(baseTarget)) {
1962 bool cont = localTypes.visitIndexes([&visitor](
const DomItem &els) {
1963 return els.visitIndexes([&visitor](
const DomItem &el) {
1964 if (DomItem obj = el.field(Fields::objects).index(0))
1965 return visitor(obj);
1974 return qmltypes.visitKeys([baseTarget, &visitor](
const QString &,
const DomItem &els) {
1976 els.field(Fields::currentItem).field(Fields::components).key(baseTarget);
1977 return comps.visitIndexes([&visitor](
const DomItem &el) {
1978 if (DomItem obj = el.field(Fields::objects).index(0))
1979 return visitor(obj);
1991
1992
1993
1994
1995
1996
1997
2006 current = current.get(h, visitedRefs);
2010 current = current.field(Fields::type);
2013 current = current.field(Fields::referredObject);
2029 [&res](
const DomItem &el) {
2033 type, opts, errorHandler);
2043 [&res](
const DomItem &el) {
2047 type, opts, errorHandler);
2053 return visitEl([](
auto &&b) {
return b->id(); });
2058 return visitEl([](
auto &&e) {
return e->pathFromOwner(); });
2063 return visitEl([
this](
auto &&e) {
return e->canonicalFilePath(*
this); });
2072 DomItem newItem = std::visit([
this, &o](
auto &&el) {
2073 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>) {
2076 auto copyPtr = el->makeCopy(o);
2077 return DomItem(m_top, copyPtr, m_ownerPath, copyPtr.get());
2083 std::shared_ptr<DomEnvironment> newEnvPtr;
2084 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
2085 newEnvPtr =
std::make_shared<DomEnvironment>(envPtr, envPtr->loadPaths(), envPtr->options(),
2086 envPtr->domCreationOption());
2087 DomBase *eBase = envPtr.get();
2088 if (std::holds_alternative<
const DomEnvironment *>(m_element) && eBase
2089 && std::get<
const DomEnvironment *>(m_element) == eBase)
2091 }
else if (std::shared_ptr<DomUniverse> univPtr = top().ownerAs<DomUniverse>()) {
2092 newEnvPtr =
std::make_shared<DomEnvironment>(
2101 [
this, newEnvPtr, &o](
auto &&el) {
2102 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>) {
2105 auto copyPtr = el->makeCopy(o);
2106 return DomItem(newEnvPtr, copyPtr, m_ownerPath, copyPtr.get());
2127 case DomType::ModuleIndex:
2128 case DomType::MockOwner:
2129 case DomType::ScriptExpression:
2130 case DomType::AstComments:
2131 case DomType::LoadInfo:
2132 case DomType::FileLocationsNode:
2133 case DomType::DomEnvironment:
2134 case DomType::DomUniverse:
2135 qCWarning(domLog) <<
"DomItem::makeCopy " << internalKindStr()
2136 <<
" does not support binding to environment";
2140 qCWarning(domLog) <<
"DomItem::makeCopy(" << internalKindStr()
2141 <<
") is not an known OwningItem";
2153 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
2154 return envPtr->commitToBase(env, validEnvPtr);
2169 case DomType::QmlObject:
2170 f = field(Fields::propertyDefs);
2172 if (!v.visitIndexes(visitor))
2174 f = field(Fields::bindings);
2176 if (!v.visitIndexes(visitor))
2178 f = field(Fields::methods);
2180 if (!v.visitIndexes(visitor))
2186 case DomType::QmlComponent:
2187 f = field(Fields::ids);
2189 if (!v.visitIndexes(visitor))
2192 case DomType::JsResource:
2193 case DomType::GlobalComponent:
2194 case DomType::QmltypesComponent:
2195 f = field(Fields::enumerations);
2197 if (!v.visitIndexes(visitor))
2201 DomItem params = field(Fields::parameters);
2202 if (!params.visitIndexes([name, visitor](
const DomItem &p) {
2204 if (pPtr->name == name && !visitor(p))
2212 f = field(Fields::components);
2214 if (!v.visitIndexes(visitor))
2219 f = field(Fields::imported);
2221 if (!v.visitIndexes(visitor))
2223 f = field(Fields::qualifiedImports);
2225 if (v && !visitor(v))
2238 if (internalKind() == DomType::Map)
2240 return field(cName);
2245 if (internalKind() == DomType::Map)
2246 return key(cName.toString());
2247 return field(cName);
2257 return base()->value();
2262 sink(u"DomItem{ topPtr:");
2263 sink(QString::number((quintptr)topPtr().get(), 16));
2264 sink(u", ownerPtr:");
2265 sink(QString::number((quintptr)owningItemPtr().get(), 16));
2266 sink(u", ownerPath:");
2267 m_ownerPath.dump(sink);
2269 sink(QString::number((quintptr)base(),16));
2274 const Sink &s,
int indent,
2275 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2277 visitEl([
this, s, indent, filter](
auto &&e) { e->dump(*
this, s, indent, filter); });
2282 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter,
2283 int nBackups,
int indent,
FileWriter *fw)
const
2290 [
this, indent, filter](QTextStream &ts) {
2291 this->dump([&ts](QStringView s) { ts << s; }, indent, filter);
2295 case FileWriter::Status::ShouldWrite:
2296 case FileWriter::Status::SkippedDueToFailure:
2297 qWarning() <<
"Failure dumping " <<
canonicalPath() <<
" to " << path;
2299 case FileWriter::Status::DidWrite:
2300 case FileWriter::Status::SkippedEqual:
2308 return dumperToString([
this](
const Sink &s){ dump(s); });
2313 return std::visit([](
auto &&ow) {
2314 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2317 return ow->derivedFrom();
2323 return std::visit([](
auto &&ow) {
2324 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2327 return ow->revision();
2333 return std::visit([](
auto &&ow) {
2334 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2335 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2337 return ow->createdAt();
2343 return std::visit([](
auto &&ow) {
2344 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2345 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2347 return ow->frozenAt();
2353 return std::visit([](
auto &&ow) {
2354 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2355 return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
2357 return ow->lastDataUpdateAt();
2363 std::visit([
this, &msg](
auto &&ow) {
2364 if constexpr (std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2365 defaultErrorHandler(msg.withItem(*
this));
2367 ow->addError(owner(), std::move(msg.withItem(*
this)));
2379 std::visit([&groups](
auto &&ow) {
2380 if constexpr (!std::is_same_v<std::decay_t<
decltype(ow)>, std::monostate>)
2381 ow->clearErrors(groups);
2385 iterateSubOwners([groups](
const DomItem &i){
2386 i.clearErrors(groups,
true);
2393 function_ref<
bool(
const DomItem &,
const ErrorMessage &)> visitor,
bool iterate,
2396 if (!std::visit([
this, visitor, inPath](
auto &&el) {
2397 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2400 return el->iterateErrors(owner(), visitor, inPath);
2405 if (iterate && !iterateSubOwners([inPath, visitor](
const DomItem &i) {
2406 return i.iterateErrors(visitor,
true, inPath);
2416 return std::visit([
this, visitor](
auto &&o) {
2417 if constexpr (std::is_same_v<std::decay_t<
decltype(o)>, std::monostate>)
2420 return o->iterateSubOwners(owner(), visitor);
2427 [
this, v](
auto &&el) {
return el->iterateDirectSubpaths(*
this, v); });
2433 List::fromQList<Path>(pathFromOwner().withComponent(c), paths,
2434 [](
const DomItem &list,
const PathEls::PathComponent &p,
const Path &el) {
2435 return list.subReferenceItem(p, el);
2442 return DomItem(m_top, m_owner, m_ownerPath, Reference(referencedObject, Path(c)));
2444 return DomItem(m_top, m_owner, m_ownerPath,
2445 Reference(referencedObject, pathFromOwner().withComponent(c)));
2451 return std::visit([](
auto &&el) -> shared_ptr<DomTop> {
2452 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2461 return std::visit([](
auto &&el) -> shared_ptr<OwningItem> {
2462 if constexpr (std::is_same_v<std::decay_t<
decltype(el)>, std::monostate>)
2470
2471
2472
2475 return visitEl([](
auto &&el) ->
const DomBase * {
return el->domBase(); });
2484 DomItem(universePtr, universePtr,
Path(), universePtr.get())
2489
2490
2491
2492
2493
2494
2495
2504 FileToLoad::fromMemory(env, QString(), code),
2505 [&tFile](Path,
const DomItem &,
const DomItem &newIt) { tFile = newIt; },
2506 std::make_optional(fileType));
2507 return tFile.fileObject();
2534 const DomItem &,
const Sink &s,
int,
2541 const Keys &keys,
const QString &targetType)
2552 QSet<QString> ksSet = keys(self);
2553 QStringList ksList = QStringList(ksSet.begin(), ksSet.end());
2554 std::sort(ksList.begin(), ksList.end());
2555 for (
const QString &k : std::as_const(ksList)) {
2556 if (!visitor(PathEls::Key(k), [&self,
this, k]() {
return key(self, k); }))
2564 return m_keys(self);
2569 return m_lookup(self, name);
2573 const DomItem &self,
const Sink &sink,
int indent,
2574 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2577 DomKind dK = self.domKind();
2579 case DomKind::Object:
2580 sink(u"{ \"~type~\":");
2581 sinkEscaped(sink, typeName());
2584 case DomKind::Value:
2586 sink(QString::fromUtf8(value().toJsonValue().toJson()));
2589 case DomKind::Empty:
2598 case DomKind::ScriptElement:
2602 auto closeParens = qScopeGuard(
2605 case DomKind::Object:
2606 sinkNewline(sink, indent);
2609 case DomKind::Value:
2611 case DomKind::Empty:
2614 sinkNewline(sink, indent);
2618 sinkNewline(sink, indent);
2621 case DomKind::ScriptElement:
2627 self.iterateDirectSubpaths(
2629 function_ref<DomItem()> itemF) {
2631 if (!filter(self, c, i))
2639 sinkNewline(sink, indent + 2);
2640 if (dK != DomKind::Object)
2641 sink(u"UNEXPECTED ENTRY ERROR:");
2642 sinkEscaped(sink, c.name());
2646 sinkNewline(sink, indent + 2);
2647 if (dK != DomKind::Map)
2648 sink(u"UNEXPECTED ENTRY ERROR:");
2649 sinkEscaped(sink, c.name());
2653 sinkNewline(sink, indent + 2);
2654 if (dK != DomKind::List)
2655 sink(u"UNEXPECTED ENTRY ERROR:");
2656 else if (idx++ != c.index())
2657 sink(u"OUT OF ORDER ARRAY:");
2660 sinkNewline(sink, indent + 2);
2661 sink(u"UNEXPECTED PATH KIND ERROR (ignored)");
2665 i.dump(sink, indent + 2, filter);
2667 sink(uR"({ "~type~": "Reference", "immediate": true, "referredObjectPath":")");
2679 const QString &elType):
2690 const DomItem &self,
const Sink &sink,
int indent,
2691 function_ref<
bool(
const DomItem &,
const PathEls::PathComponent &,
const DomItem &)> filter)
const
2695 iterateDirectSubpaths(
2697 [&self, indent, &first, sink, filter](
const PathEls::PathComponent &c,
2698 function_ref<DomItem()> itemF) {
2699 DomItem item = itemF();
2700 if (!filter(self, c, item))
2706 sinkNewline(sink, indent + 2);
2707 item.dump(sink, indent + 2, filter);
2716 return m_iterator(self, [visitor](index_type i, function_ref<DomItem()> itemF) {
2717 return visitor(PathEls::Index(i), itemF);
2720 index_type len = indexes(self);
2721 for (index_type i = 0; i < len; ++i) {
2722 if (!visitor(
PathEls::Index(i), [
this, &self, i]() {
return index(self, i); }))
2730 return m_length(self);
2735 return m_lookup(self, index);
2741 ow.writeRegion(fLoc, LeftBracketRegion);
2743 iterateDirectSubpaths(self,
2744 [&ow, &first, &fLoc, compact](
const PathEls::PathComponent &,
2745 function_ref<DomItem()> elF) {
2749 ow.writeRegion(fLoc, CommaTokenRegion).ensureSpace();
2751 ow.ensureNewline(1);
2756 if (!compact && !first)
2758 ow.writeRegion(fLoc, RightBracketRegion);
2765 Q_ASSERT(m_pathFromOwner &&
"uninitialized DomElement");
2766 return self.owner().canonicalPath().withPath(m_pathFromOwner);
2771 Q_ASSERT(m_pathFromOwner &&
"uninitialized DomElement");
2778 m_pathFromOwner = newPath;
2783 for (
const Path &p : referredObjectPath) {
2784 switch (p.headKind()) {
2785 case Path::Kind::Current:
2786 switch (p.headCurrent()) {
2787 case PathCurrent::Lookup:
2788 case PathCurrent::LookupDynamic:
2789 case PathCurrent::LookupStrict:
2790 case PathCurrent::ObjChain:
2791 case PathCurrent::ScopeChain:
2797 case Path::Kind::Empty:
2798 case Path::Kind::Any:
2799 case Path::Kind::Filter:
2821 cont = cont && self.dvValueLazyField(visitor, Fields::referredObjectPath, [
this]() {
2822 return referredObjectPath.toString();
2825 && self.dvItemField(visitor, Fields::get, [
this, &self]() {
return this->get(self); });
2831 if (Fields::referredObjectPath == name)
2832 return self.subDataItemField(Fields::referredObjectPath, referredObjectPath.toString());
2833 if (Fields::get == name)
2840 return QList<QString>({Fields::referredObjectPath.toString(), Fields::get.toString()});
2856 if (referredObjectPath) {
2864 RefCacheEntry cached = RefCacheEntry::forPath(self, selfPath);
2865 switch (cached.cached) {
2866 case RefCacheEntry::Cached::None:
2868 case RefCacheEntry::Cached::First:
2869 case RefCacheEntry::Cached::All:
2870 if (!cached.canonicalPaths.isEmpty())
2871 cachedPath = cached.canonicalPaths.first();
2879 qCWarning(refLog) <<
"referenceCache outdated, reference at " << selfPath
2880 <<
" leads to invalid path " << cachedPath;
2886 QList<Path> visitedRefsLocal;
2889 [&res](Path,
const DomItem &el) {
2893 h, ResolveOption::None, referredObjectPath,
2894 (visitedRefs ? visitedRefs : &visitedRefsLocal));
2896 RefCacheEntry::addForPath(
2897 env, selfPath, RefCacheEntry { RefCacheEntry::Cached::First, { cachedPath } });
2906 if (referredObjectPath) {
2909 QList<Path> cachedPaths;
2913 RefCacheEntry cached = RefCacheEntry::forPath(env, selfPath);
2914 switch (cached.cached) {
2915 case RefCacheEntry::Cached::None:
2916 case RefCacheEntry::Cached::First:
2918 case RefCacheEntry::Cached::All:
2919 cachedPaths += cached.canonicalPaths;
2920 if (cachedPaths.isEmpty())
2924 if (!cachedPaths.isEmpty()) {
2925 bool outdated =
false;
2926 for (
const Path &p : cachedPaths) {
2927 DomItem newEl = env.path(p);
2930 qCWarning(refLog) <<
"referenceCache outdated, reference at " << selfPath
2931 <<
" leads to invalid path " << p;
2945 [&res](Path,
const DomItem &el) {
2949 h, ResolveOption::None, referredObjectPath, visitedRefs);
2951 QList<Path> canonicalPaths;
2952 for (
const DomItem &i : res) {
2954 canonicalPaths.append(i.canonicalPath());
2957 <<
"getAll of reference at " << selfPath <<
" visits empty items.";
2959 RefCacheEntry::addForPath(
2961 RefCacheEntry { RefCacheEntry::Cached::All, std::move(canonicalPaths) });
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2985 : m_derivedFrom(derivedFrom),
2993 : m_derivedFrom(derivedFrom),
3007 QMultiMap<Path, ErrorMessage> my_errors;
3009 QMutexLocker l1(o.mutex());
3010 my_errors = o.m_errors;
3014 QMutexLocker l2(mutex());
3015 m_errors = my_errors;
3022 static QAtomicInt nextRev(0);
3029 cont = cont && self.dvItemField(visitor, Fields::errors, [&self,
this]() {
3030 QMultiMap<Path, ErrorMessage> myErrors = localErrors();
3031 return self.subMapItem(Map(
3032 self.pathFromOwner().withField(Fields::errors),
3033 [myErrors](
const DomItem &map,
const QString &key) {
3034 auto it = myErrors.find(Path::fromString(key));
3035 if (it != myErrors.end())
3036 return map.subDataItem(PathEls::Key(key), it->toCbor(),
3037 ConstantData::Options::FirstMapIsFields);
3041 [myErrors](
const DomItem &) {
3043 auto it = myErrors.keyBegin();
3044 auto end = myErrors.keyEnd();
3046 res.insert(it++->toString());
3049 QLatin1String(
"ErrorMessages")));
3057 if (s.pathFromSource) {
3058 if (!s.pathToSource)
3060 return self
.path(s.pathToSource
);
3067 return m_derivedFrom;
3077 return m_frozenAt > m_createdAt;
3083 m_frozenAt = QDateTime::currentDateTimeUtc();
3084 if (m_frozenAt <= m_createdAt)
3085 m_frozenAt = m_createdAt.addSecs(1);
3098 return m_lastDataUpdateAt;
3108 if (m_lastDataUpdateAt < tNew)
3109 m_lastDataUpdateAt = tNew;
3119 QMutexLocker l(mutex());
3120 quint32 &c = m_errorsCounts[msg];
3123 m_errors.insert(msg.path, msg);
3128 QMutexLocker l(mutex());
3129 auto it = m_errors.begin();
3130 while (it != m_errors.end()) {
3131 if (it->errorGroups == groups)
3132 it = m_errors.erase(it);
3139 const DomItem &self, function_ref<
bool(
const DomItem &,
const ErrorMessage &)> visitor,
3142 QMultiMap<Path, ErrorMessage> myErrors;
3144 QMutexLocker l(mutex());
3145 myErrors = m_errors;
3147 auto it = myErrors.lowerBound(inPath);
3148 auto end = myErrors.end();
3149 while (it != end && it.key().mid(0, inPath
.length()) == inPath) {
3150 if (!visitor(self, *it++))
3158 return self.iterateDirectSubpaths(
3161 if (i.owningItemPtr() != self.owningItemPtr()) {
3163 if (container.id() == self.id())
3172 if (o1.m_kind != o2.m_kind)
3174 return o1.visitEl([&o1, &o2](
auto &&el1) {
3175 auto &&el2 = std::get<std::decay_t<
decltype(el1)>>(o2.m_element);
3176 auto id1 = el1->id();
3177 auto id2 = el2->id();
3180 if (id1 != quintptr(0))
3182 if (o1.m_owner != o2.m_owner)
3184 Path p1 = el1->pathFromOwner();
3185 Path p2 = el2->pathFromOwner();
3204 Q_ASSERT(
false &&
"addPropertyDef on non qml scope");
3213 Q_ASSERT(
false &&
"addBinding on non qml scope");
3222 Q_ASSERT(
false &&
"addMethod on non qml scope");
3230 }
else if (QmlComponent *el = mutableAs<QmlComponent>()) {
3234 Q_ASSERT(
false &&
"addChild on non qml scope");
3242 dumperToQDebug([&c](
const Sink &s) { c.dump(s); }, debug);
3249 return debug.noquote().nospace() <<
"MutableDomItem(" << domTypeToString(cc.internalKind())
3250 <<
", " << cc.canonicalPath().toString() <<
")";
3255 index_type len = index_type(m_pList.size());
3256 for (index_type i = 0; i < len; ++i) {
3257 if (!v(
PathEls::Index(i), [
this, &self, i] {
return this->index(self, i); }))
3266 ow.writeRegion(fLoc, LeftBracketRegion);
3268 index_type len = index_type(m_pList.size());
3269 for (index_type i = 0; i < len; ++i) {
3273 ow.writeRegion(fLoc, CommaTokenRegion).ensureSpace();
3275 ow.ensureNewline(1);
3279 if (!compact && !first)
3281 ow.writeRegion(fLoc, RightBracketRegion);
3294
3295
3296
3297
3298
3307 return std::shared_ptr<ScriptElement>(
3308 e,
static_cast<ScriptElement *>(e.get()));
3317 return fileItem.ownerAs<JsFile>();
3319 return fileItem.ownerAs<QmlFile>();
3321 Q_UNREACHABLE_RETURN({});
3330#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)
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()