156 cont = cont && DomTop::iterateDirectSubpaths(self, visitor);
157 cont = cont && self.dvValueField(visitor, Fields::name, name());
158 cont = cont && self.dvItemField(visitor, Fields::globalScopeWithName, [
this, &self]() {
159 return self.subMapItem(Map(
160 Path::fromField(Fields::globalScopeWithName),
161 [
this](
const DomItem &map,
const QString &key) {
return map.copy(globalScopeWithName(key)); },
162 [
this](
const DomItem &) {
return globalScopeNames(); }, QLatin1String(
"GlobalScope")));
164 cont = cont && self.dvItemField(visitor, Fields::qmlDirectoryWithPath, [
this, &self]() {
165 return self.subMapItem(Map(
166 Path::fromField(Fields::qmlDirectoryWithPath),
167 [
this](
const DomItem &map,
const QString &key) {
return map.copy(qmlDirectoryWithPath(key)); },
168 [
this](
const DomItem &) {
return qmlDirectoryPaths(); }, QLatin1String(
"QmlDirectory")));
170 cont = cont && self.dvItemField(visitor, Fields::qmldirFileWithPath, [
this, &self]() {
171 return self.subMapItem(Map(
172 Path::fromField(Fields::qmldirFileWithPath),
173 [
this](
const DomItem &map,
const QString &key) {
return map.copy(qmldirFileWithPath(key)); },
174 [
this](
const DomItem &) {
return qmldirFilePaths(); }, QLatin1String(
"QmldirFile")));
176 cont = cont && self.dvItemField(visitor, Fields::qmlFileWithPath, [
this, &self]() {
177 return self.subMapItem(Map(
178 Path::fromField(Fields::qmlFileWithPath),
179 [
this](
const DomItem &map,
const QString &key) {
return map.copy(qmlFileWithPath(key)); },
180 [
this](
const DomItem &) {
return qmlFilePaths(); }, QLatin1String(
"QmlFile")));
182 cont = cont && self.dvItemField(visitor, Fields::jsFileWithPath, [
this, &self]() {
183 return self.subMapItem(Map(
184 Path::fromField(Fields::jsFileWithPath),
185 [
this](
const DomItem &map,
const QString &key) {
return map.copy(jsFileWithPath(key)); },
186 [
this](
const DomItem &) {
return jsFilePaths(); }, QLatin1String(
"JsFile")));
188 cont = cont && self.dvItemField(visitor, Fields::jsFileWithPath, [
this, &self]() {
189 return self.subMapItem(Map(
190 Path::fromField(Fields::qmltypesFileWithPath),
191 [
this](
const DomItem &map,
const QString &key) {
return map.copy(qmltypesFileWithPath(key)); },
192 [
this](
const DomItem &) {
return qmltypesFilePaths(); }, QLatin1String(
"QmltypesFile")));
199 QRegularExpression r(QRegularExpression::anchoredPattern(QLatin1String(R"(.*Copy([0-9]*)$)")));
200 auto m = r.match(m_name);
203 newName = QStringLiteral(u"%1Copy%2").arg(m_name).arg(m.captured(1).toInt() + 1);
205 newName = m_name + QLatin1String(
"Copy");
206 auto res =
std::make_shared<DomUniverse>(newName);
212 if (canonicalFilePath.endsWith(u".qml", Qt::CaseInsensitive)
213 || canonicalFilePath.endsWith(u".qmlannotation", Qt::CaseInsensitive)) {
215 }
else if (canonicalFilePath.endsWith(u".qmltypes")) {
217 }
else if (QStringView(u"qmldir").compare(QFileInfo(canonicalFilePath).fileName(),
221 }
else if (QFileInfo(canonicalFilePath).isDir()) {
223 }
else if (canonicalFilePath.endsWith(u".js", Qt::CaseInsensitive)
224 || canonicalFilePath.endsWith(u".mjs", Qt::CaseInsensitive)) {
228 self.addError(DomUniverse::myErrors()
229 .error(QCoreApplication::translate(
"Dom::fileTypeForPath",
230 "Could not detect type of file %1")
231 .arg(canonicalFilePath))
240 DomItem univ(shared_from_this());
248 const auto &preLoadResult = preload(univ, file, fileType);
254 return load(
std::get<ContentWithDate>(preLoadResult), file, fileType, creationOption);
258 univ.addError(myErrors()
259 .error(tr(
"Ignoring request to load file %1 of unexpected type %2, "
260 "calling callback immediately")
261 .arg(file.canonicalPath(), domTypeToString(fileType)))
263 Q_ASSERT(
false &&
"loading non supported file type");
268DomUniverse::
LoadResult DomUniverse::load(
const ContentWithDate &codeWithDate,
272 QString canonicalPath = file.canonicalPath();
279 auto qmlFile = parseQmlFile(codeWithDate.content, file, codeWithDate.date, creationOption);
280 return insertOrUpdateExternalItem(
std::move(qmlFile));
282 auto qmltypesFile =
std::make_shared<QmltypesFile>(canonicalPath, codeWithDate.content,
284 QmltypesReader reader(qmltypesFile);
286 return insertOrUpdateExternalItem(
std::move(qmltypesFile));
288 shared_ptr<QmldirFile> qmldirFile =
289 QmldirFile::fromPathAndCode(canonicalPath, codeWithDate.content);
290 return insertOrUpdateExternalItem(
std::move(qmldirFile));
292 auto qmlDirectory =
std::make_shared<QmlDirectory>(
293 canonicalPath, codeWithDate.content.split(QLatin1Char(
'\n')), codeWithDate.date);
294 return insertOrUpdateExternalItem(
std::move(qmlDirectory));
296 auto jsFile = parseJsFile(codeWithDate.content, file, codeWithDate.date);
297 return insertOrUpdateExternalItem(
std::move(jsFile));
301 return {
std::move(oldValue),
std::move(newValue) };
305
306
307
308
309
310
311
312DomUniverse::PreloadResult DomUniverse::preload(
const DomItem &univ,
const FileToLoad &file,
315 QString canonicalPath = file.canonicalPath();
316 ContentWithDate codeWithDate;
318 if (file.content().has_value()) {
319 codeWithDate = { file.content()->data, file.content()->date };
323 const auto &curValueItem = getItemIfMostRecent(univ, fType, canonicalPath);
324 if (curValueItem.has_value()) {
325 return LoadResult{ curValueItem.value(), curValueItem.value() };
328 auto readResult = readFileContent(canonicalPath);
334 codeWithDate =
std::get<ContentWithDate>(readResult);
339 const auto &curValueItem = getItemIfHasSameCode(univ, fType, canonicalPath, codeWithDate);
340 if (curValueItem.has_value()) {
341 return LoadResult{ curValueItem.value(), curValueItem.value() };
349 QMutexLocker l(mutex());
350 const auto toDelete = [path](
const auto &it) {
351 QString p = it.key();
352 return p.startsWith(path) && (p.size() == path.size() || p.at(path.size()) == u'/');
354 m_qmlDirectoryWithPath.removeIf(toDelete);
355 m_qmldirFileWithPath.removeIf(toDelete);
356 m_qmlFileWithPath.removeIf(toDelete);
357 m_jsFileWithPath.removeIf(toDelete);
358 m_qmltypesFileWithPath.removeIf(toDelete);
361DomUniverse::ReadResult DomUniverse::readFileContent(
const QString &canonicalPath)
const
363 if (canonicalPath.isEmpty()) {
366 QFile file(canonicalPath);
367 QFileInfo fileInfo(canonicalPath);
368 if (fileInfo.isDir()) {
369 return ContentWithDate{ QDir(canonicalPath)
370 .entryList(QDir::NoDotAndDotDot | QDir::Files, QDir::Name)
371 .join(QLatin1Char(
'\n')),
372 QDateTime::currentDateTimeUtc() };
374 if (!file.open(QIODevice::ReadOnly)) {
375 return myErrors().error(
376 tr(
"Error opening path %1: %2 %3")
377 .arg(canonicalPath, QString::number(file.error()), file.errorString()));
379 auto content = QString::fromUtf8(file.readAll());
381 return ContentWithDate{ std::move(content), QDateTime::currentDateTimeUtc() };
384std::shared_ptr<QmlFile> DomUniverse::parseQmlFile(
const QString &code,
const FileToLoad &file,
385 const QDateTime &contentDate,
389 std::make_shared<QmlFile>(file.canonicalPath(), code, contentDate, 0,
390 creationOption == Extended ? QmlFile::EnableParserRecovery
391 : QmlFile::DisableParserRecovery);
392 std::shared_ptr<DomEnvironment> envPtr;
393 if (
auto ptr = file.environment().lock())
394 envPtr =
std::move(ptr);
396 envPtr =
std::make_shared<DomEnvironment>(QStringList(),
398 creationOption, shared_from_this());
399 envPtr->addQmlFile(qmlFile);
401 if (qmlFile->isValid()) {
407 DomItem qmlFileObj = env.copy(qmlFile);
409 errs += m.toString();
413 qCWarning(domLog).noquote().nospace()
414 <<
"Parsed invalid file " << file.canonicalPath() << errs;
419std::shared_ptr<JsFile> DomUniverse::parseJsFile(
const QString &code,
const FileToLoad &file,
420 const QDateTime &contentDate)
426 auto jsFile =
std::make_shared<JsFile>(file.canonicalPath(), code, contentDate);
427 std::shared_ptr<DomEnvironment> envPtr;
428 if (
auto ptr = file.environment().lock())
429 envPtr =
std::move(ptr);
431 envPtr =
std::make_shared<DomEnvironment>(QStringList(),
434 envPtr->addJsFile(jsFile);
436 if (!jsFile->isValid()) {
438 DomItem qmlFileObj = env.copy(jsFile);
440 errs += m.toString();
444 qCWarning(domLog).noquote().nospace()
445 <<
"Parsed invalid file " << file.canonicalPath() << errs;
451
452
453
454
456 const QString &path)
const
459 case DomType::QmlFile:
460 return m_qmlFileWithPath.value(path);
461 case DomType::QmltypesFile:
462 return m_qmltypesFileWithPath.value(path);
463 case DomType::QmldirFile:
464 return m_qmldirFileWithPath.value(path);
465 case DomType::QmlDirectory:
466 return m_qmlDirectoryWithPath.value(path);
467 case DomType::JsFile:
468 return m_jsFileWithPath.value(path);
476 const QString &canonicalPath)
const
478 QFileInfo fInfo(canonicalPath);
479 bool valueItemIsMostRecent =
false;
484 QMutexLocker l(mutex());
485 value = getPathValueOrNull(fType, canonicalPath);
486 valueItemIsMostRecent = valueHasMostRecentItem(value.get(), fInfo.lastModified());
488 if (valueItemIsMostRecent) {
489 return univ.copy(value);
495 const QString &canonicalPath,
496 const ContentWithDate &codeWithDate)
const
499 bool valueItemHasSameCode =
false;
503 QMutexLocker l(mutex());
504 value = getPathValueOrNull(fType, canonicalPath);
505 if (valueHasSameContent(value.get(), codeWithDate.content)) {
506 valueItemHasSameCode =
true;
507 if (value->currentItem()->lastDataUpdateAt() < codeWithDate.date)
508 value->currentItem()->refreshedDataAt(codeWithDate.date);
511 if (valueItemHasSameCode) {
512 return univ.copy(value);
518
519
520
521
523 const QDateTime &lastModified)
528 return lastModified < value->currentItem()->lastDataUpdateAt();
532
533
534
535
541 QString curContent = value->currentItem()->code();
542 return !curContent.isNull() && curContent == content;
547 auto res =
std::make_shared<LoadInfo>(*
this);
549 res->addErrorLocal(DomEnvironment::myErrors().warning(
550 u"This is a copy of a LoadInfo still in progress, artificially ending it, if you "
551 u"use this you will *not* resume loading"_sv));
553 .warning([&self](
const Sink &sink) {
554 sink(u"Copying an in progress LoadInfo, which is most likely an error (");
559 QMutexLocker l(res->mutex());
562 res->m_inProgress.clear();
563 res->m_endCallbacks.clear();
575 bool cont = OwningItem::iterateDirectSubpaths(self, visitor);
576 cont = cont && self.dvValueField(visitor, Fields::status,
int(
status()));
577 cont = cont && self.dvValueField(visitor, Fields::nLoaded,
nLoaded());
579 && self.dvValueField(visitor, Fields::elementCanonicalPath,
581 cont = cont && self.dvValueField(visitor, Fields::nNotdone,
nNotDone());
582 cont = cont && self.dvValueField(visitor, Fields::nCallbacks,
nCallbacks());
592 QMutexLocker l(mutex());
594 case Status::NotStarted:
595 case Status::Starting:
596 case Status::InProgress:
597 case Status::CallingCallbacks:
598 m_endCallbacks.append(callback);
613 bool depValid =
false;
615 QMutexLocker l(mutex());
623 if (!m_toDo.isEmpty()) {
624 dep = m_toDo.dequeue();
625 m_inProgress.append(dep);
635 case Status::NotStarted:
636 refreshedDataAt(QDateTime::currentDateTimeUtc());
637 doAddDependencies(self);
638 refreshedDataAt(QDateTime::currentDateTimeUtc());
640 QMutexLocker l(mutex());
642 if (m_toDo.isEmpty() && m_inProgress.isEmpty())
653 refreshedDataAt(QDateTime::currentDateTimeUtc());
655 Q_ASSERT(envPtr &&
"missing environment");
656 if (!dep.uri.isEmpty()) {
657 envPtr->loadModuleDependency(
658 dep.uri, dep.version,
665 Q_ASSERT(dep.filePath.isEmpty() &&
"dependency with both uri and file");
666 }
else if (!dep.filePath.isEmpty()) {
668 FileToLoad::fromFileSystem(envPtr, dep.filePath),
676 Q_ASSERT(
false &&
"dependency without uri and filePath");
680 tr(
"advanceLoad called but found no work, which should never happen")
));
686 "advanceLoad called after work should have been done, which should never happen")
));
693 bool didRemove =
false;
694 bool unexpectedState =
false;
697 QMutexLocker l(mutex());
698 didRemove = m_inProgress.removeOne(d);
703 unexpectedState =
true;
708 if (m_toDo.isEmpty() && m_inProgress.isEmpty()) {
717 sink(u"LoadInfo::finishedLoadingDep did not find its dependency in those inProgress "
723 &&
"LoadInfo::finishedLoadingDep did not find its dependency in those inProgress");
725 if (unexpectedState) {
727 sink(u"LoadInfo::finishedLoadingDep found an unexpected state (");
731 Q_ASSERT(
false &&
"LoadInfo::finishedLoadingDep did find an unexpected state");
739 QList<std::function<
void(Path,
const DomItem &,
const DomItem &)>> endCallbacks;
740 bool unexpectedState =
false;
742 QMutexLocker l(mutex());
744 endCallbacks = m_endCallbacks;
745 m_endCallbacks.clear();
747 Q_ASSERT(!unexpectedState &&
"LoadInfo::execEnd found an unexpected state");
751 auto cleanup = qScopeGuard([
this, p, &el] {
752 QList<std::function<
void(Path,
const DomItem &,
const DomItem &)>> otherCallbacks;
753 bool unexpectedState2 =
false;
755 QMutexLocker l(mutex());
758 otherCallbacks = m_endCallbacks;
759 m_endCallbacks.clear();
761 Q_ASSERT(!unexpectedState2 &&
"LoadInfo::execEnd found an unexpected state");
762 for (
auto const &cb : otherCallbacks) {
767 for (
auto const &cb : endCallbacks) {
774void LoadInfo::doAddDependencies(
const DomItem &self)
786 DomItem currentFile = el.field(Fields::currentItem);
787 QString currentFilePath = currentFile.canonicalFilePath();
790 DomItem currentQmltypesFiles = currentFile.field(Fields::qmltypesFiles);
791 int qEnd = currentQmltypesFiles.indexes();
792 for (
int i = 0; i < qEnd; ++i) {
793 DomItem qmltypesRef = currentQmltypesFiles.index(i);
795 Path canonicalPath = ref->referredObjectPath[2];
796 if (canonicalPath && !canonicalPath.headName().isEmpty())
803 DomItem currentQmlFiles = currentFile.field(Fields::qmlFiles);
804 currentQmlFiles.visitKeys([
this, &self](
const QString &,
const DomItem &els) {
805 return els.visitIndexes([
this, &self](
const DomItem &el) {
806 if (
const Reference *ref = el.as<Reference>()) {
807 Path canonicalPath = ref->referredObjectPath[2];
808 if (canonicalPath && !canonicalPath.headName().isEmpty())
810 Dependency{ QString(), Version(),
811 canonicalPath.headName(), DomType::QmlFile });
817 }
else if (shared_ptr<ModuleIndex> elPtr = el.ownerAs<ModuleIndex>()) {
818 const auto qmldirs = elPtr->qmldirsToLoad(el);
819 for (
const Path &qmldirPath : qmldirs) {
820 Path canonicalPath = qmldirPath[2];
821 if (canonicalPath && !canonicalPath.headName().isEmpty())
823 Dependency { QString(), Version(), canonicalPath.headName(),
824 DomType::QmldirFile });
826 QString uri = elPtr->uri();
828 for (
const Path &p : qmldirs) {
829 DomItem qmldir = newV.path(p);
830 if (std::shared_ptr<QmldirFile> qmldirFilePtr = qmldir.ownerAs<QmldirFile>()) {
831 qmldirFilePtr->ensureInModuleIndex(qmldir, uri);
836 self.addError(DomEnvironment::myErrors().error(
837 tr(
"Ignoring dependencies for empty (invalid) type %1")
838 .arg(domTypeToString(el.internalKind()))));
841 DomEnvironment::myErrors().error(tr(
"dependencies of %1 (%2) not yet implemented")
842 .arg(domTypeToString(el.internalKind()),
843 elementCanonicalPath().toString())));
849 bool unexpectedState =
false;
851 QMutexLocker l(mutex());
855 Q_ASSERT(!unexpectedState &&
"LoadInfo::addDependency found an unexpected state");
861
862
863
864
865
866
867
868
889 cont = cont && DomTop::iterateDirectSubpaths(self, visitor);
891 cont = cont && self.dvItemField(visitor, Fields::universe, [
this]() {
return universe(); });
892 cont = cont && self.dvValueField(visitor, Fields::options,
int(options()));
893 cont = cont && self.dvItemField(visitor, Fields::base, [
this]() {
return base(); });
895 && self.dvValueLazyField(visitor, Fields::loadPaths, [
this]() {
return loadPaths(); });
896 cont = cont && self.dvValueField(visitor, Fields::globalScopeName, globalScopeName());
897 cont = cont && self.dvItemField(visitor, Fields::globalScopeWithName, [
this, &self]() {
898 return self.subMapItem(Map(
899 Path::fromField(Fields::globalScopeWithName),
900 [&self,
this](
const DomItem &map,
const QString &key) {
901 return map.copy(globalScopeWithName(self, key));
903 [&self,
this](
const DomItem &) {
return globalScopeNames(self); },
904 QLatin1String(
"GlobalScope")));
906 cont = cont && self.dvItemField(visitor, Fields::qmlDirectoryWithPath, [
this, &self]() {
907 return self.subMapItem(Map(
908 Path::fromField(Fields::qmlDirectoryWithPath),
909 [&self,
this](
const DomItem &map,
const QString &key) {
910 return map.copy(qmlDirectoryWithPath(self, key));
912 [&self,
this](
const DomItem &) {
return qmlDirectoryPaths(self); },
913 QLatin1String(
"QmlDirectory")));
915 cont = cont && self.dvItemField(visitor, Fields::qmldirFileWithPath, [
this, &self]() {
916 return self.subMapItem(Map(
917 Path::fromField(Fields::qmldirFileWithPath),
918 [&self,
this](
const DomItem &map,
const QString &key) {
919 return map.copy(qmldirFileWithPath(self, key));
921 [&self,
this](
const DomItem &) {
return qmldirFilePaths(self); },
922 QLatin1String(
"QmldirFile")));
924 cont = cont && self.dvItemField(visitor, Fields::qmldirWithPath, [
this, &self]() {
925 return self.subMapItem(Map(
926 Path::fromField(Fields::qmldirWithPath),
927 [&self,
this](
const DomItem &map,
const QString &key) {
928 return map.copy(qmlDirWithPath(self, key));
930 [&self,
this](
const DomItem &) {
return qmlDirPaths(self); }, QLatin1String(
"Qmldir")));
932 cont = cont && self.dvItemField(visitor, Fields::qmlFileWithPath, [
this, &self]() {
933 return self.subMapItem(Map(
934 Path::fromField(Fields::qmlFileWithPath),
935 [&self,
this](
const DomItem &map,
const QString &key) {
936 return map.copy(qmlFileWithPath(self, key));
938 [&self,
this](
const DomItem &) {
return qmlFilePaths(self); }, QLatin1String(
"QmlFile")));
940 cont = cont && self.dvItemField(visitor, Fields::jsFileWithPath, [
this, &self]() {
941 return self.subMapItem(Map(
942 Path::fromField(Fields::jsFileWithPath),
943 [
this](
const DomItem &map,
const QString &key) {
944 DomItem mapOw(map.owner());
945 return map.copy(jsFileWithPath(mapOw, key));
947 [
this](
const DomItem &map) {
948 DomItem mapOw = map.owner();
949 return jsFilePaths(mapOw);
951 QLatin1String(
"JsFile")));
953 cont = cont && self.dvItemField(visitor, Fields::qmltypesFileWithPath, [
this, &self]() {
954 return self.subMapItem(Map(
955 Path::fromField(Fields::qmltypesFileWithPath),
956 [
this](
const DomItem &map,
const QString &key) {
957 DomItem mapOw = map.owner();
958 return map.copy(qmltypesFileWithPath(mapOw, key));
960 [
this](
const DomItem &map) {
961 DomItem mapOw = map.owner();
962 return qmltypesFilePaths(mapOw);
964 QLatin1String(
"QmltypesFile")));
966 cont = cont && self.dvItemField(visitor, Fields::moduleIndexWithUri, [
this, &self]() {
967 return self.subMapItem(Map(
968 Path::fromField(Fields::moduleIndexWithUri),
969 [
this](
const DomItem &map,
const QString &key) {
970 return map.subMapItem(Map(
971 map.pathFromOwner().withKey(key),
972 [
this, key](
const DomItem &submap,
const QString &subKey) {
974 int i = subKey.toInt(&ok);
976 if (subKey.isEmpty())
977 i = Version::Undefined;
978 else if (subKey.compare(u"Latest", Qt::CaseInsensitive) == 0)
983 DomItem subMapOw = submap.owner();
984 std::shared_ptr<ModuleIndex> mIndex =
985 moduleIndexWithUri(subMapOw, key, i);
986 return submap.copy(mIndex);
988 [
this, key](
const DomItem &subMap) {
990 DomItem subMapOw = subMap.owner();
992 moduleIndexMajorVersions(subMapOw, key, EnvLookup::Normal))
993 if (mVersion == Version::Undefined)
994 res.insert(QString());
996 res.insert(QString::number(mVersion));
998 res.insert(QLatin1String(
"Latest"));
1001 QLatin1String(
"ModuleIndex")));
1003 [
this](
const DomItem &map) {
1004 DomItem mapOw = map.owner();
1005 return moduleIndexUris(mapOw);
1007 QLatin1String(
"Map<ModuleIndex>")));
1009 bool loadedLoadInfo =
false;
1010 QQueue<Path> loadsWithWork;
1011 QQueue<Path> inProgress;
1012 int nAllLoadedCallbacks;
1013 auto ensureInfo = [&]() {
1014 if (!loadedLoadInfo) {
1015 QMutexLocker l(mutex());
1016 loadedLoadInfo =
true;
1017 loadsWithWork = m_loadsWithWork;
1018 inProgress = m_inProgress;
1019 nAllLoadedCallbacks = m_allLoadedCallback.size();
1023 && self.dvItemField(
1024 visitor, Fields::loadsWithWork, [&ensureInfo, &self, &loadsWithWork]() {
1026 return self.subListItem(List(
1027 Path::fromField(Fields::loadsWithWork),
1028 [loadsWithWork](
const DomItem &list, index_type i) {
1029 if (i >= 0 && i < loadsWithWork.size())
1030 return list.subDataItem(PathEls::Index(i),
1031 loadsWithWork.at(i).toString());
1035 [loadsWithWork](
const DomItem &) {
1036 return index_type(loadsWithWork.size());
1038 nullptr, QLatin1String(
"Path")));
1041 && self.dvItemField(visitor, Fields::inProgress, [&self, &ensureInfo, &inProgress]() {
1043 return self.subListItem(List(
1044 Path::fromField(Fields::inProgress),
1045 [inProgress](
const DomItem &list, index_type i) {
1046 if (i >= 0 && i < inProgress.size())
1047 return list.subDataItem(PathEls::Index(i),
1048 inProgress.at(i).toString());
1052 [inProgress](
const DomItem &) {
return index_type(inProgress.size()); },
1053 nullptr, QLatin1String(
"Path")));
1055 cont = cont && self.dvItemField(visitor, Fields::loadInfo, [&self,
this]() {
1056 return self.subMapItem(Map(
1057 Path::fromField(Fields::loadInfo),
1058 [
this](
const DomItem &map,
const QString &pStr) {
1059 bool hasErrors =
false;
1060 Path p = Path::fromString(pStr, [&hasErrors](
const ErrorMessage &m) {
1062 case ErrorLevel::Debug:
1063 case ErrorLevel::Info:
1065 case ErrorLevel::Warning:
1066 case ErrorLevel::Error:
1067 case ErrorLevel::Fatal:
1073 return map.copy(loadInfo(p));
1076 [
this](
const DomItem &) {
1078 const auto infoPaths = loadInfoPaths();
1079 for (
const Path &p : infoPaths)
1080 res.insert(p.toString());
1083 QLatin1String(
"LoadInfo")));
1085 cont = cont && self.dvWrapField(visitor, Fields::imports, m_implicitImports);
1087 && self.dvValueLazyField(visitor, Fields::nAllLoadedCallbacks,
1088 [&nAllLoadedCallbacks, &ensureInfo]() {
1090 return nAllLoadedCallbacks;
1097 return DomTop::field(self, name);
1102 return std::static_pointer_cast<DomEnvironment>(
doCopy(self));
1107 shared_ptr<DomEnvironment> res;
1109 res = std::make_shared<DomEnvironment>(m_base, m_loadPaths, m_options, m_domCreationOption);
1111 res = std::make_shared<DomEnvironment>(m_loadPaths, m_options, m_domCreationOption,
1119 if (options() & DomEnvironment::Option::NoDependencies)
1120 loadFile(file, callback, DomTop::Callback(), fileType, h);
1125 loadFile(file, DomTop::Callback(), callback, fileType, h);
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1142void DomEnvironment::loadFile(
const FileToLoad &_file,
const Callback &loadCallback,
1143 const Callback &endCallback,
std::optional<
DomType> fileType,
1146 DomItem self(shared_from_this());
1148 (
bool(fileType) ? (*fileType) : fileTypeForPath(self, _file.logicalPath()));
1155 file.setCanonicalPath(QQmlJSUtils::qmlSourcePathFromBuildPath(
1156 semanticAnalysis().m_mapper.get(), file.canonicalPath()));
1157 file.setLogicalPath(file.logicalPath());
1161 if (file.canonicalPath().isEmpty()) {
1162 if (!file.content() || file.content()->data.isNull()) {
1165 .error(tr(
"Non existing path to load: '%1'").arg(file.logicalPath())
)
1170 addAllLoadedCallback(self, [endCallback](Path,
const DomItem &,
const DomItem &) {
1171 endCallback(Path(), DomItem::empty, DomItem::empty);
1176 file.canonicalPath() = file.logicalPath();
1183 const auto &fetchResult = fetchFileFromEnvs<QmlDirectory>(file);
1184 oldValue = fetchResult.first;
1185 newValue = fetchResult.second;
1187 const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOption);
1188 addExternalItemInfo<QmlDirectory>(loadRes.currentItem,
1189 getLoadCallbackFor(fType, loadCallback), endCallback);
1194 const auto &fetchResult = fetchFileFromEnvs<QmlFile>(file);
1195 oldValue = fetchResult.first;
1196 newValue = fetchResult.second;
1198 const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOption);
1199 addExternalItemInfo<QmlFile>(loadRes.currentItem,
1200 getLoadCallbackFor(fType, loadCallback), endCallback);
1205 const auto &fetchResult = fetchFileFromEnvs<QmltypesFile>(file);
1206 oldValue = fetchResult.first;
1207 newValue = fetchResult.second;
1209 const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOption);
1210 addExternalItemInfo<QmltypesFile>(loadRes.currentItem,
1211 getLoadCallbackFor(fType, loadCallback), endCallback);
1216 const auto &fetchResult = fetchFileFromEnvs<QmldirFile>(file);
1217 oldValue = fetchResult.first;
1218 newValue = fetchResult.second;
1220 const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOption);
1221 addExternalItemInfo<QmldirFile>(loadRes.currentItem,
1222 getLoadCallbackFor(fType, loadCallback), endCallback);
1227 const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOption);
1228 addExternalItemInfo<JsFile>(loadRes.currentItem, getLoadCallbackFor(fType, loadCallback),
1233 myErrors().error(tr(
"Unexpected file to load: '%1'").arg(file.canonicalPath())
).handle(h);
1241 Path p = self.copy(newValue).canonicalPath();
1242 std::shared_ptr<LoadInfo> lInfo = loadInfo(p);
1245 DomItem oldValueObj = self.copy(oldValue);
1246 DomItem newValueObj = self.copy(newValue);
1247 loadCallback(p, oldValueObj, newValueObj);
1255 addAllLoadedCallback(self, [p = std::move(p), endCallback](
1256 const Path &,
const DomItem &,
const DomItem &env) {
1257 DomItem el = env.path(p);
1258 endCallback(p, el, el);
1262void DomEnvironment::loadModuleDependency(
1263 const QString &uri,
Version version,
1267 DomItem envItem(shared_from_this());
1268 if (options() & DomEnvironment::Option::NoDependencies)
1269 loadModuleDependency(envItem, uri, version, callback,
nullptr, errorHandler);
1271 loadModuleDependency(envItem, uri, version,
nullptr, callback, errorHandler);
1274void DomEnvironment::loadModuleDependency(
1275 const DomItem &self,
const QString &uri,
Version v,
const Callback &loadCallback,
1276 const Callback &endCallback,
const ErrorHandler &errorHandler)
1278 Q_ASSERT(!uri.contains(u'/'));
1279 Path p = Paths::moduleIndexPath(uri, v.majorVersion);
1280 if (v.majorVersion == Version::Latest) {
1282 QStringList subPathComponents = uri.split(QLatin1Char(
'.'));
1284 bool commonV =
false;
1285 QString lastComponent = subPathComponents.last();
1286 subPathComponents.removeLast();
1287 QString subPathV = subPathComponents.join(u'/');
1288 QRegularExpression vRe(QRegularExpression::anchoredPattern(
1289 QRegularExpression::escape(lastComponent) + QStringLiteral(u"\\.([0-9]*)")));
1290 const auto lPaths = loadPaths();
1291 qCDebug(QQmlJSDomImporting) <<
"DomEnvironment::loadModuleDependency: Searching module with"
1294 for (
const QString &path : lPaths) {
1295 QDir dir(path + (subPathV.isEmpty() ? QStringLiteral(u"") : QStringLiteral(u"/"))
1297 const auto eList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
1298 for (
const QString &dirNow : eList) {
1299 auto m = vRe.match(dirNow);
1301 int majorV = m.captured(1).toInt();
1302 if (majorV > maxV) {
1303 QFileInfo fInfo(dir.canonicalPath() + QChar(u'/') + dirNow
1304 + QStringLiteral(u"/qmldir"));
1305 if (fInfo.isFile()) {
1306 qCDebug(QQmlJSDomImporting)
1307 <<
"Found qmldir in " << fInfo.canonicalFilePath();
1312 if (!commonV && dirNow == lastComponent) {
1313 QFileInfo fInfo(dir.canonicalPath() + QChar(u'/') + dirNow
1314 + QStringLiteral(u"/qmldir"));
1315 if (fInfo.isFile()) {
1316 qCDebug(QQmlJSDomImporting)
1317 <<
"Found qmldir in " << fInfo.canonicalFilePath();
1328 int toLoad = (commonV ? 1 : 0) + ((maxV >= 0) ? 1 : 0);
1329 const auto &loadCallback2 = loadCallback
1331 if (--toLoad == 0) {
1333 loadCallback(p, el, el);
1339 loadModuleDependency(self, uri, Version(maxV, v.minorVersion), loadCallback2,
nullptr);
1341 loadModuleDependency(self, uri, Version(Version::Undefined, v.minorVersion),
1342 loadCallback2,
nullptr);
1343 else if (maxV < 0) {
1344 if (uri != u"QML") {
1345 const QString loadPaths = lPaths.join(u", "_s);
1346 qCDebug(QQmlJSDomImporting)
1347 <<
"DomEnvironment::loadModuleDependency: qmldir at" << (uri + u"/qmldir"_s)
1348 <<
"was not found in " << loadPaths;
1351 .warning(tr(
"Failed to find main qmldir file for %1 %2 in %3.")
1352 .arg(uri, v.stringValue(), loadPaths)
)
1359 std::shared_ptr<ModuleIndex> mIndex = moduleIndexWithUri(
1360 self, uri, v.majorVersion, EnvLookup::Normal, Changeable::Writable, errorHandler);
1361 std::shared_ptr<LoadInfo> lInfo = loadInfo(p);
1363 DomItem lInfoObj = self.copy(lInfo);
1364 lInfo->addEndCallback(lInfoObj, loadCallback);
1373 addAllLoadedCallback(self, [p = std::move(p), endCallback = std::move(endCallback)](
1374 Path,
const DomItem &,
const DomItem &env) {
1375 DomItem el = env.path(p);
1376 endCallback(p, el, el);
1383 QString builtinsName = QLatin1String(
"QML/plugins.qmltypes");
1384 const auto lPaths = loadPaths();
1385 for (
const QString &path : lPaths) {
1387 QFileInfo fInfo(dir.filePath(builtinsName));
1388 if (fInfo.isFile()) {
1389 loadFile(FileToLoad::fromFileSystem(shared_from_this(), fInfo.canonicalFilePath()),
1399 QMutexLocker l(mutex());
1400 auto toDelete = [path](
auto it) {
1401 QString p = it.key();
1402 return p.startsWith(path) && (p.size() == path.size() || p.at(path.size()) == u'/');
1404 m_qmlDirectoryWithPath.removeIf(toDelete);
1405 m_qmldirFileWithPath.removeIf(toDelete);
1406 m_qmlFileWithPath.removeIf(toDelete);
1407 m_jsFileWithPath.removeIf(toDelete);
1408 m_qmltypesFileWithPath.removeIf(toDelete);
1411shared_ptr<DomUniverse> DomEnvironment::
universe()
const {
1415 return m_base->universe();
1447 DomItem baseObj = DomItem(m_base);
1448 return this->getStrings<QMap<
int, std::shared_ptr<ModuleIndex>>>(
1449 [
this, &baseObj] {
return m_base->moduleIndexUris(baseObj, EnvLookup::Normal); },
1450 m_moduleIndexWithUri, lookup);
1456 if (lookup != EnvLookup::NoBase && m_base) {
1458 res = m_base->moduleIndexMajorVersions(baseObj, uri, EnvLookup::Normal);
1461 QMap<
int, std::shared_ptr<ModuleIndex>> map;
1463 QMutexLocker l(mutex());
1464 map = m_moduleIndexWithUri.value(uri);
1466 auto it = map.keyBegin();
1467 auto end = map.keyEnd();
1476std::shared_ptr<ModuleIndex> DomEnvironment::lookupModuleInEnv(
const QString &uri,
int majorVersion)
const
1478 QMutexLocker l(mutex());
1479 auto it = m_moduleIndexWithUri.find(uri);
1480 if (it == m_moduleIndexWithUri.end())
1484 if (majorVersion == Version::Latest)
1487 return it->value(majorVersion);
1490DomEnvironment::ModuleLookupResult DomEnvironment::moduleIndexWithUriHelper(
const DomItem &self,
const QString &uri,
int majorVersion,
EnvLookup options)
const
1492 std::shared_ptr<ModuleIndex> res;
1493 if (options != EnvLookup::BaseOnly)
1494 res = lookupModuleInEnv(uri, majorVersion);
1497 if (options == EnvLookup::NoBase || !m_base)
1498 return {
std::move(res), ModuleLookupResult::FromGlobal };
1499 const std::shared_ptr existingMod =
1500 m_base->moduleIndexWithUri(self, uri, majorVersion, options, Changeable::ReadOnly);
1502 return {
std::move(existingMod), ModuleLookupResult::FromBase };
1504 return {
std::move(res), ModuleLookupResult::FromGlobal };
1510 if (majorVersion == Version::Latest) {
1511 if (res->majorVersion() >= existingMod->majorVersion())
1512 return {
std::move(res), ModuleLookupResult::FromGlobal };
1514 return {
std::move(existingMod), ModuleLookupResult::FromBase };
1518 return {
std::move(res), ModuleLookupResult::FromGlobal };
1523 const DomItem &self,
const QString &uri,
int majorVersion,
EnvLookup options,
1528 || (majorVersion >= 0 || majorVersion == Version::Undefined))
1529 &&
"A writeable moduleIndexWithUri call should have a version (not with "
1530 "Version::Latest)");
1531 if (changeable == Changeable::Writable && (m_options & Option::Exported))
1532 myErrors().error(tr(
"A mutable module was requested in a multithreaded environment")
).handle(errorHandler);
1536 auto candidate = moduleIndexWithUriHelper(self, uri, majorVersion, options);
1539 if (candidate.module && candidate.fromBase == ModuleLookupResult::FromGlobal)
1540 return std::move(candidate.module);
1544 return std::move(candidate.module);
1547 std::shared_ptr<ModuleIndex> newModulePtr = [&] {
1549 if (!candidate.module)
1550 return std::make_shared<ModuleIndex>(uri, majorVersion);
1552 DomItem existingModObj = self.copy(candidate.module);
1553 return candidate.module->makeCopy(existingModObj);
1556 DomItem newModule = self.copy(newModulePtr);
1559 QMutexLocker l(mutex());
1560 auto &modsNow = m_moduleIndexWithUri[uri];
1563 if (
auto it = modsNow.constFind(majorVersion); it != modsNow.cend())
1565 modsNow.insert(majorVersion, newModulePtr);
1568 auto lInfo =
std::make_shared<LoadInfo>(p);
1572 .error(tr(
"Could not get path for newly created ModuleIndex %1 %2")
1575 .handle(errorHandler);
1578 return newModulePtr;
1585 return moduleIndexWithUriHelper(self, uri, majorVersion, options).module;
1588std::shared_ptr<ExternalItemInfo<QmlDirectory>>
1591 return lookup<QmlDirectory>(path, options);
1596 return getStrings<std::shared_ptr<ExternalItemInfo<QmlDirectory>>>(
1598 DomItem baseObj(m_base);
1599 return m_base->qmlDirectoryPaths(baseObj, EnvLookup::Normal);
1601 m_qmlDirectoryWithPath, options);
1604std::shared_ptr<ExternalItemInfo<QmldirFile>>
1607 return lookup<QmldirFile>(path, options);
1612 return getStrings<std::shared_ptr<ExternalItemInfo<QmldirFile>>>(
1614 DomItem baseObj(m_base);
1615 return m_base->qmldirFilePaths(baseObj, EnvLookup::Normal);
1617 m_qmldirFileWithPath, lOptions);
1623 if (
auto qmldirFile = qmldirFileWithPath(self, path + QLatin1String(
"/qmldir"), options))
1625 return qmlDirectoryWithPath(self, path, options);
1630 QSet<QString> res = qmlDirectoryPaths(self, options);
1631 const auto qmldirFiles = qmldirFilePaths(self, options);
1632 for (
const QString &p : qmldirFiles) {
1633 if (p.endsWith(u"/qmldir")) {
1634 res.insert(p.left(p.size() - 7));
1637 .warning(tr(
"Unexpected path not ending with qmldir in qmldirFilePaths: %1")
1645std::shared_ptr<ExternalItemInfo<QmlFile>>
1648 return lookup<QmlFile>(path, options);
1653 return getStrings<std::shared_ptr<ExternalItemInfo<QmlFile>>>(
1655 DomItem baseObj(m_base);
1656 return m_base->qmlFilePaths(baseObj, EnvLookup::Normal);
1658 m_qmlFileWithPath, lookup);
1661std::shared_ptr<ExternalItemInfo<JsFile>>
1664 return lookup<JsFile>(path, options);
1669 return getStrings<std::shared_ptr<ExternalItemInfo<JsFile>>>(
1671 DomItem baseObj(m_base);
1672 return m_base->jsFilePaths(baseObj, EnvLookup::Normal);
1674 m_jsFileWithPath, lookup);
1677std::shared_ptr<ExternalItemInfo<QmltypesFile>>
1680 return lookup<QmltypesFile>(path, options);
1685 return getStrings<std::shared_ptr<ExternalItemInfo<QmltypesFile>>>(
1687 DomItem baseObj(m_base);
1688 return m_base->qmltypesFilePaths(baseObj, EnvLookup::Normal);
1690 m_qmltypesFileWithPath, lookup);
1693std::shared_ptr<ExternalItemInfo<GlobalScope>>
1697 return lookup<GlobalScope>(name, lookupOptions);
1700std::shared_ptr<ExternalItemInfo<GlobalScope>>
1703 if (
auto current = globalScopeWithName(self, name, lookupOptions))
1705 if (
auto u = universe()) {
1706 if (
auto newVal = u->ensureGlobalScopeWithName(name)) {
1707 if (
auto current = newVal->current) {
1709 auto newScope = current->makeCopy(currentObj);
1710 auto newCopy =
std::make_shared<ExternalItemInfo<GlobalScope>>(
1712 QMutexLocker l(mutex());
1713 if (
auto oldVal = m_globalScopeWithName.value(name))
1715 m_globalScopeWithName.insert(name, newCopy);
1720 Q_ASSERT_X(
false,
"DomEnvironment::ensureGlobalScopeWithName",
"could not ensure globalScope");
1727 if (lookupOptions != EnvLookup::NoBase && m_base) {
1730 res = m_base->globalScopeNames(baseObj, EnvLookup::Normal);
1734 QMap<QString, std::shared_ptr<ExternalItemInfo<GlobalScope>>> map;
1736 QMutexLocker l(mutex());
1737 map = m_globalScopeWithName;
1739 auto it = map.keyBegin();
1740 auto end = map.keyEnd();
1750
1751
1752
1755 if (options() & Option::NoDependencies) {
1759 const auto loadInfo =
std::make_shared<LoadInfo>(path);
1764
1765
1766
1767
1772 Path p = loadInfo->elementCanonicalPath();
1773 bool addWork = loadInfo->status() != LoadInfo::Status::Done;
1774 std::shared_ptr<LoadInfo> oldVal;
1776 QMutexLocker l(mutex());
1777 oldVal = m_loadInfos.value(p);
1778 m_loadInfos.insert(p, loadInfo);
1780 m_loadsWithWork.enqueue(p);
1784 .error(tr(
"addLoadinfo replaces unfinished load info for %1")
1792 QMutexLocker l(mutex());
1793 return m_loadInfos.value(path);
1798 QMutexLocker l(mutex());
1804 auto lInfos = loadInfos();
1805 return lInfos.keys();
1812 DomItem newFile = newV.field(Fields::currentItem);
1813 if (std::shared_ptr<QmltypesFile> newFilePtr = newFile.ownerAs<QmltypesFile>())
1814 newFilePtr->ensureInModuleIndex(newFile);
1816 loadCallback(p, oldV, newV);
1819 return loadCallback;
1822DomEnvironment::
DomEnvironment(
const QStringList &loadPaths, Options options,
1824 const shared_ptr<DomUniverse> &universe)
1829 m_domCreationOption(domCreationOption)
1835
1836
1837
1838
1844 auto result = m_base->semanticAnalysis();
1845 result.updateLoadPaths(m_loadPaths);
1849 if (m_semanticAnalysis)
1850 return *m_semanticAnalysis;
1853 m_semanticAnalysis = SemanticAnalysis(m_loadPaths);
1854 return *m_semanticAnalysis;
1857DomEnvironment::SemanticAnalysis::SemanticAnalysis(
const QStringList &loadPaths)
1858 : m_mapper(std::make_shared<QQmlJSResourceFileMapper>(
1859 QQmlJSUtils::resourceFilesFromBuildFolders(loadPaths))),
1860 m_importer(std::make_shared<QQmlJSImporter>(loadPaths, m_mapper.get(),
1861 QQmlJSImporterFlags{} | UseOptionalImports
1862 | TolerateFileSelectors
1863 | PreferQmlFilesFromSourceFolder))
1868
1869
1870
1871
1872
1873
1874
1875void DomEnvironment::SemanticAnalysis::updateLoadPaths(
const QStringList &loadPaths)
1877 if (loadPaths == m_importer->importPaths())
1880 m_importer->setImportPaths(loadPaths);
1881 *m_mapper = QQmlJSResourceFileMapper(QQmlJSUtils::resourceFilesFromBuildFolders(loadPaths));
1884std::shared_ptr<DomEnvironment> DomEnvironment::create(
const QStringList &loadPaths,
1889 std::shared_ptr<DomUniverse> universePtr = universe.ownerAs<DomUniverse>();
1890 return std::make_shared<DomEnvironment>(loadPaths, options, domCreationOption, universePtr);
1893DomEnvironment::
DomEnvironment(
const shared_ptr<DomEnvironment> &parent,
1894 const QStringList &loadPaths, Options options,
1900 m_domCreationOption(domCreationOption)
1906 addExternalItem(file, file->canonicalFilePath(), options);
1908 QQmlJSScope::Ptr handle =
1909 semanticAnalysis().m_importer->importFile(file->canonicalFilePath());
1912 QDeferredFactory<QQmlJSScope> newFactory(semanticAnalysis().m_importer.get(),
1913 file->canonicalFilePath(),
1914 TypeReader{ weak_from_this(), m_loadPaths });
1915 file->setHandleForPopulation(handle);
1916 handle.resetFactory(std::move(newFactory));
1922 addExternalItem(file, file->canonicalFilePath(), options);
1927 addExternalItem(file, file->canonicalFilePath(), options);
1932 addExternalItem(file, file->canonicalFilePath(), options);
1937 addExternalItem(file, file->canonicalFilePath(), options);
1942 addExternalItem(scope, scope->name(), options);
1945QList<QQmlJS::DiagnosticMessage>
1946DomEnvironment::TypeReader::operator()(QQmlJSImporter *importer,
const QString &filePath,
1947 const QSharedPointer<QQmlJSScope> &scopeToPopulate)
1950 Q_UNUSED(scopeToPopulate);
1952 const QFileInfo info{ filePath };
1953 const QString baseName = info.baseName();
1954 scopeToPopulate->setInternalName(baseName.endsWith(QStringLiteral(
".ui")) ? baseName.chopped(3)
1957 std::shared_ptr<DomEnvironment> envPtr = m_env.lock();
1960 auto it = envPtr->m_qmlFileWithPath.constFind(filePath);
1961 if (it == envPtr->m_qmlFileWithPath.constEnd()) {
1962 qCDebug(domLog) <<
"Import visitor tried to lazily load file \"" << filePath
1963 <<
"\", but that file was not found in the DomEnvironment. Was this "
1964 "file not discovered by the Dom's dependency loading mechanism?";
1965 return { QQmlJS::DiagnosticMessage{
1966 u"Could not find file \"%1\" in the Dom."_s.arg(filePath), QtMsgType::QtWarningMsg,
1967 SourceLocation{} } };
1969 const DomItem qmlFile = it.value()->currentItem(
DomItem(envPtr));
1973 const QStringList oldImportPaths = envPtr->loadPaths();
1974 envPtr->setLoadPaths(m_importPaths);
1976 envPtr->setLoadPaths(oldImportPaths);
1982 const DomItem &self,
const shared_ptr<DomEnvironment> &validEnvPtr)
1986 QMap<QString, QMap<
int, std::shared_ptr<ModuleIndex>>> my_moduleIndexWithUri;
1987 QMap<QString, std::shared_ptr<ExternalItemInfo<GlobalScope>>> my_globalScopeWithName;
1988 QMap<QString, std::shared_ptr<ExternalItemInfo<QmlDirectory>>> my_qmlDirectoryWithPath;
1989 QMap<QString, std::shared_ptr<ExternalItemInfo<QmldirFile>>> my_qmldirFileWithPath;
1990 QMap<QString, std::shared_ptr<ExternalItemInfo<QmlFile>>> my_qmlFileWithPath;
1991 QMap<QString, std::shared_ptr<ExternalItemInfo<JsFile>>> my_jsFileWithPath;
1992 QMap<QString, std::shared_ptr<ExternalItemInfo<QmltypesFile>>> my_qmltypesFileWithPath;
1993 QHash<Path, std::shared_ptr<LoadInfo>> my_loadInfos;
1994 std::optional<SemanticAnalysis> my_semanticAnalysis;
1996 QMutexLocker l(mutex());
1997 my_moduleIndexWithUri = m_moduleIndexWithUri;
1998 my_globalScopeWithName = m_globalScopeWithName;
1999 my_qmlDirectoryWithPath = m_qmlDirectoryWithPath;
2000 my_qmldirFileWithPath = m_qmldirFileWithPath;
2001 my_qmlFileWithPath = m_qmlFileWithPath;
2002 my_jsFileWithPath = m_jsFileWithPath;
2003 my_qmltypesFileWithPath = m_qmltypesFileWithPath;
2004 my_loadInfos = m_loadInfos;
2008 QMutexLocker lBase(base()->mutex());
2009 m_base->m_semanticAnalysis = my_semanticAnalysis;
2010 m_base->m_globalScopeWithName.insert(my_globalScopeWithName);
2011 m_base->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
2012 m_base->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
2013 m_base->m_qmlFileWithPath.insert(my_qmlFileWithPath);
2014 m_base->m_jsFileWithPath.insert(my_jsFileWithPath);
2015 m_base->m_qmltypesFileWithPath.insert(my_qmltypesFileWithPath);
2016 m_base->m_loadInfos.insert(my_loadInfos);
2018 auto it = my_moduleIndexWithUri.cbegin();
2019 auto end = my_moduleIndexWithUri.cend();
2021 QMap<
int, shared_ptr<ModuleIndex>> &myVersions =
2022 m_base->m_moduleIndexWithUri[it.key()];
2023 auto it2 = it.value().cbegin();
2024 auto end2 = it.value().cend();
2025 while (it2 != end2) {
2026 auto oldV = myVersions.value(it2.key());
2027 DomItem it2Obj = self.copy(it2.value());
2028 auto newV = it2.value()->makeCopy(it2Obj);
2029 newV->mergeWith(oldV);
2030 myVersions.insert(it2.key(), newV);
2038 m_lastValidBase = validEnvPtr;
2039 if (m_lastValidBase) {
2040 QMutexLocker lValid(
2041 m_lastValidBase->mutex());
2042 m_lastValidBase->m_semanticAnalysis = std::move(my_semanticAnalysis);
2043 m_lastValidBase->m_globalScopeWithName.insert(my_globalScopeWithName);
2044 m_lastValidBase->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
2045 m_lastValidBase->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
2046 for (
auto it = my_qmlFileWithPath.cbegin(), end = my_qmlFileWithPath.cend(); it != end;
2048 if (it.value() && it.value()->current && it.value()->current->isValid())
2049 m_lastValidBase->m_qmlFileWithPath.insert(it.key(), it.value());
2051 for (
auto it = my_jsFileWithPath.cbegin(), end = my_jsFileWithPath.cend(); it != end;
2053 if (it.value() && it.value()->current && it.value()->current->isValid())
2054 m_lastValidBase->m_jsFileWithPath.insert(it.key(), it.value());
2056 m_lastValidBase->m_qmltypesFileWithPath.insert(my_qmltypesFileWithPath);
2057 m_lastValidBase->m_loadInfos.insert(my_loadInfos);
2058 for (
auto it = my_moduleIndexWithUri.cbegin(), end = my_moduleIndexWithUri.cend();
2060 QMap<
int, shared_ptr<ModuleIndex>> &myVersions =
2061 m_lastValidBase->m_moduleIndexWithUri[it.key()];
2062 for (
auto it2 = it.value().cbegin(), end2 = it.value().cend(); it2 != end2; ++it2) {
2063 auto oldV = myVersions.value(it2.key());
2064 DomItem it2Obj = self.copy(it2.value());
2065 auto newV = it2.value()->makeCopy(it2Obj);
2066 newV->mergeWith(oldV);
2067 myVersions.insert(it2.key(), newV);
2072 auto newBaseForPopulation =
2073 m_lastValidBase ? m_lastValidBase->weak_from_this() : m_base->weak_from_this();
2076 for (
const auto &qmlFile : my_qmlFileWithPath) {
2077 if (!qmlFile || !qmlFile->current)
2079 QQmlJSScope::ConstPtr handle = qmlFile->current->handleForPopulation();
2082 auto oldFactory = handle.factory();
2086 const QDeferredFactory<QQmlJSScope> newFactory(
2087 oldFactory->importer(), oldFactory->filePath(),
2088 TypeReader{ newBaseForPopulation, m_loadPaths });
2089 handle.resetFactory(newFactory);
2096 DomItem self(shared_from_this());
2099 std::shared_ptr<LoadInfo> loadInfo;
2101 QMutexLocker l(mutex());
2102 if (m_loadsWithWork.isEmpty())
2104 elToDo = m_loadsWithWork.dequeue();
2105 m_inProgress.append(elToDo);
2106 loadInfo = m_loadInfos.value(elToDo);
2109 auto cleanup = qScopeGuard([
this, &elToDo, &self] {
2110 QList<Callback> endCallbacks;
2112 QMutexLocker l(mutex());
2113 m_inProgress.removeOne(elToDo);
2114 if (m_inProgress.isEmpty() && m_loadsWithWork.isEmpty()) {
2115 endCallbacks = m_allLoadedCallback;
2116 m_allLoadedCallback.clear();
2119 for (
const Callback &cb : std::as_const(endCallbacks))
2120 cb(self.canonicalPath(), self, self);
2122 DomItem loadInfoObj = self.copy(loadInfo);
2123 loadInfo->advanceLoad(loadInfoObj);
2125 self.addError(myErrors().error(u"DomEnvironment::loadPendingDependencies could not "
2126 u"find loadInfo listed in m_loadsWithWork"_sv));
2128 QMutexLocker l(mutex());
2129 m_inProgress.removeOne(elToDo);
2132 &&
"DomEnvironment::loadPendingDependencies could not find loadInfo listed in "
2140 bool hasPendingLoads =
true;
2141 QDateTime endTime = QDateTime::currentDateTimeUtc().addMSecs(waitMSec);
2142 for (
int i = 0; i < waitMSec / 10 + 2; ++i) {
2144 auto lInfos = loadInfos();
2145 auto it = lInfos.cbegin();
2146 auto end = lInfos.cend();
2147 hasPendingLoads =
false;
2150 hasPendingLoads =
true;
2152 if (!hasPendingLoads)
2154 auto missing = QDateTime::currentDateTimeUtc().msecsTo(endTime);
2159#if QT_FEATURE_thread
2160 QThread::msleep(missing);
2163 return !hasPendingLoads;
2168 QMutexLocker l(mutex());
2169 m_loadsWithWork.enqueue(elementCanonicalPath);
2177std::shared_ptr<DomEnvironment> DomEnvironment::
base()
const
2184 QMutexLocker l(mutex());
2187 if (m_semanticAnalysis)
2188 m_semanticAnalysis->updateLoadPaths(v);
2193 QMutexLocker l(mutex());
2199 QMutexLocker l(mutex());
2200 return m_qmldirFileWithPath.keys();
2205 return m_globalScopeName;
2208QList<Import> DomEnvironment::defaultImplicitImports()
2210 return QList<Import>({ Import::fromUriString(u"QML"_s, Version(1, 0)),
2211 Import(QmlUri::fromUriString(u"QtQml"_s), Version(6, 0)) });
2216 return m_implicitImports;
2222 bool immediate =
false;
2224 QMutexLocker l(mutex());
2225 if (m_loadsWithWork.isEmpty() && m_inProgress.isEmpty())
2228 m_allLoadedCallback.append(c);
2237 m_referenceCache.clear();
2242 if (std::shared_ptr<QmlFile> qmlFilePtr = qmlFile.ownerAs<QmlFile>()) {
2243 auto logger = std::make_shared<QQmlJSLogger>();
2244 logger->setFilePath(qmlFile.canonicalFilePath());
2245 logger->setCode(qmlFilePtr->code());
2246 logger->setSilent(
true);
2248 auto setupFile = [&qmlFilePtr, &qmlFile,
this](
auto &&visitor) {
2251 AST::Node::accept(qmlFilePtr->ast(), visitor);
2262 auto scope = analysis.m_importer->importFile(qmlFile.canonicalFilePath());
2264 scope, qmlFile, logger.get(), analysis.m_importer.get());
2265 v->enableLoadFileLazily(
true);
2266 v->enableScriptExpressions(
true);
2271 std::make_shared<QQmlJSTypeResolver>(analysis.m_importer.get());
2272 typeResolver->init(&v->scopeCreator(),
nullptr);
2273 qmlFilePtr->setTypeResolverWithDependencies(
2274 typeResolver, { analysis.m_importer, analysis.m_mapper,
std::move(logger) });
2276 auto v =
std::make_unique<QQmlDomAstCreator>(qmlFile);
2283 qCWarning(domLog) <<
"populateQmlFile called on non qmlFile";
2290 shared_ptr<ExternalOwningItem> current = currentItem();
2292 return current->canonicalFilePath(currentObj);
2297 if (!self.dvValueLazyField(visitor, Fields::currentRevision,
2300 if (!self.dvValueLazyField(visitor, Fields::lastRevision,
2303 if (!self.dvValueLazyField(visitor, Fields::lastValidRevision,
2306 if (!visitor(
PathEls::Field(Fields::currentItem),
2309 if (!self.dvValueLazyField(visitor, Fields::currentExposedAt,
2310 [
this]() {
return currentExposedAt(); }))
2317 return currentItem()->revision();
2322 Path p = currentItem()->canonicalPath();
2324 return static_cast<
int>(lastValue.value().toInteger(0));
2329 Path p = currentItem()->canonicalPath();
2331 return static_cast<
int>(lastValidValue.value().toInteger(0));
2336 shared_ptr<ExternalOwningItem> current = currentItem();
2337 return current->canonicalFilePath();
2342 shared_ptr<ExternalOwningItem> current = currentItem();
2343 return current->canonicalPath().dropTail();
2348 if (!self.dvValueLazyField(visitor, Fields::currentIsValid,
2351 if (!visitor(
PathEls::Field(Fields::validItem), [
this, &self]() {
return validItem(self
); }))
2353 if (!visitor(
PathEls::Field(Fields::currentItem),
2356 if (!self.dvValueField(visitor, Fields::validExposedAt, validExposedAt))
2358 if (!self.dvValueField(visitor, Fields::currentExposedAt, currentExposedAt))
2371 std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>();
2374 QMutexLocker l(envPtr->mutex());
2375 cached = envPtr->m_referenceCache.value(canonicalPath, {});
2377 qCWarning(domLog) <<
"No Env for reference" << canonicalPath <<
"from"
2378 << el.internalKindStr() << el.canonicalPath();
2388 std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>();
2389 bool didSet =
false;
2391 QMutexLocker l(envPtr->mutex());
2392 RefCacheEntry &cached = envPtr->m_referenceCache[canonicalPath];
2393 switch (cached.cached) {
2394 case RefCacheEntry::Cached::None:
2398 case RefCacheEntry::Cached::First:
2399 if (addOption == AddOption::Overwrite || entry.cached == RefCacheEntry::Cached::All) {
2404 case RefCacheEntry::Cached::All:
2405 if (addOption == AddOption::Overwrite || entry.cached == RefCacheEntry::Cached::All) {
2410 if (cached.cached == RefCacheEntry::Cached::First && cached.canonicalPaths.isEmpty())
2411 cached.cached = RefCacheEntry::Cached::All;
2423#include "moc_qqmldomtop_p.cpp"