156 cont = cont && DomTop::iterateDirectSubpaths(self, visitor);
157 cont = cont && self.invokeVisitorOnValue(visitor,
PathEls::Field(Fields::name), name());
158 cont = cont && visitor(
PathEls::Field(Fields::globalScopeWithName), [
this, &self]() {
159 return self.subMapItem(Map(
160 Path::fromField(Fields::globalScopeWithName),
161 [
this](
const DomItem &map,
const QString &key) {
162 return map.copy(globalScopeWithName(key));
164 [
this](
const DomItem &) {
return globalScopeNames(); },
165 QLatin1String(
"GlobalScope")));
167 cont = cont && visitor(
PathEls::Field(Fields::qmlDirectoryWithPath), [
this, &self]() {
168 return self.subMapItem(Map(
169 Path::fromField(Fields::qmlDirectoryWithPath),
170 [
this](
const DomItem &map,
const QString &key) {
171 return map.copy(qmlDirectoryWithPath(key));
173 [
this](
const DomItem &) {
return qmlDirectoryPaths(); },
174 QLatin1String(
"QmlDirectory")));
176 cont = cont && visitor(
PathEls::Field(Fields::qmldirFileWithPath), [
this, &self]() {
177 return self.subMapItem(Map(
178 Path::fromField(Fields::qmldirFileWithPath),
179 [
this](
const DomItem &map,
const QString &key) {
180 return map.copy(qmldirFileWithPath(key));
182 [
this](
const DomItem &) {
return qmldirFilePaths(); },
183 QLatin1String(
"QmldirFile")));
185 cont = cont && visitor(
PathEls::Field(Fields::qmlFileWithPath), [
this, &self]() {
186 return self.subMapItem(Map(
187 Path::fromField(Fields::qmlFileWithPath),
188 [
this](
const DomItem &map,
const QString &key) {
189 return map.copy(qmlFileWithPath(key));
191 [
this](
const DomItem &) {
return qmlFilePaths(); },
192 QLatin1String(
"QmlFile")));
194 cont = cont && visitor(
PathEls::Field(Fields::jsFileWithPath), [
this, &self]() {
195 return self.subMapItem(Map(
196 Path::fromField(Fields::jsFileWithPath),
197 [
this](
const DomItem &map,
const QString &key) {
198 return map.copy(jsFileWithPath(key));
200 [
this](
const DomItem &) {
return jsFilePaths(); }, QLatin1String(
"JsFile")));
202 cont = cont && visitor(
PathEls::Field(Fields::jsFileWithPath), [
this, &self]() {
203 return self.subMapItem(Map(
204 Path::fromField(Fields::qmltypesFileWithPath),
205 [
this](
const DomItem &map,
const QString &key) {
206 return map.copy(qmltypesFileWithPath(key));
208 [
this](
const DomItem &) {
return qmltypesFilePaths(); },
209 QLatin1String(
"QmltypesFile")));
216 QRegularExpression r(QRegularExpression::anchoredPattern(QLatin1String(R"(.*Copy([0-9]*)$)")));
217 auto m = r.match(m_name);
220 newName = QStringLiteral(u"%1Copy%2").arg(m_name).arg(m.captured(1).toInt() + 1);
222 newName = m_name + QLatin1String(
"Copy");
223 auto res =
std::make_shared<DomUniverse>(newName);
229 if (canonicalFilePath.endsWith(u".qml", Qt::CaseInsensitive)
230 || canonicalFilePath.endsWith(u".qmlannotation", Qt::CaseInsensitive)) {
232 }
else if (canonicalFilePath.endsWith(u".qmltypes")) {
234 }
else if (QStringView(u"qmldir").compare(QFileInfo(canonicalFilePath).fileName(),
238 }
else if (QFileInfo(canonicalFilePath).isDir()) {
240 }
else if (canonicalFilePath.endsWith(u".js", Qt::CaseInsensitive)
241 || canonicalFilePath.endsWith(u".mjs", Qt::CaseInsensitive)) {
246 .error(QCoreApplication::translate(
"Dom::fileTypeForPath",
247 "Could not detect type of file %1")
248 .arg(canonicalFilePath))
257 DomItem univ(shared_from_this());
265 const auto &preLoadResult = preload(univ, file, fileType);
271 return load(
std::get<ContentWithDate>(preLoadResult), file, fileType, creationOption);
276 .error(tr(
"Ignoring request to load file %1 of unexpected type %2, "
277 "calling callback immediately")
278 .arg(file.canonicalPath(), domTypeToString(fileType))
)
280 Q_ASSERT(
false &&
"loading non supported file type");
285DomUniverse::
LoadResult DomUniverse::load(
const ContentWithDate &codeWithDate,
289 QString canonicalPath = file.canonicalPath();
296 auto qmlFile = parseQmlFile(codeWithDate.content, file, codeWithDate.date, creationOption);
297 return insertOrUpdateExternalItem(
std::move(qmlFile));
299 auto qmltypesFile =
std::make_shared<QmltypesFile>(canonicalPath, codeWithDate.content,
301 QmltypesReader reader(qmltypesFile);
303 return insertOrUpdateExternalItem(
std::move(qmltypesFile));
305 shared_ptr<QmldirFile> qmldirFile =
306 QmldirFile::fromPathAndCode(canonicalPath, codeWithDate.content);
307 return insertOrUpdateExternalItem(
std::move(qmldirFile));
309 auto qmlDirectory =
std::make_shared<QmlDirectory>(
310 canonicalPath, codeWithDate.content.split(QLatin1Char(
'\n')), codeWithDate.date);
311 return insertOrUpdateExternalItem(
std::move(qmlDirectory));
313 auto jsFile = parseJsFile(codeWithDate.content, file, codeWithDate.date);
314 return insertOrUpdateExternalItem(
std::move(jsFile));
318 return {
std::move(oldValue),
std::move(newValue) };
322
323
324
325
326
327
328
329DomUniverse::PreloadResult DomUniverse::preload(
const DomItem &univ,
const FileToLoad &file,
332 QString canonicalPath = file.canonicalPath();
333 ContentWithDate codeWithDate;
335 if (file.content().has_value()) {
336 codeWithDate = { file.content()->data, file.content()->date };
340 const auto &curValueItem = getItemIfMostRecent(univ, fType, canonicalPath);
341 if (curValueItem.has_value()) {
342 return LoadResult{ curValueItem.value(), curValueItem.value() };
345 auto readResult = readFileContent(canonicalPath);
351 codeWithDate =
std::get<ContentWithDate>(readResult);
356 const auto &curValueItem = getItemIfHasSameCode(univ, fType, canonicalPath, codeWithDate);
357 if (curValueItem.has_value()) {
358 return LoadResult{ curValueItem.value(), curValueItem.value() };
366 QMutexLocker l(mutex());
367 const auto toDelete = [path](
const auto &it) {
368 QString p = it.key();
369 return p.startsWith(path) && (p.size() == path.size() || p.at(path.size()) == u'/');
371 m_qmlDirectoryWithPath.removeIf(toDelete);
372 m_qmldirFileWithPath.removeIf(toDelete);
373 m_qmlFileWithPath.removeIf(toDelete);
374 m_jsFileWithPath.removeIf(toDelete);
375 m_qmltypesFileWithPath.removeIf(toDelete);
378DomUniverse::ReadResult DomUniverse::readFileContent(
const QString &canonicalPath)
const
380 if (canonicalPath.isEmpty()) {
383 QFile file(canonicalPath);
384 QFileInfo fileInfo(canonicalPath);
385 if (fileInfo.isDir()) {
386 return ContentWithDate{ QDir(canonicalPath)
387 .entryList(QDir::NoDotAndDotDot | QDir::Files, QDir::Name)
388 .join(QLatin1Char(
'\n')),
389 QDateTime::currentDateTimeUtc() };
391 if (!file.open(QIODevice::ReadOnly)) {
393 tr(
"Error opening path %1: %2 %3")
394 .arg(canonicalPath, QString::number(file.error()), file.errorString())
);
396 auto content = QString::fromUtf8(file.readAll());
398 return ContentWithDate{ std::move(content), QDateTime::currentDateTimeUtc() };
401std::shared_ptr<QmlFile> DomUniverse::parseQmlFile(
const QString &code,
const FileToLoad &file,
402 const QDateTime &contentDate,
406 std::make_shared<QmlFile>(file.canonicalPath(), code, contentDate, 0,
407 creationOption == Extended ? QmlFile::EnableParserRecovery
408 : QmlFile::DisableParserRecovery);
409 std::shared_ptr<DomEnvironment> envPtr;
410 if (
auto ptr = file.environment())
411 envPtr =
std::move(ptr);
413 envPtr =
std::make_shared<DomEnvironment>(QStringList(),
415 creationOption, shared_from_this());
416 envPtr->addQmlFile(qmlFile);
418 if (qmlFile->isValid()) {
424 DomItem qmlFileObj = env.copy(qmlFile);
426 errs += m.toString();
430 qCWarning(domLog).noquote().nospace()
431 <<
"Parsed invalid file " << file.canonicalPath() << errs;
436std::shared_ptr<JsFile> DomUniverse::parseJsFile(
const QString &code,
const FileToLoad &file,
437 const QDateTime &contentDate)
443 auto jsFile =
std::make_shared<JsFile>(file.canonicalPath(), code, contentDate);
444 std::shared_ptr<DomEnvironment> envPtr;
445 if (
auto ptr = file.environment())
446 envPtr =
std::move(ptr);
448 envPtr =
std::make_shared<DomEnvironment>(QStringList(),
451 envPtr->addJsFile(jsFile);
453 if (!jsFile->isValid()) {
455 DomItem qmlFileObj = env.copy(jsFile);
457 errs += m.toString();
461 qCWarning(domLog).noquote().nospace()
462 <<
"Parsed invalid file " << file.canonicalPath() << errs;
468
469
470
471
473 const QString &path)
const
476 case DomType::QmlFile:
477 return m_qmlFileWithPath.value(path);
478 case DomType::QmltypesFile:
479 return m_qmltypesFileWithPath.value(path);
480 case DomType::QmldirFile:
481 return m_qmldirFileWithPath.value(path);
482 case DomType::QmlDirectory:
483 return m_qmlDirectoryWithPath.value(path);
484 case DomType::JsFile:
485 return m_jsFileWithPath.value(path);
493 const QString &canonicalPath)
const
495 QFileInfo fInfo(canonicalPath);
496 bool valueItemIsMostRecent =
false;
501 QMutexLocker l(mutex());
502 value = getPathValueOrNull(fType, canonicalPath);
503 valueItemIsMostRecent = valueHasMostRecentItem(value.get(), fInfo.lastModified());
505 if (valueItemIsMostRecent) {
506 return univ.copy(value);
512 const QString &canonicalPath,
513 const ContentWithDate &codeWithDate)
const
516 bool valueItemHasSameCode =
false;
520 QMutexLocker l(mutex());
521 value = getPathValueOrNull(fType, canonicalPath);
522 if (valueHasSameContent(value.get(), codeWithDate.content)) {
523 valueItemHasSameCode =
true;
524 if (value->currentItem()->lastDataUpdateAt() < codeWithDate.date)
525 value->currentItem()->refreshedDataAt(codeWithDate.date);
528 if (valueItemHasSameCode) {
529 return univ.copy(value);
535
536
537
538
540 const QDateTime &lastModified)
545 return lastModified < value->currentItem()->lastDataUpdateAt();
549
550
551
552
558 QString curContent = value->currentItem()->code();
559 return !curContent.isNull() && curContent == content;
564 auto res =
std::make_shared<LoadInfo>(*
this);
567 u"This is a copy of a LoadInfo still in progress, artificially ending it, if you "
568 u"use this you will *not* resume loading"_sv));
570 .warning([&self](
const Sink &sink) {
571 sink(u"Copying an in progress LoadInfo, which is most likely an error (");
576 QMutexLocker l(res->mutex());
579 res->m_inProgress.clear();
580 res->m_endCallbacks.clear();
592 bool cont = OwningItem::iterateDirectSubpaths(self, visitor);
593 cont = cont && self.invokeVisitorOnValue(visitor,
PathEls::Field(Fields::status),
int(
status()));
594 cont = cont && self.invokeVisitorOnValue(visitor,
PathEls::Field(Fields::nLoaded),
nLoaded());
595 cont = cont && self.invokeVisitorOnValue(visitor,
PathEls::Field(Fields::elementCanonicalPath),
597 cont = cont && self.invokeVisitorOnValue(visitor,
PathEls::Field(Fields::nNotdone),
nNotDone());
598 cont = cont && self.invokeVisitorOnValue(visitor,
PathEls::Field(Fields::nCallbacks),
nCallbacks());
608 QMutexLocker l(mutex());
610 case Status::NotStarted:
611 case Status::Starting:
612 case Status::InProgress:
613 case Status::CallingCallbacks:
614 m_endCallbacks.append(callback);
629 bool depValid =
false;
631 QMutexLocker l(mutex());
639 if (!m_toDo.isEmpty()) {
640 dep = m_toDo.dequeue();
641 m_inProgress.append(dep);
651 case Status::NotStarted:
652 refreshedDataAt(QDateTime::currentDateTimeUtc());
653 doAddDependencies(self);
654 refreshedDataAt(QDateTime::currentDateTimeUtc());
656 QMutexLocker l(mutex());
658 if (m_toDo.isEmpty() && m_inProgress.isEmpty())
669 refreshedDataAt(QDateTime::currentDateTimeUtc());
671 Q_ASSERT(envPtr &&
"missing environment");
672 if (!dep.uri.isEmpty()) {
673 envPtr->loadModuleDependency(
674 dep.uri, dep.version,
681 Q_ASSERT(dep.filePath.isEmpty() &&
"dependency with both uri and file");
682 }
else if (!dep.filePath.isEmpty()) {
684 FileToLoad::fromFileSystem(envPtr, dep.filePath),
692 Q_ASSERT(
false &&
"dependency without uri and filePath");
696 tr(
"advanceLoad called but found no work, which should never happen")
));
702 "advanceLoad called after work should have been done, which should never happen")
));
709 bool didRemove =
false;
710 bool unexpectedState =
false;
713 QMutexLocker l(mutex());
714 didRemove = m_inProgress.removeOne(d);
719 unexpectedState =
true;
724 if (m_toDo.isEmpty() && m_inProgress.isEmpty()) {
733 sink(u"LoadInfo::finishedLoadingDep did not find its dependency in those inProgress "
739 &&
"LoadInfo::finishedLoadingDep did not find its dependency in those inProgress");
741 if (unexpectedState) {
743 sink(u"LoadInfo::finishedLoadingDep found an unexpected state (");
747 Q_ASSERT(
false &&
"LoadInfo::finishedLoadingDep did find an unexpected state");
755 QList<std::function<
void(Path,
const DomItem &,
const DomItem &)>> endCallbacks;
756 bool unexpectedState =
false;
758 QMutexLocker l(mutex());
760 endCallbacks = m_endCallbacks;
761 m_endCallbacks.clear();
763 Q_ASSERT(!unexpectedState &&
"LoadInfo::execEnd found an unexpected state");
767 auto cleanup = qScopeGuard([
this, p, &el] {
768 QList<std::function<
void(Path,
const DomItem &,
const DomItem &)>> otherCallbacks;
769 bool unexpectedState2 =
false;
771 QMutexLocker l(mutex());
774 otherCallbacks = m_endCallbacks;
775 m_endCallbacks.clear();
777 Q_ASSERT(!unexpectedState2 &&
"LoadInfo::execEnd found an unexpected state");
778 for (
auto const &cb : otherCallbacks) {
783 for (
auto const &cb : endCallbacks) {
790void LoadInfo::doAddDependencies(
const DomItem &self)
802 DomItem currentFile = el.field(Fields::currentItem);
803 QString currentFilePath = currentFile.canonicalFilePath();
806 DomItem currentQmltypesFiles = currentFile.field(Fields::qmltypesFiles);
807 int qEnd = currentQmltypesFiles.indexes();
808 for (
int i = 0; i < qEnd; ++i) {
809 DomItem qmltypesRef = currentQmltypesFiles.index(i);
811 Path canonicalPath = ref->referredObjectPath[2];
812 if (canonicalPath && !canonicalPath.headName().isEmpty())
819 DomItem currentQmlFiles = currentFile.field(Fields::qmlFiles);
820 currentQmlFiles.visitKeys([
this, &self](
const QString &,
const DomItem &els) {
821 return els.visitIndexes([
this, &self](
const DomItem &el) {
822 if (
const Reference *ref = el.as<Reference>()) {
823 Path canonicalPath = ref->referredObjectPath[2];
824 if (canonicalPath && !canonicalPath.headName().isEmpty())
826 Dependency{ QString(), Version(),
827 canonicalPath.headName(), DomType::QmlFile });
833 }
else if (shared_ptr<ModuleIndex> elPtr = el.ownerAs<ModuleIndex>()) {
834 const auto qmldirs = elPtr->qmldirsToLoad(el);
835 for (
const Path &qmldirPath : qmldirs) {
836 Path canonicalPath = qmldirPath[2];
837 if (canonicalPath && !canonicalPath.headName().isEmpty())
839 Dependency { QString(), Version(), canonicalPath.headName(),
840 DomType::QmldirFile });
842 QString uri = elPtr->uri();
844 for (
const Path &p : qmldirs) {
845 DomItem qmldir = newV.path(p);
846 if (std::shared_ptr<QmldirFile> qmldirFilePtr = qmldir.ownerAs<QmldirFile>()) {
847 qmldirFilePtr->ensureInModuleIndex(qmldir, uri);
853 tr(
"Ignoring dependencies for empty (invalid) type %1")
854 .arg(domTypeToString(el.internalKind()))
));
858 .arg(domTypeToString(el.internalKind()),
865 bool unexpectedState =
false;
867 QMutexLocker l(mutex());
871 Q_ASSERT(!unexpectedState &&
"LoadInfo::addDependency found an unexpected state");
877
878
879
880
881
882
883
884
905 cont = cont && DomTop::iterateDirectSubpaths(self, visitor);
907 cont = cont && visitor(
PathEls::Field(Fields::universe), [
this]() {
return universe(); });
908 cont = cont && self.invokeVisitorOnValue(visitor,
PathEls::Field(Fields::options),
int(options()));
909 cont = cont && visitor(
PathEls::Field(Fields::base), [
this]() {
return base(); });
910 cont = cont && self.invokeVisitorOnLazyField(visitor, Fields::loadPaths, [
this]() {
913 cont = cont && self.invokeVisitorOnValue(visitor,
PathEls::Field(Fields::globalScopeName),
915 cont = cont && visitor(
PathEls::Field(Fields::globalScopeWithName), [
this, &self]() {
916 return self.subMapItem(Map(
917 Path::fromField(Fields::globalScopeWithName),
918 [&self,
this](
const DomItem &map,
const QString &key) {
919 return map.copy(globalScopeWithName(self, key));
921 [&self,
this](
const DomItem &) {
return globalScopeNames(self); },
922 QLatin1String(
"GlobalScope")));
924 cont = cont && visitor(
PathEls::Field(Fields::qmlDirectoryWithPath), [
this, &self]() {
925 return self.subMapItem(Map(
926 Path::fromField(Fields::qmlDirectoryWithPath),
927 [&self,
this](
const DomItem &map,
const QString &key) {
928 return map.copy(qmlDirectoryWithPath(self, key));
930 [&self,
this](
const DomItem &) {
return qmlDirectoryPaths(self); },
931 QLatin1String(
"QmlDirectory")));
933 cont = cont && visitor(
PathEls::Field(Fields::qmldirFileWithPath), [
this, &self]() {
934 return self.subMapItem(Map(
935 Path::fromField(Fields::qmldirFileWithPath),
936 [&self,
this](
const DomItem &map,
const QString &key) {
937 return map.copy(qmldirFileWithPath(self, key));
939 [&self,
this](
const DomItem &) {
return qmldirFilePaths(self); },
940 QLatin1String(
"QmldirFile")));
942 cont = cont && visitor(
PathEls::Field(Fields::qmldirWithPath), [
this, &self]() {
943 return self.subMapItem(Map(
944 Path::fromField(Fields::qmldirWithPath),
945 [&self,
this](
const DomItem &map,
const QString &key) {
946 return map.copy(qmlDirWithPath(self, key));
948 [&self,
this](
const DomItem &) {
return qmlDirPaths(self); },
949 QLatin1String(
"Qmldir")));
951 cont = cont && visitor(
PathEls::Field(Fields::qmlFileWithPath), [
this, &self]() {
952 return self.subMapItem(Map(
953 Path::fromField(Fields::qmlFileWithPath),
954 [&self,
this](
const DomItem &map,
const QString &key) {
955 return map.copy(qmlFileWithPath(self, key));
957 [&self,
this](
const DomItem &) {
return qmlFilePaths(self); },
958 QLatin1String(
"QmlFile")));
960 cont = cont && visitor(
PathEls::Field(Fields::jsFileWithPath), [
this, &self]() {
961 return self.subMapItem(Map(
962 Path::fromField(Fields::jsFileWithPath),
963 [
this](
const DomItem &map,
const QString &key) {
964 DomItem mapOw(map.owner());
965 return map.copy(jsFileWithPath(mapOw, key));
967 [
this](
const DomItem &map) {
968 DomItem mapOw = map.owner();
969 return jsFilePaths(mapOw);
971 QLatin1String(
"JsFile")));
973 cont = cont && visitor(
PathEls::Field(Fields::qmltypesFileWithPath), [
this, &self]() {
974 return self.subMapItem(Map(
975 Path::fromField(Fields::qmltypesFileWithPath),
976 [
this](
const DomItem &map,
const QString &key) {
977 DomItem mapOw = map.owner();
978 return map.copy(qmltypesFileWithPath(mapOw, key));
980 [
this](
const DomItem &map) {
981 DomItem mapOw = map.owner();
982 return qmltypesFilePaths(mapOw);
984 QLatin1String(
"QmltypesFile")));
986 cont = cont && visitor(
PathEls::Field(Fields::moduleIndexWithUri), [
this, &self]() {
987 return self.subMapItem(Map(
988 Path::fromField(Fields::moduleIndexWithUri),
989 [
this](
const DomItem &map,
const QString &key) {
990 return map.subMapItem(Map(
991 map.pathFromOwner().withKey(key),
992 [
this, key](
const DomItem &submap,
const QString &subKey) {
994 int i = subKey.toInt(&ok);
996 if (subKey.isEmpty())
997 i = Version::Undefined;
998 else if (subKey.compare(u"Latest",
1001 i = Version::Latest;
1005 DomItem subMapOw = submap.owner();
1006 std::shared_ptr<ModuleIndex> mIndex =
1007 moduleIndexWithUri(subMapOw, key, i);
1008 return submap.copy(mIndex);
1010 [
this, key](
const DomItem &subMap) {
1012 DomItem subMapOw = subMap.owner();
1013 for (
int mVersion : moduleIndexMajorVersions(
1014 subMapOw, key, EnvLookup::Normal))
1015 if (mVersion == Version::Undefined)
1016 res.insert(QString());
1018 res.insert(QString::number(mVersion));
1020 res.insert(QLatin1String(
"Latest"));
1023 QLatin1String(
"ModuleIndex")));
1025 [
this](
const DomItem &map) {
1026 DomItem mapOw = map.owner();
1027 return moduleIndexUris(mapOw);
1029 QLatin1String(
"Map<ModuleIndex>")));
1031 bool loadedLoadInfo =
false;
1032 QQueue<Path> loadsWithWork;
1033 QQueue<Path> inProgress;
1034 int nAllLoadedCallbacks;
1035 auto ensureInfo = [&]() {
1036 if (!loadedLoadInfo) {
1037 QMutexLocker l(mutex());
1038 loadedLoadInfo =
true;
1039 loadsWithWork = m_loadsWithWork;
1040 inProgress = m_inProgress;
1041 nAllLoadedCallbacks = m_allLoadedCallback.size();
1044 cont = cont && visitor(
1045 PathEls::Field(Fields::loadsWithWork), [&ensureInfo, &self, &loadsWithWork]() {
1047 return self.subListItem(List(
1048 Path::fromField(Fields::loadsWithWork),
1049 [loadsWithWork](
const DomItem &list, index_type i) {
1050 if (i >= 0 && i < loadsWithWork.size())
1051 return list.subDataItem(PathEls::Index(i),
1052 loadsWithWork.at(i).toString());
1056 [loadsWithWork](
const DomItem &) {
1057 return index_type(loadsWithWork.size());
1059 nullptr, QLatin1String(
"Path")));
1061 cont = cont && visitor(
PathEls::Field(Fields::inProgress), [&self, &ensureInfo, &inProgress]() {
1063 return self.subListItem(List(
1064 Path::fromField(Fields::inProgress),
1065 [inProgress](
const DomItem &list, index_type i) {
1066 if (i >= 0 && i < inProgress.size())
1067 return list.subDataItem(PathEls::Index(i),
1068 inProgress.at(i).toString());
1072 [inProgress](
const DomItem &) {
return index_type(inProgress.size()); },
1073 nullptr, QLatin1String(
"Path")));
1075 cont = cont && visitor(
PathEls::Field(Fields::loadInfo), [&self,
this]() {
1076 return self.subMapItem(Map(
1077 Path::fromField(Fields::loadInfo),
1078 [
this](
const DomItem &map,
const QString &pStr) {
1079 bool hasErrors =
false;
1080 Path p = Path::fromString(pStr, [&hasErrors](
const ErrorMessage &m) {
1082 case ErrorLevel::Debug:
1083 case ErrorLevel::Info:
1085 case ErrorLevel::Warning:
1086 case ErrorLevel::Error:
1087 case ErrorLevel::Fatal:
1093 return map.copy(loadInfo(p));
1096 [
this](
const DomItem &) {
1098 const auto infoPaths = loadInfoPaths();
1099 for (
const Path &p : infoPaths)
1100 res.insert(p.toString());
1103 QLatin1String(
"LoadInfo")));
1105 cont = cont && self.invokeVisitorOnField(visitor, Fields::imports, m_implicitImports);
1106 cont = cont && self.invokeVisitorOnLazyField(visitor, Fields::nAllLoadedCallbacks,
1107 [&nAllLoadedCallbacks, &ensureInfo]() {
1109 return nAllLoadedCallbacks;
1116 return DomTop::field(self, name);
1121 return std::static_pointer_cast<DomEnvironment>(
doCopy(self));
1126 shared_ptr<DomEnvironment> res;
1128 res =
std::make_shared<DomEnvironment>(m_base, m_loadPaths, m_options, m_domCreationOption);
1130 res =
std::make_shared<DomEnvironment>(m_loadPaths, m_options, m_domCreationOption,
1138 if (options() & DomEnvironment::Option::NoDependencies)
1139 loadFile(file, callback, DomTop::Callback(), fileType, h);
1144 loadFile(file, DomTop::Callback(), callback, fileType, h);
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1161void DomEnvironment::loadFile(
const FileToLoad &_file,
const Callback &loadCallback,
1162 const Callback &endCallback,
std::optional<
DomType> fileType,
1165 DomItem self(shared_from_this());
1167 (
bool(fileType) ? (*fileType) : fileTypeForPath(self, _file.logicalPath()));
1174 file.setCanonicalPath(QQmlJSUtils::qmlSourcePathFromBuildPath(
1175 semanticAnalysis().m_mapper.get(), file.canonicalPath()));
1176 file.setLogicalPath(file.logicalPath());
1180 if (file.canonicalPath().isEmpty()) {
1181 if (!file.content() || file.content()->data.isNull()) {
1184 .error(tr(
"Non existing path to load: '%1'").arg(file.logicalPath())
)
1189 addAllLoadedCallback(self, [endCallback](Path,
const DomItem &,
const DomItem &) {
1190 endCallback(Path(), DomItem::empty, DomItem::empty);
1195 file.canonicalPath() = file.logicalPath();
1202 const auto &fetchResult = fetchFileFromEnvs<QmlDirectory>(file);
1203 oldValue = fetchResult.first;
1204 newValue = fetchResult.second;
1206 const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOption);
1207 addExternalItemInfo<QmlDirectory>(loadRes.currentItem,
1208 getLoadCallbackFor(fType, loadCallback), endCallback);
1213 const auto &fetchResult = fetchFileFromEnvs<QmlFile>(file);
1214 oldValue = fetchResult.first;
1215 newValue = fetchResult.second;
1217 const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOption);
1218 addExternalItemInfo<QmlFile>(loadRes.currentItem,
1219 getLoadCallbackFor(fType, loadCallback), endCallback);
1224 const auto &fetchResult = fetchFileFromEnvs<QmltypesFile>(file);
1225 oldValue = fetchResult.first;
1226 newValue = fetchResult.second;
1228 const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOption);
1229 addExternalItemInfo<QmltypesFile>(loadRes.currentItem,
1230 getLoadCallbackFor(fType, loadCallback), endCallback);
1235 const auto &fetchResult = fetchFileFromEnvs<QmldirFile>(file);
1236 oldValue = fetchResult.first;
1237 newValue = fetchResult.second;
1239 const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOption);
1240 addExternalItemInfo<QmldirFile>(loadRes.currentItem,
1241 getLoadCallbackFor(fType, loadCallback), endCallback);
1246 const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOption);
1247 addExternalItemInfo<JsFile>(loadRes.currentItem, getLoadCallbackFor(fType, loadCallback),
1252 myErrors().error(tr(
"Unexpected file to load: '%1'").arg(file.canonicalPath())
).handle(h);
1260 Path p = self.copy(newValue).canonicalPath();
1261 std::shared_ptr<LoadInfo> lInfo = loadInfo(p);
1264 DomItem oldValueObj = self.copy(oldValue);
1265 DomItem newValueObj = self.copy(newValue);
1266 loadCallback(p, oldValueObj, newValueObj);
1274 addAllLoadedCallback(self, [p = std::move(p), endCallback](
1275 const Path &,
const DomItem &,
const DomItem &env) {
1276 DomItem el = env.path(p);
1277 endCallback(p, el, el);
1281void DomEnvironment::loadModuleDependency(
1282 const QString &uri,
Version version,
1286 DomItem envItem(shared_from_this());
1287 if (options() & DomEnvironment::Option::NoDependencies)
1288 loadModuleDependency(envItem, uri, version, callback,
nullptr, errorHandler);
1290 loadModuleDependency(envItem, uri, version,
nullptr, callback, errorHandler);
1293void DomEnvironment::loadModuleDependency(
1294 const DomItem &self,
const QString &uri,
Version v,
const Callback &loadCallback,
1295 const Callback &endCallback,
const ErrorHandler &errorHandler)
1297 Q_ASSERT(!uri.contains(u'/'));
1298 Path p = Paths::moduleIndexPath(uri, v.majorVersion);
1299 if (v.majorVersion == Version::Latest) {
1301 QStringList subPathComponents = uri.split(QLatin1Char(
'.'));
1303 bool commonV =
false;
1304 QString lastComponent = subPathComponents.last();
1305 subPathComponents.removeLast();
1306 QString subPathV = subPathComponents.join(u'/');
1307 QRegularExpression vRe(QRegularExpression::anchoredPattern(
1308 QRegularExpression::escape(lastComponent) + QStringLiteral(u"\\.([0-9]*)")));
1309 const auto lPaths = loadPaths();
1310 qCDebug(QQmlJSDomImporting) <<
"DomEnvironment::loadModuleDependency: Searching module with"
1313 for (
const QString &path : lPaths) {
1314 QDir dir(path + (subPathV.isEmpty() ? QStringLiteral(u"") : QStringLiteral(u"/"))
1316 const auto eList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
1317 for (
const QString &dirNow : eList) {
1318 auto m = vRe.match(dirNow);
1320 int majorV = m.captured(1).toInt();
1321 if (majorV > maxV) {
1322 QFileInfo fInfo(dir.canonicalPath() + QChar(u'/') + dirNow
1323 + QStringLiteral(u"/qmldir"));
1324 if (fInfo.isFile()) {
1325 qCDebug(QQmlJSDomImporting)
1326 <<
"Found qmldir in " << fInfo.canonicalFilePath();
1331 if (!commonV && dirNow == lastComponent) {
1332 QFileInfo fInfo(dir.canonicalPath() + QChar(u'/') + dirNow
1333 + QStringLiteral(u"/qmldir"));
1334 if (fInfo.isFile()) {
1335 qCDebug(QQmlJSDomImporting)
1336 <<
"Found qmldir in " << fInfo.canonicalFilePath();
1347 int toLoad = (commonV ? 1 : 0) + ((maxV >= 0) ? 1 : 0);
1348 const auto &loadCallback2 = loadCallback
1350 if (--toLoad == 0) {
1352 loadCallback(p, el, el);
1358 loadModuleDependency(self, uri, Version(maxV, v.minorVersion), loadCallback2,
nullptr);
1360 loadModuleDependency(self, uri, Version(Version::Undefined, v.minorVersion),
1361 loadCallback2,
nullptr);
1362 else if (maxV < 0) {
1363 if (uri != u"QML") {
1364 const QString loadPaths = lPaths.join(u", "_s);
1365 qCDebug(QQmlJSDomImporting)
1366 <<
"DomEnvironment::loadModuleDependency: qmldir at" << (uri + u"/qmldir"_s)
1367 <<
"was not found in " << loadPaths;
1370 .warning(tr(
"Failed to find main qmldir file for %1 %2 in %3.")
1371 .arg(uri, v.stringValue(), loadPaths)
)
1378 std::shared_ptr<ModuleIndex> mIndex = moduleIndexWithUri(
1379 self, uri, v.majorVersion, EnvLookup::Normal, Changeable::Writable, errorHandler);
1380 std::shared_ptr<LoadInfo> lInfo = loadInfo(p);
1382 DomItem lInfoObj = self.copy(lInfo);
1383 lInfo->addEndCallback(lInfoObj, loadCallback);
1392 addAllLoadedCallback(self, [p = std::move(p), endCallback = std::move(endCallback)](
1393 Path,
const DomItem &,
const DomItem &env) {
1394 DomItem el = env.path(p);
1395 endCallback(p, el, el);
1402 QString builtinsName = QLatin1String(
"QML/plugins.qmltypes");
1403 const auto lPaths = loadPaths();
1404 for (
const QString &path : lPaths) {
1406 QFileInfo fInfo(dir.filePath(builtinsName));
1407 if (fInfo.isFile()) {
1408 loadFile(FileToLoad::fromFileSystem(shared_from_this(), fInfo.canonicalFilePath()),
1418 QMutexLocker l(mutex());
1419 auto toDelete = [path](
auto it) {
1420 QString p = it.key();
1421 return p.startsWith(path) && (p.size() == path.size() || p.at(path.size()) == u'/');
1423 m_qmlDirectoryWithPath.removeIf(toDelete);
1424 m_qmldirFileWithPath.removeIf(toDelete);
1425 m_qmlFileWithPath.removeIf(toDelete);
1426 m_jsFileWithPath.removeIf(toDelete);
1427 m_qmltypesFileWithPath.removeIf(toDelete);
1430shared_ptr<DomUniverse> DomEnvironment::
universe()
const {
1434 return m_base->universe();
1466 DomItem baseObj = DomItem(m_base);
1467 return this->getStrings<QMap<
int, std::shared_ptr<ModuleIndex>>>(
1468 [
this, &baseObj] {
return m_base->moduleIndexUris(baseObj, EnvLookup::Normal); },
1469 m_moduleIndexWithUri, lookup);
1475 if (lookup != EnvLookup::NoBase && m_base) {
1477 res = m_base->moduleIndexMajorVersions(baseObj, uri, EnvLookup::Normal);
1480 QMap<
int, std::shared_ptr<ModuleIndex>> map;
1482 QMutexLocker l(mutex());
1483 map = m_moduleIndexWithUri.value(uri);
1485 auto it = map.keyBegin();
1486 auto end = map.keyEnd();
1495std::shared_ptr<ModuleIndex> DomEnvironment::lookupModuleInEnv(
const QString &uri,
int majorVersion)
const
1497 QMutexLocker l(mutex());
1498 auto it = m_moduleIndexWithUri.find(uri);
1499 if (it == m_moduleIndexWithUri.end())
1503 if (majorVersion == Version::Latest)
1506 return it->value(majorVersion);
1509DomEnvironment::ModuleLookupResult DomEnvironment::moduleIndexWithUriHelper(
const DomItem &self,
const QString &uri,
int majorVersion,
EnvLookup options)
const
1511 std::shared_ptr<ModuleIndex> res;
1512 if (options != EnvLookup::BaseOnly)
1513 res = lookupModuleInEnv(uri, majorVersion);
1516 if (options == EnvLookup::NoBase || !m_base)
1517 return {
std::move(res), ModuleLookupResult::FromGlobal };
1518 const std::shared_ptr existingMod =
1519 m_base->moduleIndexWithUri(self, uri, majorVersion, options, Changeable::ReadOnly);
1521 return {
std::move(existingMod), ModuleLookupResult::FromBase };
1523 return {
std::move(res), ModuleLookupResult::FromGlobal };
1529 if (majorVersion == Version::Latest) {
1530 if (res->majorVersion() >= existingMod->majorVersion())
1531 return {
std::move(res), ModuleLookupResult::FromGlobal };
1533 return {
std::move(existingMod), ModuleLookupResult::FromBase };
1537 return {
std::move(res), ModuleLookupResult::FromGlobal };
1542 const DomItem &self,
const QString &uri,
int majorVersion,
EnvLookup options,
1547 || (majorVersion >= 0 || majorVersion == Version::Undefined))
1548 &&
"A writeable moduleIndexWithUri call should have a version (not with "
1549 "Version::Latest)");
1550 if (changeable == Changeable::Writable && (m_options & Option::Exported))
1551 myErrors().error(tr(
"A mutable module was requested in a multithreaded environment")
).handle(errorHandler);
1555 auto candidate = moduleIndexWithUriHelper(self, uri, majorVersion, options);
1558 if (candidate.module && candidate.fromBase == ModuleLookupResult::FromGlobal)
1559 return std::move(candidate.module);
1563 return std::move(candidate.module);
1566 std::shared_ptr<ModuleIndex> newModulePtr = [&] {
1568 if (!candidate.module)
1569 return std::make_shared<ModuleIndex>(uri, majorVersion);
1571 DomItem existingModObj = self.copy(candidate.module);
1572 return candidate.module->makeCopy(existingModObj);
1575 DomItem newModule = self.copy(newModulePtr);
1578 QMutexLocker l(mutex());
1579 auto &modsNow = m_moduleIndexWithUri[uri];
1582 if (
auto it = modsNow.constFind(majorVersion); it != modsNow.cend())
1584 modsNow.insert(majorVersion, newModulePtr);
1587 auto lInfo =
std::make_shared<LoadInfo>(p);
1591 .error(tr(
"Could not get path for newly created ModuleIndex %1 %2")
1594 .handle(errorHandler);
1597 return newModulePtr;
1604 return moduleIndexWithUriHelper(self, uri, majorVersion, options).module;
1607std::shared_ptr<ExternalItemInfo<QmlDirectory>>
1610 return lookup<QmlDirectory>(path, options);
1615 return getStrings<std::shared_ptr<ExternalItemInfo<QmlDirectory>>>(
1617 DomItem baseObj(m_base);
1618 return m_base->qmlDirectoryPaths(baseObj, EnvLookup::Normal);
1620 m_qmlDirectoryWithPath, options);
1623std::shared_ptr<ExternalItemInfo<QmldirFile>>
1626 return lookup<QmldirFile>(path, options);
1631 return getStrings<std::shared_ptr<ExternalItemInfo<QmldirFile>>>(
1633 DomItem baseObj(m_base);
1634 return m_base->qmldirFilePaths(baseObj, EnvLookup::Normal);
1636 m_qmldirFileWithPath, lOptions);
1642 if (
auto qmldirFile = qmldirFileWithPath(self, path + QLatin1String(
"/qmldir"), options))
1644 return qmlDirectoryWithPath(self, path, options);
1649 QSet<QString> res = qmlDirectoryPaths(self, options);
1650 const auto qmldirFiles = qmldirFilePaths(self, options);
1651 for (
const QString &p : qmldirFiles) {
1652 if (p.endsWith(u"/qmldir")) {
1653 res.insert(p.left(p.size() - 7));
1656 .warning(tr(
"Unexpected path not ending with qmldir in qmldirFilePaths: %1")
1664std::shared_ptr<ExternalItemInfo<QmlFile>>
1667 return lookup<QmlFile>(path, options);
1672 return getStrings<std::shared_ptr<ExternalItemInfo<QmlFile>>>(
1674 DomItem baseObj(m_base);
1675 return m_base->qmlFilePaths(baseObj, EnvLookup::Normal);
1677 m_qmlFileWithPath, lookup);
1680std::shared_ptr<ExternalItemInfo<JsFile>>
1683 return lookup<JsFile>(path, options);
1688 return getStrings<std::shared_ptr<ExternalItemInfo<JsFile>>>(
1690 DomItem baseObj(m_base);
1691 return m_base->jsFilePaths(baseObj, EnvLookup::Normal);
1693 m_jsFileWithPath, lookup);
1696std::shared_ptr<ExternalItemInfo<QmltypesFile>>
1699 return lookup<QmltypesFile>(path, options);
1704 return getStrings<std::shared_ptr<ExternalItemInfo<QmltypesFile>>>(
1706 DomItem baseObj(m_base);
1707 return m_base->qmltypesFilePaths(baseObj, EnvLookup::Normal);
1709 m_qmltypesFileWithPath, lookup);
1712std::shared_ptr<ExternalItemInfo<GlobalScope>>
1716 return lookup<GlobalScope>(name, lookupOptions);
1719std::shared_ptr<ExternalItemInfo<GlobalScope>>
1722 if (
auto current = globalScopeWithName(self, name, lookupOptions))
1724 if (
auto u = universe()) {
1725 if (
auto newVal = u->ensureGlobalScopeWithName(name)) {
1726 if (
auto current = newVal->current) {
1728 auto newScope = current->makeCopy(currentObj);
1729 auto newCopy =
std::make_shared<ExternalItemInfo<GlobalScope>>(
1731 QMutexLocker l(mutex());
1732 if (
auto oldVal = m_globalScopeWithName.value(name))
1734 m_globalScopeWithName.insert(name, newCopy);
1739 Q_ASSERT_X(
false,
"DomEnvironment::ensureGlobalScopeWithName",
"could not ensure globalScope");
1746 if (lookupOptions != EnvLookup::NoBase && m_base) {
1749 res = m_base->globalScopeNames(baseObj, EnvLookup::Normal);
1753 QMap<QString, std::shared_ptr<ExternalItemInfo<GlobalScope>>> map;
1755 QMutexLocker l(mutex());
1756 map = m_globalScopeWithName;
1758 auto it = map.keyBegin();
1759 auto end = map.keyEnd();
1769
1770
1771
1774 if (options() & Option::NoDependencies) {
1778 const auto loadInfo =
std::make_shared<LoadInfo>(path);
1783
1784
1785
1786
1791 Path p = loadInfo->elementCanonicalPath();
1792 bool addWork = loadInfo->status() != LoadInfo::Status::Done;
1793 std::shared_ptr<LoadInfo> oldVal;
1795 QMutexLocker l(mutex());
1796 oldVal = m_loadInfos.value(p);
1797 m_loadInfos.insert(p, loadInfo);
1799 m_loadsWithWork.enqueue(p);
1803 .error(tr(
"addLoadinfo replaces unfinished load info for %1")
1811 QMutexLocker l(mutex());
1812 return m_loadInfos.value(path);
1817 QMutexLocker l(mutex());
1823 auto lInfos = loadInfos();
1824 return lInfos.keys();
1831 DomItem newFile = newV.field(Fields::currentItem);
1832 if (std::shared_ptr<QmltypesFile> newFilePtr = newFile.ownerAs<QmltypesFile>())
1833 newFilePtr->ensureInModuleIndex(newFile);
1835 loadCallback(p, oldV, newV);
1838 return loadCallback;
1841DomEnvironment::
DomEnvironment(
const QStringList &loadPaths, Options options,
1843 const shared_ptr<DomUniverse> &universe)
1848 m_domCreationOption(domCreationOption)
1854
1855
1856
1857
1860 QMutexLocker l(mutex());
1861 return semanticAnalysisUnlocked();
1864DomEnvironment::SemanticAnalysis DomEnvironment::semanticAnalysisUnlocked()
1869 auto result = m_base->semanticAnalysis();
1870 result.updateLoadPaths(m_loadPaths);
1874 if (m_semanticAnalysis)
1875 return *m_semanticAnalysis;
1878 m_semanticAnalysis = SemanticAnalysis(m_loadPaths);
1879 return *m_semanticAnalysis;
1882DomEnvironment::SemanticAnalysis::SemanticAnalysis(
const QStringList &loadPaths)
1883 : m_mapper(std::make_shared<QQmlJSResourceFileMapper>(
1884 QQmlJSUtils::resourceFilesFromBuildFolders(loadPaths))),
1885 m_importer(std::make_shared<QQmlJSImporter>(loadPaths, m_mapper.get(),
1886 QQmlJSImporterFlags{} | UseOptionalImports
1887 | TolerateFileSelectors
1888 | PreferQmlFilesFromSourceFolder))
1893
1894
1895
1896
1897
1898
1899
1900void DomEnvironment::SemanticAnalysis::updateLoadPaths(
const QStringList &loadPaths)
1902 if (loadPaths == m_importer->importPaths())
1905 m_importer->setImportPaths(loadPaths);
1908void DomEnvironment::SemanticAnalysis::setResourceFiles(
const QStringList &qrcFiles)
1910 *m_mapper = QQmlJSResourceFileMapper(qrcFiles);
1913std::shared_ptr<DomEnvironment> DomEnvironment::create(
const QStringList &loadPaths,
1918 std::shared_ptr<DomUniverse> universePtr = universe.ownerAs<DomUniverse>();
1919 return std::make_shared<DomEnvironment>(loadPaths, options, domCreationOption, universePtr);
1922DomEnvironment::
DomEnvironment(
const shared_ptr<DomEnvironment> &parent,
1923 const QStringList &loadPaths, Options options,
1929 m_domCreationOption(domCreationOption)
1935 addExternalItem(file, file->canonicalFilePath(), options);
1937 QQmlJSScope::Ptr handle =
1941 QDeferredFactory<QQmlJSScope> newFactory(semanticAnalysis().m_importer.get(),
1942 file->canonicalFilePath(),
1943 TypeReader{ weak_from_this(), m_loadPaths });
1944 file->setHandleForPopulation(handle);
1945 handle.resetFactory(
std::move(newFactory));
1951 addExternalItem(file, file->canonicalFilePath(), options);
1956 addExternalItem(file, file->canonicalFilePath(), options);
1961 addExternalItem(file, file->canonicalFilePath(), options);
1966 addExternalItem(file, file->canonicalFilePath(), options);
1971 addExternalItem(scope, scope->name(), options);
1974QList<QQmlJS::DiagnosticMessage>
1975DomEnvironment::TypeReader::operator()(QQmlJSImporter *importer,
const QString &filePath,
1976 const QSharedPointer<QQmlJSScope> &scopeToPopulate)
1979 Q_UNUSED(scopeToPopulate);
1981 const QFileInfo info{ filePath };
1982 const QString baseName = info.baseName();
1983 scopeToPopulate->setInternalName(baseName.endsWith(QStringLiteral(
".ui")) ? baseName.chopped(3)
1986 std::shared_ptr<DomEnvironment> envPtr = m_env.lock();
1989 auto it = envPtr->m_qmlFileWithPath.constFind(filePath);
1990 if (it == envPtr->m_qmlFileWithPath.constEnd()) {
1991 qCDebug(domLog) <<
"Import visitor tried to lazily load file \"" << filePath
1992 <<
"\", but that file was not found in the DomEnvironment. Was this "
1993 "file not discovered by the Dom's dependency loading mechanism?";
1994 return { QQmlJS::DiagnosticMessage{
1995 u"Could not find file \"%1\" in the Dom."_s.arg(filePath), QtMsgType::QtWarningMsg,
1996 SourceLocation{} } };
1998 const DomItem qmlFile = it.value()->currentItem(
DomItem(envPtr));
2002 const QStringList oldImportPaths = envPtr->loadPaths();
2003 envPtr->setLoadPaths(m_importPaths);
2005 envPtr->setLoadPaths(oldImportPaths);
2011 const DomItem &self,
const shared_ptr<DomEnvironment> &validEnvPtr)
2015 QMap<QString, QMap<
int, std::shared_ptr<ModuleIndex>>> my_moduleIndexWithUri;
2016 QMap<QString, std::shared_ptr<ExternalItemInfo<GlobalScope>>> my_globalScopeWithName;
2017 QMap<QString, std::shared_ptr<ExternalItemInfo<QmlDirectory>>> my_qmlDirectoryWithPath;
2018 QMap<QString, std::shared_ptr<ExternalItemInfo<QmldirFile>>> my_qmldirFileWithPath;
2019 QMap<QString, std::shared_ptr<ExternalItemInfo<QmlFile>>> my_qmlFileWithPath;
2020 QMap<QString, std::shared_ptr<ExternalItemInfo<JsFile>>> my_jsFileWithPath;
2021 QMap<QString, std::shared_ptr<ExternalItemInfo<QmltypesFile>>> my_qmltypesFileWithPath;
2022 QHash<Path, std::shared_ptr<LoadInfo>> my_loadInfos;
2023 std::optional<SemanticAnalysis> my_semanticAnalysis;
2025 QMutexLocker l(mutex());
2026 my_moduleIndexWithUri = m_moduleIndexWithUri;
2027 my_globalScopeWithName = m_globalScopeWithName;
2028 my_qmlDirectoryWithPath = m_qmlDirectoryWithPath;
2029 my_qmldirFileWithPath = m_qmldirFileWithPath;
2030 my_qmlFileWithPath = m_qmlFileWithPath;
2031 my_jsFileWithPath = m_jsFileWithPath;
2032 my_qmltypesFileWithPath = m_qmltypesFileWithPath;
2033 my_loadInfos = m_loadInfos;
2034 my_semanticAnalysis = semanticAnalysisUnlocked();
2037 QMutexLocker lBase(base()->mutex());
2038 m_base->m_semanticAnalysis = my_semanticAnalysis;
2039 m_base->m_globalScopeWithName.insert(my_globalScopeWithName);
2040 m_base->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
2041 m_base->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
2042 m_base->m_qmlFileWithPath.insert(my_qmlFileWithPath);
2043 m_base->m_jsFileWithPath.insert(my_jsFileWithPath);
2044 m_base->m_qmltypesFileWithPath.insert(my_qmltypesFileWithPath);
2045 m_base->m_loadInfos.insert(my_loadInfos);
2047 auto it = my_moduleIndexWithUri.cbegin();
2048 auto end = my_moduleIndexWithUri.cend();
2050 QMap<
int, shared_ptr<ModuleIndex>> &myVersions =
2051 m_base->m_moduleIndexWithUri[it.key()];
2052 auto it2 = it.value().cbegin();
2053 auto end2 = it.value().cend();
2054 while (it2 != end2) {
2055 auto oldV = myVersions.value(it2.key());
2056 DomItem it2Obj = self.copy(it2.value());
2057 auto newV = it2.value()->makeCopy(it2Obj);
2058 newV->mergeWith(oldV);
2059 myVersions.insert(it2.key(), newV);
2067 m_lastValidBase = validEnvPtr;
2068 if (m_lastValidBase) {
2069 QMutexLocker lValid(
2070 m_lastValidBase->mutex());
2071 m_lastValidBase->m_semanticAnalysis = std::move(my_semanticAnalysis);
2072 m_lastValidBase->m_globalScopeWithName.insert(my_globalScopeWithName);
2073 m_lastValidBase->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
2074 m_lastValidBase->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
2075 for (
auto it = my_qmlFileWithPath.cbegin(), end = my_qmlFileWithPath.cend(); it != end;
2077 if (it.value() && it.value()->current && it.value()->current->isValid())
2078 m_lastValidBase->m_qmlFileWithPath.insert(it.key(), it.value());
2080 for (
auto it = my_jsFileWithPath.cbegin(), end = my_jsFileWithPath.cend(); it != end;
2082 if (it.value() && it.value()->current && it.value()->current->isValid())
2083 m_lastValidBase->m_jsFileWithPath.insert(it.key(), it.value());
2085 m_lastValidBase->m_qmltypesFileWithPath.insert(my_qmltypesFileWithPath);
2086 m_lastValidBase->m_loadInfos.insert(my_loadInfos);
2087 for (
auto it = my_moduleIndexWithUri.cbegin(), end = my_moduleIndexWithUri.cend();
2089 QMap<
int, shared_ptr<ModuleIndex>> &myVersions =
2090 m_lastValidBase->m_moduleIndexWithUri[it.key()];
2091 for (
auto it2 = it.value().cbegin(), end2 = it.value().cend(); it2 != end2; ++it2) {
2092 auto oldV = myVersions.value(it2.key());
2093 DomItem it2Obj = self.copy(it2.value());
2094 auto newV = it2.value()->makeCopy(it2Obj);
2095 newV->mergeWith(oldV);
2096 myVersions.insert(it2.key(), newV);
2101 auto newBaseForPopulation =
2102 m_lastValidBase ? m_lastValidBase->weak_from_this() : m_base->weak_from_this();
2105 for (
const auto &qmlFile : my_qmlFileWithPath) {
2106 if (!qmlFile || !qmlFile->current)
2108 QQmlJSScope::ConstPtr handle = qmlFile->current->handleForPopulation();
2111 auto oldFactory = handle.factory();
2115 const QDeferredFactory<QQmlJSScope> newFactory(
2116 oldFactory->importer(), oldFactory->filePath(),
2117 TypeReader{ newBaseForPopulation, m_loadPaths });
2118 handle.resetFactory(newFactory);
2125 DomItem self(shared_from_this());
2128 std::shared_ptr<LoadInfo> loadInfo;
2130 QMutexLocker l(mutex());
2131 if (m_loadsWithWork.isEmpty())
2133 elToDo = m_loadsWithWork.dequeue();
2134 m_inProgress.append(elToDo);
2135 loadInfo = m_loadInfos.value(elToDo);
2138 auto cleanup = qScopeGuard([
this, &elToDo, &self] {
2139 QList<Callback> endCallbacks;
2141 QMutexLocker l(mutex());
2142 m_inProgress.removeOne(elToDo);
2143 if (m_inProgress.isEmpty() && m_loadsWithWork.isEmpty()) {
2144 endCallbacks = m_allLoadedCallback;
2145 m_allLoadedCallback.clear();
2148 for (
const Callback &cb : std::as_const(endCallbacks))
2149 cb(self.canonicalPath(), self, self);
2151 DomItem loadInfoObj = self.copy(loadInfo);
2152 loadInfo->advanceLoad(loadInfoObj);
2155 u"find loadInfo listed in m_loadsWithWork"_sv)
);
2157 QMutexLocker l(mutex());
2158 m_inProgress.removeOne(elToDo);
2161 &&
"DomEnvironment::loadPendingDependencies could not find loadInfo listed in "
2169 bool hasPendingLoads =
true;
2170 QDateTime endTime = QDateTime::currentDateTimeUtc().addMSecs(waitMSec);
2171 for (
int i = 0; i < waitMSec / 10 + 2; ++i) {
2173 auto lInfos = loadInfos();
2174 auto it = lInfos.cbegin();
2175 auto end = lInfos.cend();
2176 hasPendingLoads =
false;
2179 hasPendingLoads =
true;
2181 if (!hasPendingLoads)
2183 auto missing = QDateTime::currentDateTimeUtc().msecsTo(endTime);
2188#if QT_FEATURE_thread
2189 QThread::msleep(missing);
2192 return !hasPendingLoads;
2197 QMutexLocker l(mutex());
2198 m_loadsWithWork.enqueue(elementCanonicalPath);
2206std::shared_ptr<DomEnvironment> DomEnvironment::
base()
const
2213 QMutexLocker l(mutex());
2216 if (m_semanticAnalysis)
2217 m_semanticAnalysis->updateLoadPaths(v);
2222 QMutexLocker l(mutex());
2224 if (m_semanticAnalysis)
2225 m_semanticAnalysis->setResourceFiles(v);
2231 QMutexLocker l(mutex());
2237 QMutexLocker l(mutex());
2238 return m_qmldirFileWithPath.keys();
2243 return m_globalScopeName;
2246QList<Import> DomEnvironment::defaultImplicitImports()
2248 return QList<
Import>({ Import::fromUriString(u"QML"_s, Version(1, 0)),
2249 Import(QmlUri::fromUriString(u"QtQml"_s), Version(6, 0)) });
2254 return m_implicitImports;
2260 bool immediate =
false;
2262 QMutexLocker l(mutex());
2263 if (m_loadsWithWork.isEmpty() && m_inProgress.isEmpty())
2266 m_allLoadedCallback.append(c);
2275 m_referenceCache.clear();
2280 if (std::shared_ptr<QmlFile> qmlFilePtr = qmlFile.ownerAs<QmlFile>()) {
2281 auto logger = std::make_shared<QQmlJSLogger>();
2282 logger->setFilePath(qmlFile.canonicalFilePath());
2283 logger->setCode(qmlFilePtr->code());
2284 logger->setSilent(
true);
2286 auto setupFile = [&qmlFilePtr, &qmlFile,
this](
auto &&visitor) {
2289 AST::Node::accept(qmlFilePtr->ast(), visitor);
2300 auto scope = analysis.m_importer->importFile(qmlFile.canonicalFilePath());
2302 scope, qmlFile, logger.get(), analysis.m_importer.get());
2303 v->enableLoadFileLazily(
true);
2304 v->enableScriptExpressions(
true);
2309 std::make_shared<QQmlJSTypeResolver>(analysis.m_importer.get());
2310 typeResolver->init(&v->scopeCreator(),
nullptr);
2311 qmlFilePtr->setTypeResolverWithDependencies(
2312 typeResolver, { analysis.m_importer, analysis.m_mapper,
std::move(logger) });
2314 auto v =
std::make_unique<QQmlDomAstCreator>(qmlFile);
2321 qCWarning(domLog) <<
"populateQmlFile called on non qmlFile";
2328 shared_ptr<ExternalOwningItem> current = currentItem();
2330 return current->canonicalFilePath(currentObj);
2335 if (!self.invokeVisitorOnLazyField(visitor, Fields::currentRevision,
2338 if (!self.invokeVisitorOnLazyField(visitor, Fields::lastRevision,
2341 if (!self.invokeVisitorOnLazyField(visitor, Fields::lastValidRevision,
2344 if (!visitor(
PathEls::Field(Fields::currentItem),
2347 if (!self.invokeVisitorOnLazyField(visitor, Fields::currentExposedAt,
2348 [
this]() {
return currentExposedAt(); }))
2355 return currentItem()->revision();
2360 Path p = currentItem()->canonicalPath();
2362 return static_cast<
int>(lastValue.value().toInteger(0));
2367 Path p = currentItem()->canonicalPath();
2369 return static_cast<
int>(lastValidValue.value().toInteger(0));
2374 shared_ptr<ExternalOwningItem> current = currentItem();
2375 return current->canonicalFilePath();
2380 shared_ptr<ExternalOwningItem> current = currentItem();
2381 return current->canonicalPath().dropTail();
2386 if (!self.invokeVisitorOnLazyField(visitor, Fields::currentIsValid,
2389 if (!visitor(
PathEls::Field(Fields::validItem), [
this, &self]() {
return validItem(self
); }))
2391 if (!visitor(
PathEls::Field(Fields::currentItem),
2394 if (!self.invokeVisitorOnValue(visitor,
PathEls::Field(Fields::validExposedAt), validExposedAt))
2396 if (!self.invokeVisitorOnValue(visitor,
PathEls::Field(Fields::currentExposedAt),
2397 currentExposedAt)) {
2411 std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>();
2414 QMutexLocker l(envPtr->mutex());
2415 cached = envPtr->m_referenceCache.value(canonicalPath, {});
2417 qCWarning(domLog) <<
"No Env for reference" << canonicalPath <<
"from"
2428 std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>();
2429 bool didSet =
false;
2431 QMutexLocker l(envPtr->mutex());
2432 RefCacheEntry &cached = envPtr->m_referenceCache[canonicalPath];
2433 switch (cached.cached) {
2434 case RefCacheEntry::Cached::None:
2438 case RefCacheEntry::Cached::First:
2439 if (addOption == AddOption::Overwrite || entry.cached == RefCacheEntry::Cached::All) {
2444 case RefCacheEntry::Cached::All:
2445 if (addOption == AddOption::Overwrite || entry.cached == RefCacheEntry::Cached::All) {
2450 if (cached.cached == RefCacheEntry::Cached::First && cached.canonicalPaths.isEmpty())
2451 cached.cached = RefCacheEntry::Cached::All;
2463#include "moc_qqmldomtop_p.cpp"