155 cont = cont && self.dvValueField(visitor, Fields::name,
name());
156 cont = cont && self.dvItemField(visitor, Fields::globalScopeWithName, [
this, &self]() {
157 return self.subMapItem(
Map(
162 cont = cont && self.dvItemField(visitor, Fields::qmlDirectoryWithPath, [
this, &self]() {
163 return self.subMapItem(
Map(
168 cont = cont &&
self.dvItemField(visitor, Fields::qmldirFileWithPath, [
this, &self]() {
174 cont = cont &&
self.dvItemField(visitor, Fields::qmlFileWithPath, [
this, &self]() {
180 cont = cont &&
self.dvItemField(visitor, Fields::jsFileWithPath, [
this, &self]() {
186 cont = cont &&
self.dvItemField(visitor, Fields::jsFileWithPath, [
this, &self]() {
198 auto m =
r.match(m_name);
201 newName =
QStringLiteral(u
"%1Copy%2").arg(m_name).arg(
m.captured(1).toInt() + 1);
204 auto res = std::make_shared<DomUniverse>(newName);
213 }
else if (canonicalFilePath.
endsWith(u
".qmltypes")) {
219 }
else if (
QFileInfo(canonicalFilePath).isDir()) {
228 "Could not detect type of file %1")
229 .
arg(canonicalFilePath))
236 DomCreationOptions creationOptions)
238 DomItem univ(shared_from_this());
246 const auto &preLoadResult = preload(univ,
file,
fileType);
247 if (std::holds_alternative<LoadResult>(preLoadResult)) {
249 return std::get<LoadResult>(preLoadResult);
252 return load(std::get<ContentWithDate>(preLoadResult),
file,
fileType, creationOptions);
257 .
error(
tr(
"Ignoring request to load file %1 of unexpected type %2, "
258 "calling callback immediately")
261 Q_ASSERT(
false &&
"loading non supported file type");
268 DomCreationOptions creationOptions)
277 auto qmlFile = parseQmlFile(codeWithDate.content,
file, codeWithDate.date, creationOptions);
278 return insertOrUpdateExternalItem(std::move(qmlFile));
280 auto qmltypesFile = std::make_shared<QmltypesFile>(
canonicalPath, codeWithDate.content,
282 QmltypesReader reader(univ.copy(qmltypesFile));
284 return insertOrUpdateExternalItem(std::move(qmltypesFile));
286 shared_ptr<QmldirFile> qmldirFile =
288 return insertOrUpdateExternalItem(std::move(qmldirFile));
290 auto qmlDirectory = std::make_shared<QmlDirectory>(
292 return insertOrUpdateExternalItem(std::move(qmlDirectory));
294 auto jsFile = parseJsFile(codeWithDate.content,
file, codeWithDate.date);
295 return insertOrUpdateExternalItem(std::move(jsFile));
299 return { std::move(oldValue), std::move(newValue) };
310DomUniverse::PreloadResult DomUniverse::preload(
const DomItem &univ,
const FileToLoad &
file,
314 ContentWithDate codeWithDate;
316 if (
file.content().has_value()) {
317 codeWithDate = {
file.content()->data,
file.content()->date };
321 const auto &curValueItem = getItemIfMostRecent(univ, fType,
canonicalPath);
322 if (curValueItem.has_value()) {
323 return LoadResult{ curValueItem.value(), curValueItem.value() };
327 if (std::holds_alternative<ErrorMessage>(readResult)) {
329 newValue.addError(std::move(std::get<ErrorMessage>(readResult)));
330 return LoadResult{
DomItem(), std::move(newValue) };
332 codeWithDate = std::get<ContentWithDate>(readResult);
337 const auto &curValueItem = getItemIfHasSameCode(univ, fType,
canonicalPath, codeWithDate);
338 if (curValueItem.has_value()) {
339 return LoadResult{ curValueItem.value(), curValueItem.value() };
348 const auto toDelete = [
path](
const auto &
it) {
350 return p.startsWith(
path) && (
p.size() ==
path.size() ||
p.at(
path.size()) == u
'/');
352 m_qmlDirectoryWithPath.removeIf(toDelete);
353 m_qmldirFileWithPath.removeIf(toDelete);
354 m_qmlFileWithPath.removeIf(toDelete);
355 m_jsFileWithPath.removeIf(toDelete);
356 m_qmltypesFileWithPath.removeIf(toDelete);
366 if (fileInfo.isDir()) {
374 tr(
"Error opening path %1: %2 %3")
382std::shared_ptr<QmlFile> DomUniverse::parseQmlFile(
const QString &code,
const FileToLoad &
file,
384 DomCreationOptions creationOptions)
386 auto qmlFile = std::make_shared<QmlFile>(
file.canonicalPath(), code, contentDate, 0,
389 :
QmlFile::DisableParserRecovery);
390 std::shared_ptr<DomEnvironment> envPtr;
391 if (
auto ptr =
file.environment().lock())
392 envPtr = std::move(
ptr);
394 envPtr = std::make_shared<DomEnvironment>(
QStringList(),
396 creationOptions, shared_from_this());
397 envPtr->addQmlFile(qmlFile);
399 if (qmlFile->isValid()) {
402 envPtr->populateFromQmlFile(MutableDomItem(env.copy(qmlFile)));
405 DomItem qmlFileObj = env.copy(qmlFile);
407 errs +=
m.toString();
412 <<
"Parsed invalid file " <<
file.canonicalPath() << errs;
417std::shared_ptr<JsFile> DomUniverse::parseJsFile(
const QString &code,
const FileToLoad &
file,
424 auto jsFile = std::make_shared<JsFile>(
file.canonicalPath(), code, contentDate);
425 std::shared_ptr<DomEnvironment> envPtr;
426 if (
auto ptr =
file.environment().lock())
427 envPtr = std::move(
ptr);
429 envPtr = std::make_shared<DomEnvironment>(
QStringList(),
432 envPtr->addJsFile(jsFile);
434 if (!jsFile->isValid()) {
436 DomItem qmlFileObj = env.copy(jsFile);
438 errs +=
m.toString();
443 <<
"Parsed invalid file " <<
file.canonicalPath() << errs;
453std::shared_ptr<ExternalItemPairBase> DomUniverse::getPathValueOrNull(DomType fType,
458 return m_qmlFileWithPath.value(
path);
460 return m_qmltypesFileWithPath.value(
path);
462 return m_qmldirFileWithPath.value(
path);
464 return m_qmlDirectoryWithPath.value(
path);
466 return m_jsFileWithPath.value(
path);
473std::optional<DomItem> DomUniverse::getItemIfMostRecent(
const DomItem &univ, DomType fType,
477 bool valueItemIsMostRecent =
false;
478 std::shared_ptr<ExternalItemPairBase>
value =
nullptr;
484 valueItemIsMostRecent = valueHasMostRecentItem(
value.get(), fInfo.lastModified());
486 if (valueItemIsMostRecent) {
487 return univ.copy(
value);
492std::optional<DomItem> DomUniverse::getItemIfHasSameCode(
const DomItem &univ, DomType fType,
494 const ContentWithDate &codeWithDate)
const
496 std::shared_ptr<ExternalItemPairBase>
value =
nullptr;
497 bool valueItemHasSameCode =
false;
503 if (valueHasSameContent(
value.get(), codeWithDate.content)) {
504 valueItemHasSameCode =
true;
505 if (
value->currentItem()->lastDataUpdateAt() < codeWithDate.date)
506 value->currentItem()->refreshedDataAt(codeWithDate.date);
509 if (valueItemHasSameCode) {
510 return univ.copy(
value);
520bool DomUniverse::valueHasMostRecentItem(
const ExternalItemPairBase *
value,
526 return lastModified <
value->currentItem()->lastDataUpdateAt();
534bool DomUniverse::valueHasSameContent(
const ExternalItemPairBase *
value,
const QString &content)
540 return !curContent.
isNull() && curContent == content;
545 auto res = std::make_shared<LoadInfo>(*
this);
548 u
"This is a copy of a LoadInfo still in progress, artificially ending it, if you "
549 u
"use this you will *not* resume loading"));
551 .warning([&self](
const Sink &
sink) {
552 sink(u
"Copying an in progress LoadInfo, which is most likely an error (");
560 res->m_inProgress.clear();
561 res->m_endCallbacks.clear();
574 cont = cont && self.dvValueField(visitor, Fields::status,
int(
status()));
575 cont = cont && self.dvValueField(visitor, Fields::nLoaded,
nLoaded());
577 && self.dvValueField(visitor, Fields::elementCanonicalPath,
579 cont = cont && self.dvValueField(visitor, Fields::nNotdone,
nNotDone());
580 cont = cont && self.dvValueField(visitor, Fields::nCallbacks,
nCallbacks());
596 m_endCallbacks.append(callback);
611 bool depValid =
false;
621 if (!m_toDo.isEmpty()) {
622 dep = m_toDo.dequeue();
623 m_inProgress.append(dep);
635 doAddDependencies(self);
640 if (m_toDo.isEmpty() && m_inProgress.isEmpty())
653 Q_ASSERT(envPtr &&
"missing environment");
654 if (!dep.uri.isEmpty()) {
655 envPtr->loadModuleDependency(
656 dep.uri, dep.version,
660 finishedLoadingDep(copiedSelf, dep);
662 self.errorHandler());
663 Q_ASSERT(dep.filePath.isEmpty() &&
"dependency with both uri and file");
664 }
else if (!dep.filePath.isEmpty()) {
670 finishedLoadingDep(copiedSelf, dep);
672 dep.fileType, self.errorHandler());
674 Q_ASSERT(
false &&
"dependency without uri and filePath");
678 tr(
"advanceLoad called but found no work, which should never happen")));
684 "advanceLoad called after work should have been done, which should never happen")));
691 bool didRemove =
false;
692 bool unexpectedState =
false;
696 didRemove = m_inProgress.removeOne(
d);
701 unexpectedState =
true;
706 if (m_toDo.isEmpty() && m_inProgress.isEmpty()) {
715 sink(u
"LoadInfo::finishedLoadingDep did not find its dependency in those inProgress "
721 &&
"LoadInfo::finishedLoadingDep did not find its dependency in those inProgress");
723 if (unexpectedState) {
725 sink(u
"LoadInfo::finishedLoadingDep found an unexpected state (");
729 Q_ASSERT(
false &&
"LoadInfo::finishedLoadingDep did find an unexpected state");
738 bool unexpectedState =
false;
742 endCallbacks = m_endCallbacks;
743 m_endCallbacks.clear();
745 Q_ASSERT(!unexpectedState &&
"LoadInfo::execEnd found an unexpected state");
751 bool unexpectedState2 =
false;
756 otherCallbacks = m_endCallbacks;
757 m_endCallbacks.clear();
759 Q_ASSERT(!unexpectedState2 &&
"LoadInfo::execEnd found an unexpected state");
760 for (
auto const &
cb : otherCallbacks) {
765 for (
auto const &
cb : endCallbacks) {
772void LoadInfo::doAddDependencies(
const DomItem &self)
776 .error(
tr(
"Uninitialized LoadInfo %1").
arg(self.canonicalPath().toString()))
784 DomItem currentFile =
el.field(Fields::currentItem);
785 QString currentFilePath = currentFile.canonicalFilePath();
788 DomItem currentQmltypesFiles = currentFile.field(Fields::qmltypesFiles);
789 int qEnd = currentQmltypesFiles.indexes();
790 for (
int i = 0;
i < qEnd; ++
i) {
791 DomItem qmltypesRef = currentQmltypesFiles.index(
i);
801 DomItem currentQmlFiles = currentFile.field(Fields::qmlFiles);
802 currentQmlFiles.visitKeys([
this, &self](
const QString &,
const DomItem &els) {
803 return els.visitIndexes([
this, &self](
const DomItem &
el) {
805 Path canonicalPath = ref->referredObjectPath[2];
806 if (canonicalPath && !canonicalPath.headName().isEmpty())
808 Dependency{ QString(), Version(),
809 canonicalPath.headName(), DomType::QmlFile });
815 }
else if (shared_ptr<ModuleIndex> elPtr =
el.ownerAs<
ModuleIndex>()) {
816 const auto qmldirs = elPtr->qmldirsToLoad(
el);
817 for (
const Path &qmldirPath : qmldirs) {
825 addEndCallback(self, [uri, qmldirs](Path,
const DomItem &,
const DomItem &newV) {
826 for (
const Path &
p : qmldirs) {
828 if (std::shared_ptr<QmldirFile> qmldirFilePtr = qmldir.ownerAs<
QmldirFile>()) {
829 qmldirFilePtr->ensureInModuleIndex(qmldir, uri);
835 tr(
"Ignoring dependencies for empty (invalid) type %1")
841 elementCanonicalPath().
toString())));
845void LoadInfo::addDependency(
const DomItem &self,
const Dependency &dep)
847 bool unexpectedState =
false;
850 unexpectedState = m_status != Status::Starting;
853 Q_ASSERT(!unexpectedState &&
"LoadInfo::addDependency found an unexpected state");
855 env.ownerAs<
DomEnvironment>()->addWorkForLoadInfo(elementCanonicalPath());
879Path DomEnvironment::canonicalPath()
const
881 return Path::Root(u
"env");
887 cont = cont && DomTop::iterateDirectSubpaths(self, visitor);
889 cont = cont && self.dvItemField(visitor, Fields::universe, [
this]() {
return universe(); });
890 cont = cont && self.dvValueField(visitor, Fields::options,
int(options()));
891 cont = cont && self.dvItemField(visitor, Fields::base, [
this]() {
return base(); });
893 && self.dvValueLazyField(visitor, Fields::loadPaths, [
this]() {
return loadPaths(); });
894 cont = cont && self.dvValueField(visitor, Fields::globalScopeName, globalScopeName());
895 cont = cont && self.dvItemField(visitor, Fields::globalScopeWithName, [
this, &self]() {
896 return self.subMapItem(
Map(
897 Path::Field(Fields::globalScopeWithName),
899 return map.copy(globalScopeWithName(self,
key));
901 [&self,
this](
const DomItem &) {
return globalScopeNames(self); },
904 cont = cont && self.dvItemField(visitor, Fields::qmlDirectoryWithPath, [
this, &self]() {
905 return self.subMapItem(
Map(
906 Path::Field(Fields::qmlDirectoryWithPath),
908 return map.copy(qmlDirectoryWithPath(self,
key));
910 [&self,
this](
const DomItem &) {
return qmlDirectoryPaths(self); },
913 cont = cont && self.dvItemField(visitor, Fields::qmldirFileWithPath, [
this, &self]() {
914 return self.subMapItem(
Map(
915 Path::Field(Fields::qmldirFileWithPath),
917 return map.copy(qmldirFileWithPath(self,
key));
919 [&self,
this](
const DomItem &) {
return qmldirFilePaths(self); },
922 cont = cont && self.dvItemField(visitor, Fields::qmldirWithPath, [
this, &self]() {
923 return self.subMapItem(
Map(
924 Path::Field(Fields::qmldirWithPath),
926 return map.copy(qmlDirWithPath(self,
key));
930 cont = cont && self.dvItemField(visitor, Fields::qmlFileWithPath, [
this, &self]() {
931 return self.subMapItem(
Map(
932 Path::Field(Fields::qmlFileWithPath),
934 return map.copy(qmlFileWithPath(self,
key));
938 cont = cont && self.dvItemField(visitor, Fields::jsFileWithPath, [
this, &self]() {
939 return self.subMapItem(
Map(
940 Path::Field(Fields::jsFileWithPath),
943 return map.copy(jsFileWithPath(mapOw,
key));
947 return jsFilePaths(mapOw);
951 cont = cont && self.dvItemField(visitor, Fields::qmltypesFileWithPath, [
this, &self]() {
952 return self.subMapItem(
Map(
953 Path::Field(Fields::qmltypesFileWithPath),
956 return map.copy(qmltypesFileWithPath(mapOw,
key));
960 return qmltypesFilePaths(mapOw);
964 cont = cont && self.dvItemField(visitor, Fields::moduleIndexWithUri, [
this, &self]() {
965 return self.subMapItem(
Map(
966 Path::Field(Fields::moduleIndexWithUri),
968 return map.subMapItem(
Map(
972 int i = subKey.toInt(&ok);
974 if (subKey.isEmpty())
975 i = Version::Undefined;
976 else if (subKey.compare(u
"Latest", Qt::CaseInsensitive) == 0)
982 std::shared_ptr<ModuleIndex> mIndex =
983 moduleIndexWithUri(subMapOw,
key,
i);
984 return submap.copy(mIndex);
990 moduleIndexMajorVersions(subMapOw,
key, EnvLookup::Normal))
991 if (mVersion == Version::Undefined)
1003 return moduleIndexUris(mapOw);
1007 bool loadedLoadInfo =
false;
1008 QQueue<Path> loadsWithWork;
1009 QQueue<Path> inProgress;
1010 int nAllLoadedCallbacks;
1011 auto ensureInfo = [&]() {
1012 if (!loadedLoadInfo) {
1014 loadedLoadInfo =
true;
1015 loadsWithWork = m_loadsWithWork;
1016 inProgress = m_inProgress;
1017 nAllLoadedCallbacks = m_allLoadedCallback.size();
1021 && self.dvItemField(
1022 visitor, Fields::loadsWithWork, [&ensureInfo, &self, &loadsWithWork]() {
1024 return self.subListItem(List(
1025 Path::Field(Fields::loadsWithWork),
1027 if (
i >= 0 &&
i < loadsWithWork.size())
1028 return list.subDataItem(PathEls::Index(
i),
1029 loadsWithWork.at(
i).toString());
1033 [loadsWithWork](
const DomItem &) {
1039 &&
self.dvItemField(visitor, Fields::inProgress, [&self, &ensureInfo, &inProgress]() {
1041 return self.subListItem(List(
1042 Path::Field(Fields::inProgress),
1044 if (
i >= 0 &&
i < inProgress.size())
1045 return list.subDataItem(PathEls::Index(
i),
1046 inProgress.at(
i).toString());
1053 cont = cont &&
self.dvItemField(visitor, Fields::loadInfo, [&self,
this]() {
1055 Path::Field(Fields::loadInfo),
1057 bool hasErrors =
false;
1058 Path
p = Path::fromString(pStr, [&hasErrors](
const ErrorMessage &
m) {
1060 case ErrorLevel::Debug:
1061 case ErrorLevel::Info:
1063 case ErrorLevel::Warning:
1064 case ErrorLevel::Error:
1065 case ErrorLevel::Fatal:
1071 return map.copy(loadInfo(
p));
1076 const auto infoPaths = loadInfoPaths();
1077 for (
const Path &
p : infoPaths)
1083 cont = cont &&
self.dvWrapField(visitor, Fields::imports, m_implicitImports);
1085 &&
self.dvValueLazyField(visitor, Fields::nAllLoadedCallbacks,
1086 [&nAllLoadedCallbacks, &ensureInfo]() {
1088 return nAllLoadedCallbacks;
1095 return DomTop::field(self,
name);
1098std::shared_ptr<DomEnvironment> DomEnvironment::makeCopy(
const DomItem &self)
const
1100 return std::static_pointer_cast<DomEnvironment>(doCopy(self));
1103std::shared_ptr<OwningItem> DomEnvironment::doCopy(
const DomItem &)
const
1105 shared_ptr<DomEnvironment>
res;
1107 res = std::make_shared<DomEnvironment>(m_base, m_loadPaths,
m_options,
1108 m_domCreationOptions);
1110 res = std::make_shared<DomEnvironment>(m_loadPaths,
m_options, m_domCreationOptions,
1118 if (options() & DomEnvironment::Option::NoDependencies)
1141void DomEnvironment::loadFile(
const FileToLoad &
file,
const Callback &loadCallback,
1142 const Callback &endCallback, std::optional<DomType>
fileType,
1145 DomItem self(shared_from_this());
1146 if (
file.canonicalPath().isEmpty()) {
1147 if (!
file.content() ||
file.content()->data.isNull()) {
1150 .error(
tr(
"Non existing path to load: '%1'").
arg(
file.logicalPath()))
1161 file.canonicalPath() =
file.logicalPath();
1165 shared_ptr<ExternalItemInfoBase> oldValue, newValue;
1166 const DomType fType =
1169 case DomType::QmlDirectory: {
1170 const auto &fetchResult = fetchFileFromEnvs<QmlDirectory>(
file);
1171 oldValue = fetchResult.first;
1172 newValue = fetchResult.second;
1174 const auto &loadRes = universe()->loadFile(
file, fType, m_domCreationOptions);
1175 addExternalItemInfo<QmlDirectory>(loadRes.currentItem,
1176 getLoadCallbackFor(fType, loadCallback), endCallback);
1180 case DomType::QmlFile: {
1181 const auto &fetchResult = fetchFileFromEnvs<QmlFile>(
file);
1182 oldValue = fetchResult.first;
1183 newValue = fetchResult.second;
1185 const auto &loadRes = universe()->loadFile(
file, fType, m_domCreationOptions);
1186 addExternalItemInfo<QmlFile>(loadRes.currentItem,
1187 getLoadCallbackFor(fType, loadCallback), endCallback);
1191 case DomType::QmltypesFile: {
1192 const auto &fetchResult = fetchFileFromEnvs<QmltypesFile>(
file);
1193 oldValue = fetchResult.first;
1194 newValue = fetchResult.second;
1196 const auto &loadRes = universe()->loadFile(
file, fType, m_domCreationOptions);
1197 addExternalItemInfo<QmltypesFile>(loadRes.currentItem,
1198 getLoadCallbackFor(fType, loadCallback), endCallback);
1202 case DomType::QmldirFile: {
1203 const auto &fetchResult = fetchFileFromEnvs<QmldirFile>(
file);
1204 oldValue = fetchResult.first;
1205 newValue = fetchResult.second;
1207 const auto &loadRes = universe()->loadFile(
file, fType, m_domCreationOptions);
1208 addExternalItemInfo<QmldirFile>(loadRes.currentItem,
1209 getLoadCallbackFor(fType, loadCallback), endCallback);
1213 case DomType::JsFile: {
1214 const auto &loadRes = universe()->loadFile(
file, fType, m_domCreationOptions);
1215 addExternalItemInfo<JsFile>(loadRes.currentItem, getLoadCallbackFor(fType, loadCallback),
1220 myErrors().error(
tr(
"Unexpected file to load: '%1'").
arg(
file.canonicalPath())).handle(
h);
1228 Path
p =
self.copy(newValue).canonicalPath();
1229 std::shared_ptr<LoadInfo> lInfo = loadInfo(
p);
1234 loadCallback(
p, oldValueObj, newValueObj);
1237 self.addError(myErrors().
error(
tr(
"missing load info in ")));
1242 addAllLoadedCallback(self, [
p = std::move(
p), endCallback](
1245 endCallback(
p,
el,
el);
1249void DomEnvironment::loadModuleDependency(
1251 const std::function<
void(
const Path &,
const DomItem &,
const DomItem &)> &callback,
1252 const ErrorHandler &errorHandler)
1254 DomItem envItem(shared_from_this());
1255 if (options() & DomEnvironment::Option::NoDependencies)
1256 loadModuleDependency(envItem, uri, version, callback,
nullptr, errorHandler);
1258 loadModuleDependency(envItem, uri, version,
nullptr, callback, errorHandler);
1262 Callback loadCallback, Callback endCallback,
1263 const ErrorHandler &errorHandler)
1266 Path
p = Paths::moduleIndexPath(uri,
v.majorVersion);
1267 if (
v.majorVersion == Version::Latest) {
1271 bool commonV =
false;
1274 QString subPathV = subPathComponents.join(u
'/');
1277 const auto lPaths = loadPaths();
1278 qCDebug(QQmlJSDomImporting) <<
"DomEnvironment::loadModuleDependency: Searching module with"
1285 for (
const QString &dirNow : eList) {
1286 auto m = vRe.match(dirNow);
1288 int majorV =
m.captured(1).
toInt();
1289 if (majorV > maxV) {
1292 if (fInfo.isFile()) {
1294 <<
"Found qmldir in " << fInfo.canonicalFilePath();
1299 if (!commonV && dirNow == lastComponent) {
1302 if (fInfo.isFile()) {
1304 <<
"Found qmldir in " << fInfo.canonicalFilePath();
1315 int toLoad = (commonV ? 1 : 0) + ((maxV >= 0) ? 1 : 0);
1316 const auto loadCallback2 = loadCallback
1317 ? [
p, loadCallback, toLoad](Path,
const DomItem &,
const DomItem &elV)
mutable {
1318 if (--toLoad == 0) {
1320 loadCallback(
p,
el,
el);
1326 loadModuleDependency(self, uri,
Version(maxV,
v.minorVersion), loadCallback2,
nullptr);
1328 loadModuleDependency(self, uri,
Version(Version::Undefined,
v.minorVersion),
1329 loadCallback2,
nullptr);
1330 else if (maxV < 0) {
1331 if (uri != u
"QML") {
1332 const QString loadPaths = lPaths.join(u
", "_s);
1334 <<
"DomEnvironment::loadModuleDependency: qmldir at" << (uri + u
"/qmldir"_s)
1335 <<
"was not found in " << loadPaths;
1338 .
warning(
tr(
"Failed to find main qmldir file for %1 %2 in %3.")
1339 .
arg(uri,
v.stringValue(), loadPaths))
1346 std::shared_ptr<ModuleIndex> mIndex = moduleIndexWithUri(
1347 self, uri,
v.majorVersion, EnvLookup::Normal, Changeable::Writable, errorHandler);
1348 std::shared_ptr<LoadInfo> lInfo = loadInfo(
p);
1351 lInfo->addEndCallback(lInfoObj, loadCallback);
1354 myErrors().
warning(
tr(
"Missing loadInfo for %1").
arg(
p.toString())).handle());
1360 addAllLoadedCallback(self, [
p = std::move(
p), endCallback = std::move(endCallback)](
1363 endCallback(
p,
el,
el);
1371 const auto lPaths = loadPaths();
1375 if (fInfo.isFile()) {
1376 loadFile(FileToLoad::fromFileSystem(shared_from_this(), fInfo.canonicalFilePath()),
1381 myErrors().error(
tr(
"Could not find builtins.qmltypes file")).handle(
h);
1387 auto toDelete = [
path](
auto it) {
1389 return p.startsWith(
path) && (
p.size() ==
path.size() ||
p.at(
path.size()) == u
'/');
1391 m_qmlDirectoryWithPath.
removeIf(toDelete);
1392 m_qmldirFileWithPath.removeIf(toDelete);
1393 m_qmlFileWithPath.removeIf(toDelete);
1394 m_jsFileWithPath.removeIf(toDelete);
1395 m_qmltypesFileWithPath.removeIf(toDelete);
1398shared_ptr<DomUniverse> DomEnvironment::universe()
const {
1402 return m_base->universe();
1408QSet<QString> DomEnvironment::getStrings(
function_ref<QSet<QString>()> getBase,
1409 const QMap<QString, T> &selfMap,
EnvLookup options)
const
1412 if (options != EnvLookup::NoBase && m_base) {
1416 if (options != EnvLookup::BaseOnly) {
1417 QMap<QString, T>
map;
1435 return this->getStrings<QMap<int, std::shared_ptr<ModuleIndex>>>(
1436 [
this, &baseObj] {
return m_base->moduleIndexUris(baseObj, EnvLookup::Normal); },
1437 m_moduleIndexWithUri, lookup);
1443 if (lookup != EnvLookup::NoBase && m_base) {
1445 res = m_base->moduleIndexMajorVersions(baseObj, uri, EnvLookup::Normal);
1447 if (lookup != EnvLookup::BaseOnly) {
1448 QMap<int, std::shared_ptr<ModuleIndex>>
map;
1451 map = m_moduleIndexWithUri.
value(uri);
1463std::shared_ptr<ModuleIndex> DomEnvironment::lookupModuleInEnv(
const QString &uri,
int majorVersion)
const
1466 auto it = m_moduleIndexWithUri.
find(uri);
1467 if (
it == m_moduleIndexWithUri.
end())
1471 if (majorVersion == Version::Latest)
1474 return it->value(majorVersion);
1477DomEnvironment::ModuleLookupResult DomEnvironment::moduleIndexWithUriHelper(
const DomItem &self,
const QString &uri,
int majorVersion, EnvLookup options)
const
1479 std::shared_ptr<ModuleIndex>
res;
1480 if (options != EnvLookup::BaseOnly)
1481 res = lookupModuleInEnv(uri, majorVersion);
1484 if (options == EnvLookup::NoBase || !m_base)
1485 return {std::move(
res), ModuleLookupResult::FromGlobal };
1486 const std::shared_ptr existingMod =
1487 m_base->moduleIndexWithUri(self, uri, majorVersion, options, Changeable::ReadOnly);
1489 return { std::move(existingMod), ModuleLookupResult::FromBase };
1491 return {std::move(
res), ModuleLookupResult::FromGlobal };
1497 if (majorVersion == Version::Latest) {
1498 if (
res->majorVersion() >= existingMod->majorVersion())
1499 return { std::move(
res), ModuleLookupResult::FromGlobal };
1501 return { std::move(existingMod), ModuleLookupResult::FromBase };
1505 return { std::move(
res), ModuleLookupResult::FromGlobal };
1509std::shared_ptr<ModuleIndex> DomEnvironment::moduleIndexWithUri(
1514 Q_ASSERT((changeable == Changeable::ReadOnly
1515 || (majorVersion >= 0 || majorVersion == Version::Undefined))
1516 &&
"A writeable moduleIndexWithUri call should have a version (not with "
1517 "Version::Latest)");
1518 if (changeable == Changeable::Writable && (
m_options & Option::Exported))
1519 myErrors().error(
tr(
"A mutable module was requested in a multithreaded environment")).handle(errorHandler);
1523 auto [candidate, origin] = moduleIndexWithUriHelper(self, uri, majorVersion, options);
1526 if (candidate && origin == ModuleLookupResult::FromGlobal)
1530 if (changeable == Changeable::ReadOnly)
1534 std::shared_ptr<ModuleIndex> newModulePtr = [&, candidate = candidate](){
1537 return std::make_shared<ModuleIndex>(uri, majorVersion);
1539 DomItem existingModObj = self.copy(candidate);
1540 return candidate->makeCopy(existingModObj);
1543 DomItem newModule = self.copy(newModulePtr);
1544 Path p = newModule.canonicalPath();
1547 auto &modsNow = m_moduleIndexWithUri[uri];
1552 modsNow.
insert(majorVersion, newModulePtr);
1555 auto lInfo = std::make_shared<LoadInfo>(
p);
1556 addLoadInfo(self, lInfo);
1559 .error(
tr(
"Could not get path for newly created ModuleIndex %1 %2")
1562 .handle(errorHandler);
1565 return newModulePtr;
1568std::shared_ptr<ModuleIndex> DomEnvironment::moduleIndexWithUri(
const DomItem &self,
const QString &uri,
1572 return moduleIndexWithUriHelper(self, uri, majorVersion, options).module;
1575std::shared_ptr<ExternalItemInfo<QmlDirectory>>
1578 return lookup<QmlDirectory>(
path, options);
1583 return getStrings<std::shared_ptr<ExternalItemInfo<QmlDirectory>>>(
1586 return m_base->qmlDirectoryPaths(baseObj, EnvLookup::Normal);
1588 m_qmlDirectoryWithPath, options);
1591std::shared_ptr<ExternalItemInfo<QmldirFile>>
1594 return lookup<QmldirFile>(
path, options);
1599 return getStrings<std::shared_ptr<ExternalItemInfo<QmldirFile>>>(
1602 return m_base->qmldirFilePaths(baseObj, EnvLookup::Normal);
1604 m_qmldirFileWithPath, lOptions);
1607std::shared_ptr<ExternalItemInfoBase> DomEnvironment::qmlDirWithPath(
const DomItem &self,
const QString &
path,
1610 if (
auto qmldirFile = qmldirFileWithPath(self,
path +
QLatin1String(
"/qmldir"), options))
1612 return qmlDirectoryWithPath(self,
path, options);
1617 QSet<QString>
res = qmlDirectoryPaths(self, options);
1618 const auto qmldirFiles = qmldirFilePaths(self, options);
1619 for (
const QString &
p : qmldirFiles) {
1620 if (
p.endsWith(u
"/qmldir")) {
1621 res.insert(
p.left(
p.size() - 7));
1624 .warning(
tr(
"Unexpected path not ending with qmldir in qmldirFilePaths: %1")
1632std::shared_ptr<ExternalItemInfo<QmlFile>>
1635 return lookup<QmlFile>(
path, options);
1640 return getStrings<std::shared_ptr<ExternalItemInfo<QmlFile>>>(
1643 return m_base->qmlFilePaths(baseObj, EnvLookup::Normal);
1645 m_qmlFileWithPath, lookup);
1648std::shared_ptr<ExternalItemInfo<JsFile>>
1651 return lookup<JsFile>(
path, options);
1656 return getStrings<std::shared_ptr<ExternalItemInfo<JsFile>>>(
1659 return m_base->jsFilePaths(baseObj, EnvLookup::Normal);
1661 m_jsFileWithPath, lookup);
1664std::shared_ptr<ExternalItemInfo<QmltypesFile>>
1667 return lookup<QmltypesFile>(
path, options);
1672 return getStrings<std::shared_ptr<ExternalItemInfo<QmltypesFile>>>(
1675 return m_base->qmltypesFilePaths(baseObj, EnvLookup::Normal);
1677 m_qmltypesFileWithPath, lookup);
1680std::shared_ptr<ExternalItemInfo<GlobalScope>>
1684 return lookup<GlobalScope>(
name, lookupOptions);
1687std::shared_ptr<ExternalItemInfo<GlobalScope>>
1690 if (
auto current = globalScopeWithName(self,
name, lookupOptions))
1692 if (
auto u = universe()) {
1693 if (
auto newVal = u->ensureGlobalScopeWithName(
name)) {
1694 if (
auto current = newVal->current) {
1696 auto newScope = current->
makeCopy(currentObj);
1697 auto newCopy = std::make_shared<ExternalItemInfo<GlobalScope>>(
1700 if (
auto oldVal = m_globalScopeWithName.value(
name))
1702 m_globalScopeWithName.insert(
name, newCopy);
1707 Q_ASSERT_X(
false,
"DomEnvironment::ensureGlobalScopeWithName",
"could not ensure globalScope");
1714 if (lookupOptions != EnvLookup::NoBase && m_base) {
1717 res = m_base->globalScopeNames(baseObj, EnvLookup::Normal);
1720 if (lookupOptions != EnvLookup::BaseOnly) {
1721 QMap<QString, std::shared_ptr<ExternalItemInfo<GlobalScope>>>
map;
1724 map = m_globalScopeWithName;
1740void DomEnvironment::addDependenciesToLoad(
const Path &
path)
1742 if (options() & Option::NoDependencies) {
1746 const auto loadInfo = std::make_shared<LoadInfo>(
path);
1747 return addLoadInfo(
DomItem(shared_from_this()), loadInfo);
1755void DomEnvironment::addLoadInfo(
const DomItem &self,
const std::shared_ptr<LoadInfo> &loadInfo)
1759 Path p = loadInfo->elementCanonicalPath();
1760 bool addWork = loadInfo->status() != LoadInfo::Status::Done;
1761 std::shared_ptr<LoadInfo> oldVal;
1764 oldVal = m_loadInfos.value(
p);
1765 m_loadInfos.insert(
p, loadInfo);
1767 m_loadsWithWork.enqueue(
p);
1769 if (oldVal && oldVal->status() != LoadInfo::Status::Done) {
1770 self.addError(myErrors()
1771 .
error(
tr(
"addLoadinfo replaces unfinished load info for %1")
1777std::shared_ptr<LoadInfo> DomEnvironment::loadInfo(
const Path &
path)
const
1780 return m_loadInfos.value(
path);
1783QHash<Path, std::shared_ptr<LoadInfo>> DomEnvironment::loadInfos()
const
1789QList<Path> DomEnvironment::loadInfoPaths()
const
1791 auto lInfos = loadInfos();
1792 return lInfos.keys();
1797 if (
fileType == DomType::QmltypesFile) {
1800 if (std::shared_ptr<QmltypesFile> newFilePtr = newFile.ownerAs<
QmltypesFile>())
1801 newFilePtr->ensureInModuleIndex(newFile);
1803 loadCallback(
p, oldV, newV);
1806 return loadCallback;
1810 DomCreationOptions domCreationOptions,
1811 const shared_ptr<DomUniverse> &universe)
1813 m_universe(
DomUniverse::guaranteeUniverse(universe)),
1814 m_loadPaths(loadPaths),
1815 m_implicitImports(defaultImplicitImports()),
1816 m_domCreationOptions(domCreationOptions)
1826DomEnvironment::SemanticAnalysis &DomEnvironment::semanticAnalysis()
1828 if (m_semanticAnalysis)
1829 return *m_semanticAnalysis;
1833 m_semanticAnalysis = SemanticAnalysis(m_loadPaths);
1834 const auto &importer = m_semanticAnalysis->m_importer;
1836 importer->setImportVisitor([self = weak_from_this(),
base = m_base](
1846 std::shared_ptr<DomEnvironment> envPtr;
1854 auto it = envPtr->m_qmlFileWithPath.
constFind(
p.m_logger->fileName());
1855 if (
it == envPtr->m_qmlFileWithPath.
constEnd()) {
1856 qCDebug(domLog) <<
"Import visitor tried to lazily load file \""
1857 <<
p.m_logger->fileName()
1858 <<
"\", but that file was not found in the DomEnvironment. Was this "
1859 "file not discovered by the Dom's dependency loading mechanism?";
1863 envPtr->populateFromQmlFile(MutableDomItem(qmlFile));
1866 return *m_semanticAnalysis;
1869DomEnvironment::SemanticAnalysis::SemanticAnalysis(
const QStringList &loadPaths)
1876void DomEnvironment::SemanticAnalysis::setLoadPaths(
const QStringList &loadPaths)
1906 semanticAnalysis().m_importer->importFile(
file->canonicalFilePath());
1934 addExternalItem(scope, scope->name(),
options);
1938 const DomItem &self,
const shared_ptr<DomEnvironment> &validEnvPtr)
1942 QMap<QString, QMap<int, std::shared_ptr<ModuleIndex>>> my_moduleIndexWithUri;
1943 QMap<QString, std::shared_ptr<ExternalItemInfo<GlobalScope>>> my_globalScopeWithName;
1944 QMap<QString, std::shared_ptr<ExternalItemInfo<QmlDirectory>>> my_qmlDirectoryWithPath;
1945 QMap<QString, std::shared_ptr<ExternalItemInfo<QmldirFile>>> my_qmldirFileWithPath;
1946 QMap<QString, std::shared_ptr<ExternalItemInfo<QmlFile>>> my_qmlFileWithPath;
1947 QMap<QString, std::shared_ptr<ExternalItemInfo<JsFile>>> my_jsFileWithPath;
1948 QMap<QString, std::shared_ptr<ExternalItemInfo<QmltypesFile>>> my_qmltypesFileWithPath;
1949 QHash<Path, std::shared_ptr<LoadInfo>> my_loadInfos;
1952 my_moduleIndexWithUri = m_moduleIndexWithUri;
1953 my_globalScopeWithName = m_globalScopeWithName;
1954 my_qmlDirectoryWithPath = m_qmlDirectoryWithPath;
1955 my_qmldirFileWithPath = m_qmldirFileWithPath;
1956 my_qmlFileWithPath = m_qmlFileWithPath;
1957 my_jsFileWithPath = m_jsFileWithPath;
1958 my_qmltypesFileWithPath = m_qmltypesFileWithPath;
1959 my_loadInfos = m_loadInfos;
1963 m_base->m_semanticAnalysis = m_semanticAnalysis;
1964 m_base->m_globalScopeWithName.insert(my_globalScopeWithName);
1965 m_base->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
1966 m_base->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
1967 m_base->m_qmlFileWithPath.insert(my_qmlFileWithPath);
1968 m_base->m_jsFileWithPath.insert(my_jsFileWithPath);
1969 m_base->m_qmltypesFileWithPath.insert(my_qmltypesFileWithPath);
1970 m_base->m_loadInfos.insert(my_loadInfos);
1972 auto it = my_moduleIndexWithUri.
cbegin();
1973 auto end = my_moduleIndexWithUri.cend();
1975 QMap<int, shared_ptr<ModuleIndex>> &myVersions =
1976 m_base->m_moduleIndexWithUri[
it.key()];
1978 auto end2 =
it.value().
cend();
1979 while (it2 != end2) {
1980 auto oldV = myVersions.value(it2.key());
1981 DomItem it2Obj = self.copy(it2.value());
1982 auto newV = it2.value()->makeCopy(it2Obj);
1983 newV->mergeWith(oldV);
1984 myVersions.
insert(it2.key(), newV);
1992 m_lastValidBase = validEnvPtr;
1993 if (m_lastValidBase) {
1995 m_lastValidBase->mutex());
1996 m_base->m_semanticAnalysis = m_semanticAnalysis;
1997 m_lastValidBase->m_globalScopeWithName.insert(my_globalScopeWithName);
1998 m_lastValidBase->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
1999 m_lastValidBase->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
2000 for (
auto it = my_qmlFileWithPath.
cbegin(),
end = my_qmlFileWithPath.cend();
it !=
end;
2002 if (
it.value() &&
it.value()->current &&
it.value()->current->isValid())
2003 m_lastValidBase->m_qmlFileWithPath.insert(
it.key(),
it.value());
2005 for (
auto it = my_jsFileWithPath.
cbegin(),
end = my_jsFileWithPath.cend();
it !=
end;
2007 if (
it.value() &&
it.value()->current &&
it.value()->current->isValid())
2008 m_lastValidBase->m_jsFileWithPath.insert(
it.key(),
it.value());
2010 m_lastValidBase->m_qmltypesFileWithPath.insert(my_qmltypesFileWithPath);
2011 m_lastValidBase->m_loadInfos.insert(my_loadInfos);
2012 for (
auto it = my_moduleIndexWithUri.
cbegin(),
end = my_moduleIndexWithUri.cend();
2014 QMap<int, shared_ptr<ModuleIndex>> &myVersions =
2015 m_lastValidBase->m_moduleIndexWithUri[
it.key()];
2016 for (
auto it2 =
it.value().
cbegin(), end2 =
it.value().
cend(); it2 != end2; ++it2) {
2017 auto oldV = myVersions.value(it2.key());
2018 DomItem it2Obj = self.copy(it2.value());
2019 auto newV = it2.value()->makeCopy(it2Obj);
2020 newV->mergeWith(oldV);
2021 myVersions.
insert(it2.key(), newV);
2030 DomItem self(shared_from_this());
2033 std::shared_ptr<LoadInfo>
loadInfo;
2036 if (m_loadsWithWork.isEmpty())
2038 elToDo = m_loadsWithWork.dequeue();
2039 m_inProgress.append(elToDo);
2040 loadInfo = m_loadInfos.value(elToDo);
2043 auto cleanup =
qScopeGuard([
this, &elToDo, &self] {
2044 QList<Callback> endCallbacks;
2047 m_inProgress.removeOne(elToDo);
2048 if (m_inProgress.isEmpty() && m_loadsWithWork.isEmpty()) {
2049 endCallbacks = m_allLoadedCallback;
2050 m_allLoadedCallback.
clear();
2053 for (
const Callback &
cb : std::as_const(endCallbacks))
2054 cb(self.canonicalPath(), self, self);
2057 loadInfo->advanceLoad(loadInfoObj);
2059 self.addError(
myErrors().error(u
"DomEnvironment::loadPendingDependencies could not "
2060 u
"find loadInfo listed in m_loadsWithWork"));
2063 m_inProgress.removeOne(elToDo);
2066 &&
"DomEnvironment::loadPendingDependencies could not find loadInfo listed in "
2074 bool hasPendingLoads =
true;
2076 for (
int i = 0;
i < waitMSec / 10 + 2; ++
i) {
2080 auto end = lInfos.cend();
2081 hasPendingLoads =
false;
2084 hasPendingLoads =
true;
2086 if (!hasPendingLoads)
2093#if QT_FEATURE_thread
2097 return !hasPendingLoads;
2103 m_loadsWithWork.enqueue(elementCanonicalPath);
2121 if (m_semanticAnalysis)
2122 m_semanticAnalysis->setLoadPaths(
v);
2134 return m_qmldirFileWithPath.keys();
2139 return m_globalScopeName;
2150 return m_implicitImports;
2156 bool immediate =
false;
2159 if (m_loadsWithWork.isEmpty() && m_inProgress.isEmpty())
2162 m_allLoadedCallback.
append(
c);
2165 c(
Path(), self, self);
2171 m_referenceCache.clear();
2176 if (std::shared_ptr<QmlFile> qmlFilePtr = qmlFile.ownerAs<
QmlFile>()) {
2181 auto setupFile = [&qmlFilePtr, &qmlFile,
this](
auto &&visitor) {
2190 auto &analysis = semanticAnalysis();
2191 auto scope = analysis.m_importer->importFile(qmlFile.canonicalFilePath());
2192 auto v = std::make_unique<QQmlDomAstCreatorWithQQmlJSScope>(scope, qmlFile, &logger,
2193 analysis.m_importer.get());
2194 v->enableLoadFileLazily(
true);
2200 std::make_shared<QQmlJSTypeResolver>(analysis.m_importer.get());
2201 typeResolver->init(&
v->scopeCreator(),
nullptr);
2202 qmlFilePtr->setTypeResolverWithDependencies(typeResolver,
2203 { analysis.m_importer, analysis.m_mapper });
2205 auto v = std::make_unique<QQmlDomAstCreator>(qmlFile);
2206 v->enableScriptExpressions(
2212 qCWarning(domLog) <<
"populateQmlFile called on non qmlFile";
2219 shared_ptr<ExternalOwningItem> current =
currentItem();
2221 return current->canonicalFilePath(currentObj);
2226 if (!self.dvValueLazyField(visitor, Fields::currentRevision,
2227 [
this, &self]() { return currentRevision(self); }))
2229 if (!self.dvValueLazyField(visitor, Fields::lastRevision,
2230 [
this, &self]() { return lastRevision(self); }))
2232 if (!self.dvValueLazyField(visitor, Fields::lastValidRevision,
2233 [
this, &self]() { return lastValidRevision(self); }))
2238 if (!self.dvValueLazyField(visitor, Fields::currentExposedAt,
2252 DomItem lastValue = self.universe()[
p.mid(1,
p.length() - 1)].field(u
"revision");
2253 return static_cast<int>(lastValue.value().toInteger(0));
2259 DomItem lastValidValue = self.universe()[
p.mid(1,
p.length() - 2)].field(u
"validItem").field(u
"revision");
2260 return static_cast<int>(lastValidValue.value().toInteger(0));
2265 shared_ptr<ExternalOwningItem> current =
currentItem();
2266 return current->canonicalFilePath();
2271 shared_ptr<ExternalOwningItem> current =
currentItem();
2272 return current->canonicalPath().dropTail();
2277 if (!self.dvValueLazyField(visitor, Fields::currentIsValid,
2278 [
this]() { return currentIsValid(); }))
2285 if (!self.dvValueField(visitor, Fields::validExposedAt,
validExposedAt))
2287 if (!self.dvValueField(visitor, Fields::currentExposedAt,
currentExposedAt))
2307 <<
el.internalKindStr() <<
el.canonicalPath();
2318 bool didSet =
false;
2352#include "moc_qqmldomtop_p.cpp"