Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qqmldomtop.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmldomitem_p.h"
5#include "qqmldomtop_p.h"
7#include "qqmldommock_p.h"
8#include "qqmldomelements_p.h"
12#include "qqmldom_utils_p.h"
13
14#include <QtQml/private/qqmljslexer_p.h>
15#include <QtQml/private/qqmljsparser_p.h>
16#include <QtQml/private/qqmljsengine_p.h>
17#include <QtQml/private/qqmljsastvisitor_p.h>
18#include <QtQml/private/qqmljsast_p.h>
19
20#include <QtCore/QBasicMutex>
21#include <QtCore/QCborArray>
22#include <QtCore/QDebug>
23#include <QtCore/QDir>
24#include <QtCore/QFile>
25#include <QtCore/QFileInfo>
26#include <QtCore/QPair>
27#include <QtCore/QRegularExpression>
28#include <QtCore/QScopeGuard>
29#if QT_FEATURE_thread
30# include <QtCore/QThread>
31#endif
32
33#include <memory>
34
36
37using namespace Qt::StringLiterals;
38
39namespace QQmlJS {
40namespace Dom {
41
42using std::shared_ptr;
43
44
59{
60 return canonicalPath();
61}
62
64{
65 return DomItem();
66}
67
69{
70 static QHash<QString, QString> knownFields;
71 static QBasicMutex m;
72 auto toField = [](QString f) mutable -> QStringView {
73 QMutexLocker l(&m);
74 if (!knownFields.contains(f))
75 knownFields[f] = f;
76 return knownFields[f];
77 };
78 bool cont = true;
79 auto objs = m_extraOwningItems;
80 auto itO = objs.cbegin();
81 auto endO = objs.cend();
82 while (itO != endO) {
83 cont = cont && self.dvItemField(visitor, toField(itO.key()), [&self, &itO]() {
84 return std::visit([&self](auto &&el) { return self.copy(el); }, *itO);
85 });
86 ++itO;
87 }
88 return cont;
89}
90
91void DomTop::clearExtraOwningItems()
92{
94 m_extraOwningItems.clear();
95}
96
97QMap<QString, OwnerT> DomTop::extraOwningItems() const
98{
100 QMap<QString, OwnerT> res = m_extraOwningItems;
101 return res;
102}
103
118ErrorGroups DomUniverse::myErrors()
119{
120 static ErrorGroups groups = {{ DomItem::domErrorGroup, NewErrorGroup("Universe") }};
121 return groups;
122}
123
124DomUniverse::DomUniverse(QString universeName, Options options):
125 m_name(universeName), m_options(options)
126{}
127
128std::shared_ptr<DomUniverse> DomUniverse::guaranteeUniverse(std::shared_ptr<DomUniverse> univ)
129{
130 const auto next = [] {
131 Q_CONSTINIT static std::atomic<int> counter(0);
132 return counter.fetch_add(1, std::memory_order_relaxed) + 1;
133 };
134 if (univ)
135 return univ;
136
137 return std::make_shared<DomUniverse>(
138 QLatin1String("universe") + QString::number(next()));
139}
140
142{
143 auto res = std::make_shared<DomUniverse>(universeName, options);
144 return DomItem(res);
145}
146
148{
149 return Path::Root(u"universe");
150}
151
153{
154 bool cont = true;
155 cont = cont && DomTop::iterateDirectSubpaths(self, visitor);
156 cont = cont && self.dvValueField(visitor, Fields::name, name());
157 cont = cont && self.dvValueField(visitor, Fields::options, int(options()));
158 cont = cont && self.dvItemField(visitor, Fields::globalScopeWithName, [this, &self]() {
159 return self.subMapItem(Map(
160 Path::Field(Fields::globalScopeWithName),
161 [this](DomItem &map, QString key) { return map.copy(globalScopeWithName(key)); },
162 [this](DomItem &) { return globalScopeNames(); }, QLatin1String("GlobalScope")));
163 });
164 cont = cont && self.dvItemField(visitor, Fields::qmlDirectoryWithPath, [this, &self]() {
165 return self.subMapItem(Map(
166 Path::Field(Fields::qmlDirectoryWithPath),
167 [this](DomItem &map, QString key) { return map.copy(qmlDirectoryWithPath(key)); },
168 [this](DomItem &) { return qmlDirectoryPaths(); }, QLatin1String("QmlDirectory")));
169 });
170 cont = cont && self.dvItemField(visitor, Fields::qmldirFileWithPath, [this, &self]() {
171 return self.subMapItem(Map(
172 Path::Field(Fields::qmldirFileWithPath),
173 [this](DomItem &map, QString key) { return map.copy(qmldirFileWithPath(key)); },
174 [this](DomItem &) { return qmldirFilePaths(); }, QLatin1String("QmldirFile")));
175 });
176 cont = cont && self.dvItemField(visitor, Fields::qmlFileWithPath, [this, &self]() {
177 return self.subMapItem(Map(
178 Path::Field(Fields::qmlFileWithPath),
179 [this](DomItem &map, QString key) { return map.copy(qmlFileWithPath(key)); },
180 [this](DomItem &) { return qmlFilePaths(); }, QLatin1String("QmlFile")));
181 });
182 cont = cont && self.dvItemField(visitor, Fields::jsFileWithPath, [this, &self]() {
183 return self.subMapItem(Map(
184 Path::Field(Fields::jsFileWithPath),
185 [this](DomItem &map, QString key) { return map.copy(jsFileWithPath(key)); },
186 [this](DomItem &) { return jsFilePaths(); }, QLatin1String("JsFile")));
187 });
188 cont = cont && self.dvItemField(visitor, Fields::jsFileWithPath, [this, &self]() {
189 return self.subMapItem(Map(
190 Path::Field(Fields::qmltypesFileWithPath),
191 [this](DomItem &map, QString key) { return map.copy(qmltypesFileWithPath(key)); },
192 [this](DomItem &) { return qmltypesFilePaths(); }, QLatin1String("QmltypesFile")));
193 });
194 cont = cont && self.dvItemField(visitor, Fields::queue, [this, &self]() {
196 return self.subListItem(List(
197 Path::Field(Fields::queue),
198 [q](DomItem &list, index_type i) {
199 if (i >= 0 && i < q.size())
200 return list.subDataItem(PathEls::Index(i), q.at(i).toCbor(),
202 else
203 return DomItem();
204 },
205 [q](DomItem &) { return index_type(q.size()); }, nullptr,
206 QLatin1String("ParsingTask")));
207 });
208 return cont;
209}
210
211std::shared_ptr<OwningItem> DomUniverse::doCopy(DomItem &) const
212{
214 auto m = r.match(m_name);
215 QString newName;
216 if (m.hasMatch())
217 newName = QStringLiteral(u"%1Copy%2").arg(m_name).arg(m.captured(1).toInt() + 1);
218 else
219 newName = m_name + QLatin1String("Copy");
220 auto res = std::make_shared<DomUniverse>(newName);
221 return res;
222}
223
224static DomType fileTypeForPath(DomItem &self, QString canonicalFilePath)
225{
226 if (canonicalFilePath.endsWith(u".qml", Qt::CaseInsensitive)
227 || canonicalFilePath.endsWith(u".qmlannotation", Qt::CaseInsensitive)) {
228 return DomType::QmlFile;
229 } else if (canonicalFilePath.endsWith(u".qmltypes")) {
231 } else if (QStringView(u"qmldir").compare(QFileInfo(canonicalFilePath).fileName(),
233 == 0) {
234 return DomType::QmldirFile;
235 } else if (QFileInfo(canonicalFilePath).isDir()) {
237 } else {
238 self.addError(DomUniverse::myErrors()
239 .error(QCoreApplication::translate("Dom::fileTypeForPath",
240 "Could not detect type of file %1")
241 .arg(canonicalFilePath))
242 .handle());
243 }
244 return DomType::Empty;
245}
246
248 LoadOptions loadOptions, std::optional<DomType> fileType)
249{
250 DomType fType = (bool(fileType) ? (*fileType) : fileTypeForPath(self, file.canonicalPath()));
251 switch (fType) {
252 case DomType::QmlFile:
256 // Protect the queue from concurrent access.
257 QMutexLocker l(mutex());
258 m_queue.enqueue(ParsingTask{ QDateTime::currentDateTimeUtc(), loadOptions, fType, file,
259 self.ownerAs<DomUniverse>(), callback });
260 break;
261 }
262 default:
263 self.addError(myErrors()
264 .error(tr("Ignoring request to load file %1 of unexpected type %2, "
265 "calling callback immediately")
266 .arg(file.canonicalPath(), domTypeToString(fType)))
267 .handle());
268 Q_ASSERT(false && "loading non supported file type");
269 callback(Path(), DomItem::empty, DomItem::empty);
270 return;
271 }
272 if (m_options & Option::SingleThreaded)
273 execQueue(); // immediate execution in the same thread
274}
275
276template<typename T>
277QPair<std::shared_ptr<ExternalItemPair<T>>, std::shared_ptr<ExternalItemPair<T>>>
278updateEntry(DomItem &univ, std::shared_ptr<T> newItem,
279 QMap<QString, std::shared_ptr<ExternalItemPair<T>>> &map, QBasicMutex *mutex)
280{
281 std::shared_ptr<ExternalItemPair<T>> oldValue;
282 std::shared_ptr<ExternalItemPair<T>> newValue;
283 QString canonicalPath = newItem->canonicalFilePath();
285 {
287 auto it = map.find(canonicalPath);
288 if (it != map.cend() && (*it) && (*it)->current) {
289 oldValue = *it;
290 QString oldCode = oldValue->current->code();
291 QString newCode = newItem->code();
292 if (!oldCode.isNull() && !newCode.isNull() && oldCode == newCode) {
293 newValue = oldValue;
294 if (newValue->current->lastDataUpdateAt() < newItem->lastDataUpdateAt())
295 newValue->current->refreshedDataAt(newItem->lastDataUpdateAt());
296 } else if (oldValue->current->lastDataUpdateAt() > newItem->lastDataUpdateAt()) {
297 newValue = oldValue;
298 } else {
299 DomItem oldValueObj = univ.copy(oldValue);
300 newValue = oldValue->makeCopy(oldValueObj);
301 newValue->current = newItem;
302 newValue->currentExposedAt = now;
303 if (newItem->isValid()) {
304 newValue->valid = newItem;
305 newValue->validExposedAt = now;
306 }
307 it = map.insert(it, canonicalPath, newValue);
308 }
309 } else {
310 newValue = std::make_shared<ExternalItemPair<T>>(
311 (newItem->isValid() ? newItem : std::shared_ptr<T>()), newItem, now, now);
312 map.insert(canonicalPath, newValue);
313 }
314 }
315 return qMakePair(oldValue, newValue);
316}
317
319{
321 {
322 // Protect the queue from concurrent access.
323 QMutexLocker l(mutex());
324 if (m_queue.isEmpty())
325 return;
326 t = m_queue.dequeue();
327 }
328 shared_ptr<DomUniverse> topPtr = t.requestingUniverse.lock();
329 QString canonicalPath = t.file.canonicalPath();
330 if (!topPtr) {
331 myErrors()
332 .error(tr("Ignoring callback for loading of %1: universe is not valid anymore")
334 .handle();
335 }
336
337 QString code = t.file.content() ? t.file.content()->data : QString();
338 QDateTime contentDate = t.file.content() ? t.file.content()->date
340
341 bool skipParse = false;
342 DomItem oldValue; // old ExternalItemPair (might be empty, or equal to newValue)
343 DomItem newValue; // current ExternalItemPair
344 DomItem univ = DomItem(topPtr);
345 QVector<ErrorMessage> messages;
346
347 if (t.kind == DomType::QmlFile || t.kind == DomType::QmltypesFile
348 || t.kind == DomType::QmldirFile || t.kind == DomType::QmlDirectory) {
349 auto getValue = [&t, this, &canonicalPath]() -> std::shared_ptr<ExternalItemPairBase> {
350 if (t.kind == DomType::QmlFile)
351 return m_qmlFileWithPath.value(canonicalPath);
352 else if (t.kind == DomType::QmltypesFile)
353 return m_qmlFileWithPath.value(canonicalPath);
354 else if (t.kind == DomType::QmldirFile)
355 return m_qmlFileWithPath.value(canonicalPath);
356 else if (t.kind == DomType::QmlDirectory)
357 return m_qmlDirectoryWithPath.value(canonicalPath);
358 else
359 Q_ASSERT(false);
360 return {};
361 };
362 if (code.isEmpty()) {
365 if (canonicalPath.isEmpty()) {
366 messages.append(myErrors().error(tr("Non existing path %1").arg(canonicalPath)));
367 skipParse = true; // nothing to parse from the non-existing path
368 }
369 {
370 QMutexLocker l(mutex());
371 auto value = getValue();
372 if (!(t.loadOptions & LoadOption::ForceLoad) && value) {
373 // use value also when its path is non-existing
374 if (value && value->currentItem()
375 && (canonicalPath.isEmpty()
376 || path.lastModified() < value->currentItem()->lastDataUpdateAt())) {
377 oldValue = newValue = univ.copy(value);
378 skipParse = true;
379 }
380 }
381 }
382 if (!skipParse) {
383 contentDate = QDateTime::currentDateTimeUtc();
384 if (path.isDir()) {
385 code = QDir(canonicalPath)
387 .join(QLatin1Char('\n'));
388 } else if (!file.open(QIODevice::ReadOnly)) {
389 code = QStringLiteral(u"");
390 messages.append(myErrors().error(tr("Error opening path %1: %2 %3")
393 file.errorString())));
394 } else {
396 file.close();
397 }
398 }
399 }
400 if (!skipParse) {
401 QMutexLocker l(mutex());
402 if (auto value = getValue()) {
403 QString oldCode = value->currentItem()->code();
404 if (value && value->currentItem() && !oldCode.isNull() && oldCode == code) {
405 skipParse = true;
406 newValue = oldValue = univ.copy(value);
407 if (value->currentItem()->lastDataUpdateAt() < contentDate)
408 value->currentItem()->refreshedDataAt(contentDate);
409 }
410 }
411 }
412 if (!skipParse) {
414 if (t.kind == DomType::QmlFile) {
415 auto qmlFile = std::make_shared<QmlFile>(canonicalPath, code, contentDate);
416 std::shared_ptr<DomEnvironment> envPtr;
417 if (auto ptr = t.file.environment().lock())
418 envPtr = std::move(ptr);
419 else
420 envPtr = std::make_shared<DomEnvironment>(
422 envPtr->addQmlFile(qmlFile);
423 DomItem env(envPtr);
424 if (qmlFile->isValid()) {
425 MutableDomItem qmlFileObj(env.copy(qmlFile));
426 createDom(qmlFileObj, t.file.options());
427 } else {
428 QString errs;
429 DomItem qmlFileObj = env.copy(qmlFile);
430 qmlFile->iterateErrors(qmlFileObj, [&errs](DomItem, ErrorMessage m) {
431 errs += m.toString();
432 errs += u"\n";
433 return true;
434 });
435 qCWarning(domLog).noquote().nospace()
436 << "Parsed invalid file " << canonicalPath << errs;
437 }
438 auto change = updateEntry<QmlFile>(univ, qmlFile, m_qmlFileWithPath, mutex());
439 oldValue = univ.copy(change.first);
440 newValue = univ.copy(change.second);
441 } else if (t.kind == DomType::QmltypesFile) {
442 auto qmltypesFile = std::make_shared<QmltypesFile>(
443 canonicalPath, code, contentDate);
444 QmltypesReader reader(univ.copy(qmltypesFile));
445 reader.parse();
446 auto change = updateEntry<QmltypesFile>(univ, qmltypesFile, m_qmltypesFileWithPath,
447 mutex());
448 oldValue = univ.copy(change.first);
449 newValue = univ.copy(change.second);
450 } else if (t.kind == DomType::QmldirFile) {
451 shared_ptr<QmldirFile> qmldirFile =
453 auto change =
454 updateEntry<QmldirFile>(univ, qmldirFile, m_qmldirFileWithPath, mutex());
455 oldValue = univ.copy(change.first);
456 newValue = univ.copy(change.second);
457 } else if (t.kind == DomType::QmlDirectory) {
458 auto qmlDirectory = std::make_shared<QmlDirectory>(
459 canonicalPath, code.split(QLatin1Char('\n')), contentDate);
460 auto change = updateEntry<QmlDirectory>(univ, qmlDirectory, m_qmlDirectoryWithPath,
461 mutex());
462 oldValue = univ.copy(change.first);
463 newValue = univ.copy(change.second);
464 } else {
465 Q_ASSERT(false);
466 }
467 }
468 for (const ErrorMessage &m : messages)
469 newValue.addError(m);
470 // to do: tell observers?
471 // execute callback
472 if (t.callback) {
473 Path p;
474 if (t.kind == DomType::QmlFile)
476 else if (t.kind == DomType::QmltypesFile)
478 else if (t.kind == DomType::QmldirFile)
480 else if (t.kind == DomType::QmlDirectory)
482 else
483 Q_ASSERT(false);
484 t.callback(p, oldValue, newValue);
485 }
486 } else {
487 Q_ASSERT(false && "Unhandled kind in queue");
488 }
489}
490
492{
493 QMutexLocker l(mutex());
494 auto toDelete = [path](auto it) {
495 QString p = it.key();
496 return p.startsWith(path) && (p.size() == path.size() || p.at(path.size()) == u'/');
497 };
498 m_qmlDirectoryWithPath.removeIf(toDelete);
499 m_qmldirFileWithPath.removeIf(toDelete);
500 m_qmlFileWithPath.removeIf(toDelete);
501 m_jsFileWithPath.removeIf(toDelete);
502 m_qmltypesFileWithPath.removeIf(toDelete);
503}
504
505std::shared_ptr<OwningItem> LoadInfo::doCopy(DomItem &self) const
506{
507 auto res = std::make_shared<LoadInfo>(*this);
508 if (res->status() != Status::Done) {
509 res->addErrorLocal(DomEnvironment::myErrors().warning(
510 u"This is a copy of a LoadInfo still in progress, artificially ending it, if you "
511 u"use this you will *not* resume loading"));
513 .warning([&self](Sink sink) {
514 sink(u"Copying an in progress LoadInfo, which is most likely an error (");
515 self.dump(sink);
516 sink(u")");
517 })
518 .handle();
519 QMutexLocker l(res->mutex());
520 res->m_status = Status::Done;
521 res->m_toDo.clear();
522 res->m_inProgress.clear();
523 res->m_endCallbacks.clear();
524 }
525 return res;
526}
527
529{
530 return Path::Root(PathRoot::Env).field(Fields::loadInfo).key(elementCanonicalPath().toString());
531}
532
534{
535 bool cont = OwningItem::iterateDirectSubpaths(self, visitor);
536 cont = cont && self.dvValueField(visitor, Fields::status, int(status()));
537 cont = cont && self.dvValueField(visitor, Fields::nLoaded, nLoaded());
538 cont = cont
539 && self.dvValueField(visitor, Fields::elementCanonicalPath,
541 cont = cont && self.dvValueField(visitor, Fields::nNotdone, nNotDone());
542 cont = cont && self.dvValueField(visitor, Fields::nCallbacks, nCallbacks());
543 return cont;
544}
545
547 std::function<void(Path, DomItem &, DomItem &)> callback)
548{
549 if (!callback)
550 return;
551 {
552 QMutexLocker l(mutex());
553 switch (m_status) {
555 case Status::Starting:
558 m_endCallbacks.append(callback);
559 return;
560 case Status::Done:
561 break;
562 }
563 }
565 DomItem el = self.path(p);
566 callback(p, el, el);
567}
568
570{
571 Status myStatus;
572 Dependency dep;
573 bool depValid = false;
574 {
575 QMutexLocker l(mutex());
576 myStatus = m_status;
577 switch (myStatus) {
579 m_status = Status::Starting;
580 break;
581 case Status::Starting:
583 if (!m_toDo.isEmpty()) {
584 dep = m_toDo.dequeue();
585 m_inProgress.append(dep);
586 depValid = true;
587 }
588 break;
590 case Status::Done:
591 break;
592 }
593 }
594 switch (myStatus) {
597 doAddDependencies(self);
599 {
600 QMutexLocker l(mutex());
601 Q_ASSERT(m_status == Status::Starting);
602 if (m_toDo.isEmpty() && m_inProgress.isEmpty())
603 myStatus = m_status = Status::CallingCallbacks;
604 else
605 myStatus = m_status = Status::InProgress;
606 }
607 if (myStatus == Status::CallingCallbacks)
608 execEnd(self);
609 break;
610 case Status::Starting:
612 if (depValid) {
614 if (!dep.uri.isEmpty()) {
615 self.loadModuleDependency(
616 dep.uri, dep.version,
617 [this, self, dep](Path, DomItem &, DomItem &) mutable {
618 finishedLoadingDep(self, dep);
619 },
620 self.errorHandler());
621 Q_ASSERT(dep.filePath.isEmpty() && "dependency with both uri and file");
622 } else if (!dep.filePath.isEmpty()) {
623 DomItem env = self.environment();
624 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>())
625 envPtr->loadFile(
626 env, FileToLoad::fromFileSystem(envPtr, dep.filePath),
627 [this, self, dep](Path, DomItem &, DomItem &) mutable {
628 finishedLoadingDep(self, dep);
629 },
630 nullptr, nullptr, LoadOption::DefaultLoad, dep.fileType,
631 self.errorHandler());
632 else
633 Q_ASSERT(false && "missing environment");
634 } else {
635 Q_ASSERT(false && "dependency without uri and filePath");
636 }
637 } else {
639 tr("advanceLoad called but found no work, which should never happen")));
640 }
641 break;
643 case Status::Done:
645 "advanceLoad called after work should have been done, which should never happen")));
646 break;
647 }
648}
649
651{
652 bool didRemove = false;
653 bool unexpectedState = false;
654 bool doEnd = false;
655 {
656 QMutexLocker l(mutex());
657 didRemove = m_inProgress.removeOne(d);
658 switch (m_status) {
661 case Status::Done:
662 unexpectedState = true;
663 break;
664 case Status::Starting:
665 break;
667 if (m_toDo.isEmpty() && m_inProgress.isEmpty()) {
668 m_status = Status::CallingCallbacks;
669 doEnd = true;
670 }
671 break;
672 }
673 }
674 if (!didRemove) {
676 sink(u"LoadInfo::finishedLoadingDep did not find its dependency in those inProgress "
677 u"()");
678 self.dump(sink);
679 sink(u")");
680 }));
681 Q_ASSERT(false
682 && "LoadInfo::finishedLoadingDep did not find its dependency in those inProgress");
683 }
684 if (unexpectedState) {
686 sink(u"LoadInfo::finishedLoadingDep found an unexpected state (");
687 self.dump(sink);
688 sink(u")");
689 }));
690 Q_ASSERT(false && "LoadInfo::finishedLoadingDep did find an unexpected state");
691 }
692 if (doEnd)
693 execEnd(self);
694}
695
697{
698 QList<std::function<void(Path, DomItem &, DomItem &)>> endCallbacks;
699 bool unexpectedState = false;
700 {
701 QMutexLocker l(mutex());
702 unexpectedState = m_status != Status::CallingCallbacks;
703 endCallbacks = m_endCallbacks;
704 m_endCallbacks.clear();
705 }
706 Q_ASSERT(!unexpectedState && "LoadInfo::execEnd found an unexpected state");
708 DomItem el = self.path(p);
709 {
710 auto cleanup = qScopeGuard([this, p, &el] {
711 QList<std::function<void(Path, DomItem &, DomItem &)>> otherCallbacks;
712 bool unexpectedState2 = false;
713 {
714 QMutexLocker l(mutex());
715 unexpectedState2 = m_status != Status::CallingCallbacks;
716 m_status = Status::Done;
717 otherCallbacks = m_endCallbacks;
718 m_endCallbacks.clear();
719 }
720 Q_ASSERT(!unexpectedState2 && "LoadInfo::execEnd found an unexpected state");
721 for (auto const &cb : otherCallbacks) {
722 if (cb)
723 cb(p, el, el);
724 }
725 });
726 for (auto const &cb : endCallbacks) {
727 if (cb)
728 cb(p, el, el);
729 }
730 }
731}
732
733void LoadInfo::doAddDependencies(DomItem &self)
734{
735 if (!elementCanonicalPath()) {
737 .error(tr("Uninitialized LoadInfo %1").arg(self.canonicalPath().toString()))
738 .handle(nullptr);
739 Q_ASSERT(false);
740 return;
741 }
742 // sychronous add of all dependencies
743 DomItem el = self.path(elementCanonicalPath());
744 if (el.internalKind() == DomType::ExternalItemInfo) {
745 DomItem currentFile = el.field(Fields::currentItem);
746 DomItem currentImports = currentFile.field(Fields::imports);
747 QString currentFilePath = currentFile.canonicalFilePath();
748 int iEnd = currentImports.indexes();
749 for (int i = 0; i < iEnd; ++i) {
750 DomItem import = currentImports.index(i);
751 if (const Import *importPtr = import.as<Import>()) {
752 if (importPtr->uri.isDirectory()) {
753 QString path = importPtr->uri.absoluteLocalPath(currentFilePath);
754 if (!path.isEmpty()) {
755 addDependency(self,
756 Dependency { QString(), importPtr->version, path,
758 } else {
760 tr("Ignoring dependencies for non resolved path import %1")
761 .arg(importPtr->uri.toString())));
762 }
763 } else {
764 addDependency(self,
765 Dependency { importPtr->uri.moduleUri(), importPtr->version,
767 }
768 }
769 }
770 DomItem currentQmltypesFiles = currentFile.field(Fields::qmltypesFiles);
771 int qEnd = currentQmltypesFiles.indexes();
772 for (int i = 0; i < qEnd; ++i) {
773 DomItem qmltypesRef = currentQmltypesFiles.index(i);
774 if (const Reference *ref = qmltypesRef.as<Reference>()) {
775 Path canonicalPath = ref->referredObjectPath[2];
777 addDependency(self,
778 Dependency { QString(), Version(), canonicalPath.headName(),
780 }
781 }
782 DomItem currentQmlFiles = currentFile.field(Fields::qmlFiles);
783 currentQmlFiles.visitKeys([this, &self](QString, DomItem &els) {
784 return els.visitIndexes([this, &self](DomItem &el) {
785 if (const Reference *ref = el.as<Reference>()) {
786 Path canonicalPath = ref->referredObjectPath[2];
787 if (canonicalPath && !canonicalPath.headName().isEmpty())
788 addDependency(self,
789 Dependency { QString(), Version(), canonicalPath.headName(),
790 DomType::QmlFile });
791 }
792 return true;
793 });
794 });
795 } else if (shared_ptr<ModuleIndex> elPtr = el.ownerAs<ModuleIndex>()) {
796 const auto qmldirs = elPtr->qmldirsToLoad(el);
797 for (const Path &qmldirPath : qmldirs) {
798 Path canonicalPath = qmldirPath[2];
799 if (canonicalPath && !canonicalPath.headName().isEmpty())
800 addDependency(self,
801 Dependency { QString(), Version(), canonicalPath.headName(),
803 }
804 QString uri = elPtr->uri();
805 addEndCallback(self, [uri, qmldirs](Path, DomItem &, DomItem &newV) {
806 for (const Path &p : qmldirs) {
807 DomItem qmldir = newV.path(p);
808 if (std::shared_ptr<QmldirFile> qmldirFilePtr = qmldir.ownerAs<QmldirFile>()) {
809 qmldirFilePtr->ensureInModuleIndex(qmldir, uri);
810 }
811 }
812 });
813 } else if (!el) {
815 tr("Ignoring dependencies for empty (invalid) type %1")
816 .arg(domTypeToString(el.internalKind()))));
817 } else {
818 self.addError(
819 DomEnvironment::myErrors().error(tr("dependencies of %1 (%2) not yet implemented")
820 .arg(domTypeToString(el.internalKind()),
821 elementCanonicalPath().toString())));
822 }
823}
824
825void LoadInfo::addDependency(DomItem &self, const Dependency &dep)
826{
827 bool unexpectedState = false;
828 {
829 QMutexLocker l(mutex());
830 unexpectedState = m_status != Status::Starting;
831 m_toDo.enqueue(dep);
832 }
833 Q_ASSERT(!unexpectedState && "LoadInfo::addDependency found an unexpected state");
834 DomItem env = self.environment();
835 env.ownerAs<DomEnvironment>()->addWorkForLoadInfo(elementCanonicalPath());
836}
837
844template<typename T>
846 DomItem &self, QMap<QString, std::shared_ptr<ExternalItemInfo<T>>> DomEnvironment::*map,
847 std::shared_ptr<ExternalItemInfo<T>> (DomEnvironment::*lookupF)(DomItem &, QString,
848 EnvLookup) const,
849 DomTop::Callback loadCallback, DomTop::Callback allDirectDepsCallback,
850 DomTop::Callback endCallback)
851{
852 std::shared_ptr<DomEnvironment> ePtr = self.ownerAs<DomEnvironment>();
853 std::weak_ptr<DomEnvironment> selfPtr = ePtr;
854 std::shared_ptr<DomEnvironment> basePtr = ePtr->base();
855 return [selfPtr, basePtr, map, lookupF, loadCallback, allDirectDepsCallback,
856 endCallback](Path, DomItem &, DomItem &newItem) {
857 shared_ptr<DomEnvironment> envPtr = selfPtr.lock();
858 if (!envPtr)
859 return;
860 DomItem env = DomItem(envPtr);
861 shared_ptr<ExternalItemInfo<T>> oldValue;
862 shared_ptr<ExternalItemInfo<T>> newValue;
863 shared_ptr<T> newItemPtr;
864 if (envPtr->options() & DomEnvironment::Option::KeepValid)
865 newItemPtr = newItem.field(Fields::validItem).ownerAs<T>();
866 if (!newItemPtr)
867 newItemPtr = newItem.field(Fields::currentItem).ownerAs<T>();
868 Q_ASSERT(newItemPtr && "callbackForQmlFile reached without current qmlFile");
869 {
870 QMutexLocker l(envPtr->mutex());
871 oldValue = ((*envPtr).*map).value(newItem.canonicalFilePath());
872 }
873 if (oldValue) {
874 // we do not change locally loaded files (avoid loading a file more than once)
875 newValue = oldValue;
876 } else {
877 if (basePtr) {
878 DomItem baseObj(basePtr);
879 oldValue = ((*basePtr).*lookupF)(baseObj, newItem.canonicalFilePath(),
880 EnvLookup::BaseOnly);
881 }
882 if (oldValue) {
883 DomItem oldValueObj = env.copy(oldValue);
884 newValue = oldValue->makeCopy(oldValueObj);
885 if (newValue->current != newItemPtr) {
886 newValue->current = newItemPtr;
887 newValue->setCurrentExposedAt(QDateTime::currentDateTimeUtc());
888 }
889 } else {
890 newValue = std::make_shared<ExternalItemInfo<T>>(
891 newItemPtr, QDateTime::currentDateTimeUtc());
892 }
893 {
894 QMutexLocker l(envPtr->mutex());
895 auto value = ((*envPtr).*map).value(newItem.canonicalFilePath());
896 if (value) {
897 oldValue = newValue = value;
898 } else {
899 ((*envPtr).*map).insert(newItem.canonicalFilePath(), newValue);
900 }
901 }
902 }
903 Path p = env.copy(newValue).canonicalPath();
904 {
905 auto depLoad = qScopeGuard([p, &env, envPtr, allDirectDepsCallback, endCallback] {
906 if (!(envPtr->options() & DomEnvironment::Option::NoDependencies)) {
907 auto loadInfo = std::make_shared<LoadInfo>(p);
908 if (!p)
909 Q_ASSERT(false);
910 DomItem loadInfoObj = env.copy(loadInfo);
911 loadInfo->addEndCallback(loadInfoObj, allDirectDepsCallback);
912 envPtr->addLoadInfo(env, loadInfo);
913 }
914 if (endCallback)
915 envPtr->addAllLoadedCallback(env,
916 [p, endCallback](Path, DomItem &, DomItem &env) {
917 DomItem el = env.path(p);
918 endCallback(p, el, el);
919 });
920 });
921 if (loadCallback) {
922 DomItem oldValueObj = env.copy(oldValue);
923 DomItem newValueObj = env.copy(newValue);
924 loadCallback(p, oldValueObj, newValueObj);
925 }
926 if ((envPtr->options() & DomEnvironment::Option::NoDependencies)
927 && allDirectDepsCallback) {
928 DomItem oldValueObj = env.copy(oldValue);
929 DomItem newValueObj = env.copy(newValue);
930 env.addError(DomEnvironment::myErrors().warning(
931 QLatin1String("calling allDirectDepsCallback immediately for load with "
932 "NoDependencies of %1")
933 .arg(newItem.canonicalFilePath())));
934 allDirectDepsCallback(p, oldValueObj, newValueObj);
935 }
936 }
937 };
938}
939
940ErrorGroups DomEnvironment::myErrors() {
941 static ErrorGroups res = {{NewErrorGroup("Dom")}};
942 return res;
943}
944
945DomType DomEnvironment::kind() const
946{
947 return kindValue;
948}
949
950Path DomEnvironment::canonicalPath() const
951{
952 return Path::Root(u"env");
953}
954
955bool DomEnvironment::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
956{
957 bool cont = true;
958 cont = cont && DomTop::iterateDirectSubpaths(self, visitor);
959 DomItem univ = universe();
960 cont = cont && self.dvItemField(visitor, Fields::universe, [this]() { return universe(); });
961 cont = cont && self.dvValueField(visitor, Fields::options, int(options()));
962 cont = cont && self.dvItemField(visitor, Fields::base, [this]() { return base(); });
963 cont = cont
964 && self.dvValueLazyField(visitor, Fields::loadPaths, [this]() { return loadPaths(); });
965 cont = cont && self.dvValueField(visitor, Fields::globalScopeName, globalScopeName());
966 cont = cont && self.dvItemField(visitor, Fields::globalScopeWithName, [this, &self]() {
967 return self.subMapItem(Map(
968 Path::Field(Fields::globalScopeWithName),
969 [&self, this](DomItem &map, QString key) {
970 return map.copy(globalScopeWithName(self, key));
971 },
972 [&self, this](DomItem &) { return globalScopeNames(self); },
973 QLatin1String("GlobalScope")));
974 });
975 cont = cont && self.dvItemField(visitor, Fields::qmlDirectoryWithPath, [this, &self]() {
976 return self.subMapItem(Map(
977 Path::Field(Fields::qmlDirectoryWithPath),
978 [&self, this](DomItem &map, QString key) {
979 return map.copy(qmlDirectoryWithPath(self, key));
980 },
981 [&self, this](DomItem &) { return qmlDirectoryPaths(self); },
982 QLatin1String("QmlDirectory")));
983 });
984 cont = cont && self.dvItemField(visitor, Fields::qmldirFileWithPath, [this, &self]() {
985 return self.subMapItem(Map(
986 Path::Field(Fields::qmldirFileWithPath),
987 [&self, this](DomItem &map, QString key) {
988 return map.copy(qmldirFileWithPath(self, key));
989 },
990 [&self, this](DomItem &) { return qmldirFilePaths(self); },
991 QLatin1String("QmldirFile")));
992 });
993 cont = cont && self.dvItemField(visitor, Fields::qmldirWithPath, [this, &self]() {
994 return self.subMapItem(Map(
995 Path::Field(Fields::qmldirWithPath),
996 [&self, this](DomItem &map, QString key) {
997 return map.copy(qmlDirWithPath(self, key));
998 },
999 [&self, this](DomItem &) { return qmlDirPaths(self); }, QLatin1String("Qmldir")));
1000 });
1001 cont = cont && self.dvItemField(visitor, Fields::qmlFileWithPath, [this, &self]() {
1002 return self.subMapItem(Map(
1003 Path::Field(Fields::qmlFileWithPath),
1004 [&self, this](DomItem &map, QString key) {
1005 return map.copy(qmlFileWithPath(self, key));
1006 },
1007 [&self, this](DomItem &) { return qmlFilePaths(self); }, QLatin1String("QmlFile")));
1008 });
1009 cont = cont && self.dvItemField(visitor, Fields::jsFileWithPath, [this, &self]() {
1010 return self.subMapItem(Map(
1011 Path::Field(Fields::jsFileWithPath),
1012 [this](DomItem &map, QString key) {
1013 DomItem mapOw(map.owner());
1014 return map.copy(jsFileWithPath(mapOw, key));
1015 },
1016 [this](DomItem &map) {
1017 DomItem mapOw = map.owner();
1018 return jsFilePaths(mapOw);
1019 },
1020 QLatin1String("JsFile")));
1021 });
1022 cont = cont && self.dvItemField(visitor, Fields::qmltypesFileWithPath, [this, &self]() {
1023 return self.subMapItem(Map(
1024 Path::Field(Fields::qmltypesFileWithPath),
1025 [this](DomItem &map, QString key) {
1026 DomItem mapOw = map.owner();
1027 return map.copy(qmltypesFileWithPath(mapOw, key));
1028 },
1029 [this](DomItem &map) {
1030 DomItem mapOw = map.owner();
1031 return qmltypesFilePaths(mapOw);
1032 },
1033 QLatin1String("QmltypesFile")));
1034 });
1035 cont = cont && self.dvItemField(visitor, Fields::moduleIndexWithUri, [this, &self]() {
1036 return self.subMapItem(Map(
1037 Path::Field(Fields::moduleIndexWithUri),
1038 [this](DomItem &map, QString key) {
1039 return map.subMapItem(Map(
1040 map.pathFromOwner().key(key),
1041 [this, key](DomItem &submap, QString subKey) {
1042 bool ok;
1043 int i = subKey.toInt(&ok);
1044 if (!ok) {
1045 if (subKey.isEmpty())
1046 i = Version::Undefined;
1047 else if (subKey.compare(u"Latest", Qt::CaseInsensitive) == 0)
1048 i = Version::Latest;
1049 else
1050 return DomItem();
1051 }
1052 DomItem subMapOw = submap.owner();
1053 std::shared_ptr<ModuleIndex> mIndex =
1054 moduleIndexWithUri(subMapOw, key, i);
1055 return submap.copy(mIndex);
1056 },
1057 [this, key](DomItem &subMap) {
1059 DomItem subMapOw = subMap.owner();
1060 for (int mVersion :
1061 moduleIndexMajorVersions(subMapOw, key, EnvLookup::Normal))
1062 if (mVersion == Version::Undefined)
1063 res.insert(QString());
1064 else
1065 res.insert(QString::number(mVersion));
1066 if (!res.isEmpty())
1067 res.insert(QLatin1String("Latest"));
1068 return res;
1069 },
1070 QLatin1String("ModuleIndex")));
1071 },
1072 [this](DomItem &map) {
1073 DomItem mapOw = map.owner();
1074 return moduleIndexUris(mapOw);
1075 },
1076 QLatin1String("Map<ModuleIndex>")));
1077 });
1078 bool loadedLoadInfo = false;
1079 QQueue<Path> loadsWithWork;
1080 QQueue<Path> inProgress;
1081 int nAllLoadedCallbacks;
1082 auto ensureInfo = [&]() {
1083 if (!loadedLoadInfo) {
1084 QMutexLocker l(mutex());
1085 loadedLoadInfo = true;
1086 loadsWithWork = m_loadsWithWork;
1087 inProgress = m_inProgress;
1088 nAllLoadedCallbacks = m_allLoadedCallback.size();
1089 }
1090 };
1091 cont = cont
1092 && self.dvItemField(
1093 visitor, Fields::loadsWithWork, [&ensureInfo, &self, &loadsWithWork]() {
1094 ensureInfo();
1095 return self.subListItem(List(
1096 Path::Field(Fields::loadsWithWork),
1097 [loadsWithWork](DomItem &list, index_type i) {
1098 if (i >= 0 && i < loadsWithWork.size())
1099 return list.subDataItem(PathEls::Index(i),
1100 loadsWithWork.at(i).toString());
1101 else
1102 return DomItem();
1103 },
1104 [loadsWithWork](DomItem &) {
1105 return index_type(loadsWithWork.size());
1106 },
1107 nullptr, QLatin1String("Path")));
1108 });
1109 cont = cont
1110 && self.dvItemField(visitor, Fields::inProgress, [&self, &ensureInfo, &inProgress]() {
1111 ensureInfo();
1112 return self.subListItem(List(
1113 Path::Field(Fields::inProgress),
1114 [inProgress](DomItem &list, index_type i) {
1115 if (i >= 0 && i < inProgress.size())
1116 return list.subDataItem(PathEls::Index(i),
1117 inProgress.at(i).toString());
1118 else
1119 return DomItem();
1120 },
1121 [inProgress](DomItem &) { return index_type(inProgress.size()); },
1122 nullptr, QLatin1String("Path")));
1123 });
1124 cont = cont && self.dvItemField(visitor, Fields::loadInfo, [&self, this]() {
1125 return self.subMapItem(Map(
1126 Path::Field(Fields::loadInfo),
1127 [this](DomItem &map, QString pStr) {
1128 bool hasErrors = false;
1129 Path p = Path::fromString(pStr, [&hasErrors](ErrorMessage m) {
1130 switch (m.level) {
1131 case ErrorLevel::Debug:
1132 case ErrorLevel::Info:
1133 break;
1134 case ErrorLevel::Warning:
1135 case ErrorLevel::Error:
1136 case ErrorLevel::Fatal:
1137 hasErrors = true;
1138 break;
1139 }
1140 });
1141 if (!hasErrors)
1142 return map.copy(loadInfo(p));
1143 return DomItem();
1144 },
1145 [this](DomItem &) {
1147 const auto infoPaths = loadInfoPaths();
1148 for (const Path &p : infoPaths)
1149 res.insert(p.toString());
1150 return res;
1151 },
1152 QLatin1String("LoadInfo")));
1153 });
1154 cont = cont && self.dvWrapField(visitor, Fields::imports, m_implicitImports);
1155 cont = cont
1156 && self.dvValueLazyField(visitor, Fields::nAllLoadedCallbacks,
1157 [&nAllLoadedCallbacks, &ensureInfo]() {
1158 ensureInfo();
1159 return nAllLoadedCallbacks;
1160 });
1161 return cont;
1162}
1163
1164DomItem DomEnvironment::field(DomItem &self, QStringView name) const
1165{
1166 return DomTop::field(self, name);
1167}
1168
1169std::shared_ptr<DomEnvironment> DomEnvironment::makeCopy(DomItem &self) const
1170{
1171 return std::static_pointer_cast<DomEnvironment>(doCopy(self));
1172}
1173
1174std::shared_ptr<OwningItem> DomEnvironment::doCopy(DomItem &) const
1175{
1176 shared_ptr<DomEnvironment> res;
1177 if (m_base)
1178 res = std::make_shared<DomEnvironment>(m_base, m_loadPaths, m_options);
1179 else
1180 res = std::make_shared<DomEnvironment>(
1181 m_loadPaths, m_options, m_universe);
1182 return res;
1183}
1184
1185void DomEnvironment::loadFile(DomItem &self, FileToLoad file, Callback loadCallback,
1186 Callback directDepsCallback, Callback endCallback,
1187 LoadOptions loadOptions, std::optional<DomType> fileType,
1189{
1190 if (file.canonicalPath().isEmpty()) {
1191 if (!file.content() || file.content()->data.isNull()) {
1192 // file's content inavailable and no path to retrieve it
1193 myErrors()
1194 .error(tr("Non existing path to load: '%1'").arg(file.logicalPath()))
1195 .handle(h);
1196 if (loadCallback)
1197 loadCallback(Path(), DomItem::empty, DomItem::empty);
1198 if (directDepsCallback)
1199 directDepsCallback(Path(), DomItem::empty, DomItem::empty);
1200 if (endCallback)
1201 addAllLoadedCallback(self, [endCallback](Path, DomItem &, DomItem &) {
1202 endCallback(Path(), DomItem::empty, DomItem::empty);
1203 });
1204 return;
1205 } else {
1206 // fallback: path invalid but file's content is already available.
1207 file.canonicalPath() = file.logicalPath();
1208 }
1209 }
1210
1211 shared_ptr<ExternalItemInfoBase> oldValue, newValue;
1212 const DomType fType =
1213 (bool(fileType) ? (*fileType) : fileTypeForPath(self, file.canonicalPath()));
1214 switch (fType) {
1215 case DomType::QmlDirectory: {
1216 {
1217 QMutexLocker l(mutex());
1218 auto it = m_qmlDirectoryWithPath.find(file.canonicalPath());
1219 if (it != m_qmlDirectoryWithPath.end())
1220 oldValue = newValue = *it;
1221 }
1222 if (!newValue && (options() & Option::NoReload) && m_base) {
1223 if (auto v = m_base->qmlDirectoryWithPath(self, file.canonicalPath(),
1224 EnvLookup::Normal)) {
1225 oldValue = v;
1227 auto newV = std::make_shared<ExternalItemInfo<QmlDirectory>>(
1228 v->current, now, v->revision(), v->lastDataUpdateAt());
1229 newValue = newV;
1230 QMutexLocker l(mutex());
1231 auto it = m_qmlDirectoryWithPath.find(file.canonicalPath());
1232 if (it != m_qmlDirectoryWithPath.end())
1233 oldValue = newValue = *it;
1234 else
1235 m_qmlDirectoryWithPath.insert(file.canonicalPath(), newV);
1236 }
1237 }
1238 if (!newValue) {
1239 self.universe().loadFile(
1240 file,
1241 callbackForQmlDirectory(self, loadCallback, directDepsCallback, endCallback),
1242 loadOptions, fType);
1243 return;
1244 }
1245 } break;
1246 case DomType::QmlFile: {
1247 {
1248 QMutexLocker l(mutex());
1249 auto it = m_qmlFileWithPath.find(file.canonicalPath());
1250 if (it != m_qmlFileWithPath.end())
1251 oldValue = newValue = *it;
1252 }
1253 if (!newValue && (options() & Option::NoReload) && m_base) {
1254 if (auto v = m_base->qmlFileWithPath(self, file.canonicalPath(), EnvLookup::Normal)) {
1255 oldValue = v;
1257 auto newV = std::make_shared<ExternalItemInfo<QmlFile>>(
1258 v->current, now, v->revision(), v->lastDataUpdateAt());
1259 newValue = newV;
1260 QMutexLocker l(mutex());
1261 auto it = m_qmlFileWithPath.find(file.canonicalPath());
1262 if (it != m_qmlFileWithPath.end())
1263 oldValue = newValue = *it;
1264 else
1265 m_qmlFileWithPath.insert(file.canonicalPath(), newV);
1266 }
1267 }
1268 if (!newValue) {
1269 self.universe().loadFile(
1270 file, callbackForQmlFile(self, loadCallback, directDepsCallback, endCallback),
1271 loadOptions, fType);
1272 return;
1273 }
1274 } break;
1275 case DomType::QmltypesFile: {
1276 {
1277 QMutexLocker l(mutex());
1278 auto it = m_qmltypesFileWithPath.find(file.canonicalPath());
1279 if (it != m_qmltypesFileWithPath.end())
1280 oldValue = newValue = *it;
1281 }
1282 if (!newValue && (options() & Option::NoReload) && m_base) {
1283 if (auto v = m_base->qmltypesFileWithPath(self, file.canonicalPath(),
1284 EnvLookup::Normal)) {
1285 oldValue = v;
1287 auto newV = std::make_shared<ExternalItemInfo<QmltypesFile>>(
1288 v->current, now, v->revision(), v->lastDataUpdateAt());
1289 newValue = newV;
1290 QMutexLocker l(mutex());
1291 auto it = m_qmltypesFileWithPath.find(file.canonicalPath());
1292 if (it != m_qmltypesFileWithPath.end())
1293 oldValue = newValue = *it;
1294 else
1295 m_qmltypesFileWithPath.insert(file.canonicalPath(), newV);
1296 }
1297 }
1298 if (!newValue) {
1299 self.universe().loadFile(
1300 file,
1301 callbackForQmltypesFile(self, loadCallback, directDepsCallback, endCallback),
1302 loadOptions, fType);
1303 return;
1304 }
1305 } break;
1306 case DomType::QmldirFile: {
1307 {
1308 QMutexLocker l(mutex());
1309 auto it = m_qmldirFileWithPath.find(file.canonicalPath());
1310 if (it != m_qmldirFileWithPath.end())
1311 oldValue = newValue = *it;
1312 }
1313 if (!newValue && (options() & Option::NoReload) && m_base) {
1314 if (auto v =
1315 m_base->qmldirFileWithPath(self, file.canonicalPath(), EnvLookup::Normal)) {
1316 oldValue = v;
1318 auto newV = std::make_shared<ExternalItemInfo<QmldirFile>>(
1319 v->current, now, v->revision(), v->lastDataUpdateAt());
1320 newValue = newV;
1321 QMutexLocker l(mutex());
1322 auto it = m_qmldirFileWithPath.find(file.canonicalPath());
1323 if (it != m_qmldirFileWithPath.end())
1324 oldValue = newValue = *it;
1325 else
1326 m_qmldirFileWithPath.insert(file.canonicalPath(), newV);
1327 }
1328 }
1329 if (!newValue) {
1330 self.universe().loadFile(
1331 file,
1332 callbackForQmldirFile(self, loadCallback, directDepsCallback, endCallback),
1333 loadOptions, fType);
1334 return;
1335 }
1336 } break;
1337 default: {
1338 myErrors().error(tr("Unexpected file to load: '%1'").arg(file.canonicalPath())).handle(h);
1339 if (loadCallback)
1340 loadCallback(self.canonicalPath(), DomItem::empty, DomItem::empty);
1341 if (directDepsCallback)
1342 directDepsCallback(self.canonicalPath(), DomItem::empty, DomItem::empty);
1343 if (endCallback)
1344 endCallback(self.canonicalPath(), DomItem::empty, DomItem::empty);
1345 return;
1346 } break;
1347 }
1348 Path p = self.copy(newValue).canonicalPath();
1349 std::shared_ptr<LoadInfo> lInfo = loadInfo(p);
1350 if (lInfo) {
1351 if (loadCallback) {
1352 DomItem oldValueObj = self.copy(oldValue);
1353 DomItem newValueObj = self.copy(newValue);
1354 loadCallback(p, oldValueObj, newValueObj);
1355 }
1356 if (directDepsCallback) {
1357 DomItem lInfoObj = self.copy(lInfo);
1358 lInfo->addEndCallback(lInfoObj, directDepsCallback);
1359 }
1360 } else {
1361 self.addError(myErrors().error(tr("missing load info in ")));
1362 if (loadCallback)
1363 loadCallback(self.canonicalPath(), DomItem::empty, DomItem::empty);
1364 if (directDepsCallback)
1365 directDepsCallback(self.canonicalPath(), DomItem::empty, DomItem::empty);
1366 }
1367 if (endCallback)
1368 addAllLoadedCallback(self, [p, endCallback](Path, DomItem &, DomItem &env) {
1369 DomItem el = env.path(p);
1370 endCallback(p, el, el);
1371 });
1372}
1373
1374void DomEnvironment::loadModuleDependency(DomItem &self, QString uri, Version v,
1375 Callback loadCallback, Callback endCallback,
1376 ErrorHandler errorHandler)
1377{
1378 Q_ASSERT(!uri.contains(u'/'));
1379 Path p = Paths::moduleIndexPath(uri, v.majorVersion);
1380 if (v.majorVersion == Version::Latest) {
1381 // load both the latest .<version> directory, and the common one
1382 QStringList subPathComponents = uri.split(QLatin1Char('.'));
1383 int maxV = -1;
1384 bool commonV = false;
1385 QString lastComponent = subPathComponents.last();
1386 subPathComponents.removeLast();
1387 QString subPathV = subPathComponents.join(u'/');
1389 QRegularExpression::escape(lastComponent) + QStringLiteral(u"\\.([0-9]*)")));
1390 const auto lPaths = loadPaths();
1391 for (const QString &path : lPaths) {
1392 QDir dir(path + (subPathV.isEmpty() ? QStringLiteral(u"") : QStringLiteral(u"/"))
1393 + subPathV);
1394 const auto eList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
1395 for (const QString &dirNow : eList) {
1396 auto m = vRe.match(dirNow);
1397 if (m.hasMatch()) {
1398 int majorV = m.captured(1).toInt();
1399 if (majorV > maxV) {
1400 QFileInfo fInfo(dir.canonicalPath() + QChar(u'/') + dirNow
1401 + QStringLiteral(u"/qmldir"));
1402 if (fInfo.isFile())
1403 maxV = majorV;
1404 }
1405 }
1406 if (!commonV && dirNow == lastComponent) {
1407 QFileInfo fInfo(dir.canonicalPath() + QChar(u'/') + dirNow
1408 + QStringLiteral(u"/qmldir"));
1409 if (fInfo.isFile())
1410 commonV = true;
1411 }
1412 }
1413 }
1414 QAtomicInt toLoad((commonV ? 1 : 0) + ((maxV >= 0) ? 1 : 0));
1415 auto loadCallback2 = (loadCallback ? [p, loadCallback, toLoad](Path, DomItem &, DomItem &elV) mutable {
1416 if (--toLoad == 0) {
1417 DomItem el = elV.path(p);
1418 loadCallback(p, el, el);
1419 }
1420 }: Callback());
1421 if (maxV >= 0)
1422 loadModuleDependency(self, uri, Version(maxV, v.minorVersion), loadCallback2, nullptr);
1423 if (commonV)
1424 loadModuleDependency(self, uri, Version(Version::Undefined, v.minorVersion),
1425 loadCallback2, nullptr);
1426 else if (maxV < 0) {
1427 if (uri != u"QML") {
1428 addErrorLocal(myErrors()
1429 .warning(tr("Failed to find main qmldir file for %1 %2")
1430 .arg(uri, v.stringValue()))
1431 .handle());
1432 }
1433 if (loadCallback)
1434 loadCallback(p, DomItem::empty, DomItem::empty);
1435 }
1436 } else {
1437 std::shared_ptr<ModuleIndex> mIndex = moduleIndexWithUri(
1438 self, uri, v.majorVersion, EnvLookup::Normal, Changeable::Writable, errorHandler);
1439 std::shared_ptr<LoadInfo> lInfo = loadInfo(p);
1440 if (lInfo) {
1441 DomItem lInfoObj = self.copy(lInfo);
1442 lInfo->addEndCallback(lInfoObj, loadCallback);
1443 } else {
1444 addErrorLocal(
1445 myErrors().warning(tr("Missing loadInfo for %1").arg(p.toString())).handle());
1446 if (loadCallback)
1447 loadCallback(p, DomItem::empty, DomItem::empty);
1448 }
1449 }
1450 if (endCallback)
1451 addAllLoadedCallback(self, [p, endCallback](Path, DomItem &, DomItem &env) {
1452 DomItem el = env.path(p);
1453 endCallback(p, el, el);
1454 });
1455}
1456
1457void DomEnvironment::loadBuiltins(DomItem &self, Callback callback, ErrorHandler h)
1458{
1459 QString builtinsName = QLatin1String("builtins.qmltypes");
1460 const auto lPaths = loadPaths();
1461 for (const QString &path : lPaths) {
1462 QDir dir(path);
1463 QFileInfo fInfo(dir.filePath(builtinsName));
1464 if (fInfo.isFile()) {
1465 self.loadFile(FileToLoad::fromFileSystem(self.ownerAs<DomEnvironment>(),
1466 fInfo.canonicalFilePath()),
1467 callback, LoadOption::DefaultLoad);
1468 return;
1469 }
1470 }
1471 myErrors().error(tr("Could not find builtins.qmltypes file")).handle(h);
1472}
1473
1474void DomEnvironment::removePath(const QString &path)
1475{
1476 QMutexLocker l(mutex());
1477 auto toDelete = [path](auto it) {
1478 QString p = it.key();
1479 return p.startsWith(path) && (p.size() == path.size() || p.at(path.size()) == u'/');
1480 };
1481 m_qmlDirectoryWithPath.removeIf(toDelete);
1482 m_qmldirFileWithPath.removeIf(toDelete);
1483 m_qmlFileWithPath.removeIf(toDelete);
1484 m_jsFileWithPath.removeIf(toDelete);
1485 m_qmltypesFileWithPath.removeIf(toDelete);
1486}
1487
1488shared_ptr<DomUniverse> DomEnvironment::universe() const {
1489 if (m_universe)
1490 return m_universe;
1491 else if (m_base)
1492 return m_base->universe();
1493 else
1494 return {};
1495}
1496
1497template<typename T>
1498QSet<QString> DomEnvironment::getStrings(function_ref<QSet<QString>()> getBase,
1499 const QMap<QString, T> &selfMap, EnvLookup options) const
1500{
1502 if (options != EnvLookup::NoBase && m_base) {
1503 if (m_base)
1504 res = getBase();
1505 }
1506 if (options != EnvLookup::BaseOnly) {
1508 {
1509 QMutexLocker l(mutex());
1510 map = selfMap;
1511 }
1512 auto it = map.keyBegin();
1513 auto end = map.keyEnd();
1514 while (it != end) {
1515 res += *it;
1516 ++it;
1517 }
1518 }
1519 return res;
1520}
1521
1522QSet<QString> DomEnvironment::moduleIndexUris(DomItem &, EnvLookup lookup) const
1523{
1524 DomItem baseObj = DomItem(m_base);
1525 return this->getStrings<QMap<int, std::shared_ptr<ModuleIndex>>>(
1526 [this, &baseObj] { return m_base->moduleIndexUris(baseObj, EnvLookup::Normal); },
1527 m_moduleIndexWithUri, lookup);
1528}
1529
1530QSet<int> DomEnvironment::moduleIndexMajorVersions(DomItem &, QString uri, EnvLookup lookup) const
1531{
1532 QSet<int> res;
1533 if (lookup != EnvLookup::NoBase && m_base) {
1534 DomItem baseObj(m_base);
1535 res = m_base->moduleIndexMajorVersions(baseObj, uri, EnvLookup::Normal);
1536 }
1537 if (lookup != EnvLookup::BaseOnly) {
1539 {
1540 QMutexLocker l(mutex());
1541 map = m_moduleIndexWithUri.value(uri);
1542 }
1543 auto it = map.keyBegin();
1544 auto end = map.keyEnd();
1545 while (it != end) {
1546 res += *it;
1547 ++it;
1548 }
1549 }
1550 return res;
1551}
1552
1553std::shared_ptr<ModuleIndex> DomEnvironment::lookupModuleInEnv(const QString &uri, int majorVersion) const
1554{
1555 QMutexLocker l(mutex());
1556 auto it = m_moduleIndexWithUri.find(uri);
1557 if (it == m_moduleIndexWithUri.end())
1558 return {}; // we haven't seen the module yet
1559 if (it->empty())
1560 return {}; // module contains nothing
1561 if (majorVersion == Version::Latest)
1562 return it->last(); // map is ordered by version, so last == Latest
1563 else
1564 return it->value(majorVersion); // null shared_ptr is fine if no match
1565}
1566
1567DomEnvironment::ModuleLookupResult DomEnvironment::moduleIndexWithUriHelper(DomItem &self, QString uri, int majorVersion, EnvLookup options) const
1568{
1569 std::shared_ptr<ModuleIndex> res;
1570 if (options != EnvLookup::BaseOnly)
1571 res = lookupModuleInEnv(uri, majorVersion);
1572 // if there is no base, or if we should not consider it
1573 // then the only result we can end up with is the module we looked up above
1574 if (options == EnvLookup::NoBase || !m_base)
1575 return {std::move(res), ModuleLookupResult::FromGlobal };
1576 const std::shared_ptr existingMod =
1577 m_base->moduleIndexWithUri(self, uri, majorVersion, options, Changeable::ReadOnly);
1578 if (!res) // the only module we can find at all is the one in base (might be null, too, though)
1579 return { std::move(existingMod), ModuleLookupResult::FromBase };
1580 if (!existingMod) // on the other hand, if there was nothing in base, we can only return what was in the larger env
1581 return {std::move(res), ModuleLookupResult::FromGlobal };
1582
1583 // if we have both res and existingMod, res and existingMod should be the same
1584 // _unless_ we looked for the latest version. Then one might have a higher version than the other
1585 // and we have to check it
1586
1587 if (majorVersion == Version::Latest) {
1588 if (res->majorVersion() >= existingMod->majorVersion())
1589 return { std::move(res), ModuleLookupResult::FromGlobal };
1590 else
1591 return { std::move(existingMod), ModuleLookupResult::FromBase };
1592 } else {
1593 // doesn't really matter which we return, but the other overload benefits from using the
1594 // version from m_moduleIndexWithUri
1595 return { std::move(res), ModuleLookupResult::FromGlobal };
1596 }
1597}
1598
1599std::shared_ptr<ModuleIndex> DomEnvironment::moduleIndexWithUri(DomItem &self, QString uri,
1600 int majorVersion, EnvLookup options,
1601 Changeable changeable,
1602 ErrorHandler errorHandler)
1603{
1604 // sanity checks
1605 Q_ASSERT((changeable == Changeable::ReadOnly
1606 || (majorVersion >= 0 || majorVersion == Version::Undefined))
1607 && "A writeable moduleIndexWithUri call should have a version (not with "
1608 "Version::Latest)");
1609 if (changeable == Changeable::Writable && (m_options & Option::Exported))
1610 myErrors().error(tr("A mutable module was requested in a multithreaded environment")).handle(errorHandler);
1611
1612
1613 // use the overload which does not care about changing m_moduleIndexWithUri to find a candidate
1614 auto [candidate, origin] = moduleIndexWithUriHelper(self, uri, majorVersion, options);
1615
1616 // A ModuleIndex from m_moduleIndexWithUri can always be returned
1617 if (candidate && origin == ModuleLookupResult::FromGlobal)
1618 return candidate;
1619
1620 // If we don't want to modify anything, return the candidate that we have found (if any)
1621 if (changeable == Changeable::ReadOnly)
1622 return candidate;
1623
1624 // Else we want to create a modifyable version
1625 std::shared_ptr<ModuleIndex> newModulePtr = [&, candidate = candidate](){
1626 // which is a completely new module in case we don't have candidate
1627 if (!candidate)
1628 return std::make_shared<ModuleIndex>(uri, majorVersion);
1629 // or a copy of the candidate otherwise
1630 DomItem existingModObj = self.copy(candidate);
1631 return candidate->makeCopy(existingModObj);
1632 }();
1633
1634 DomItem newModule = self.copy(newModulePtr);
1635 Path p = newModule.canonicalPath();
1636 {
1637 QMutexLocker l(mutex());
1638 auto &modsNow = m_moduleIndexWithUri[uri];
1639 // As we do not hold the lock for the whole operation, some other thread
1640 // might have created the module already
1641 if (auto it = modsNow.find(majorVersion); it != modsNow.end())
1642 return *it;
1643 modsNow.insert(majorVersion, newModulePtr);
1644 }
1645 if (p) {
1646 auto lInfo = std::make_shared<LoadInfo>(p);
1647 addLoadInfo(self, lInfo);
1648 } else {
1649 myErrors()
1650 .error(tr("Could not get path for newly created ModuleIndex %1 %2")
1651 .arg(uri)
1652 .arg(majorVersion))
1653 .handle(errorHandler);
1654 }
1655
1656 return newModulePtr;
1657}
1658
1659std::shared_ptr<ModuleIndex> DomEnvironment::moduleIndexWithUri(DomItem &self, QString uri,
1660 int majorVersion,
1661 EnvLookup options) const
1662{
1663 return moduleIndexWithUriHelper(self, uri, majorVersion, options).module;
1664}
1665
1666
1667
1668std::shared_ptr<ExternalItemInfo<QmlDirectory>>
1669DomEnvironment::qmlDirectoryWithPath(DomItem &self, QString path, EnvLookup options) const
1670{
1671 if (options != EnvLookup::BaseOnly) {
1672 QMutexLocker l(mutex());
1673 if (m_qmlDirectoryWithPath.contains(path))
1674 return m_qmlDirectoryWithPath.value(path);
1675 }
1676 if (options != EnvLookup::NoBase && m_base) {
1677 return m_base->qmlDirectoryWithPath(self, path, options);
1678 }
1679 return {};
1680}
1681
1682QSet<QString> DomEnvironment::qmlDirectoryPaths(DomItem &, EnvLookup options) const
1683{
1684 return getStrings<std::shared_ptr<ExternalItemInfo<QmlDirectory>>>(
1685 [this] {
1686 DomItem baseObj(m_base);
1687 return m_base->qmlDirectoryPaths(baseObj, EnvLookup::Normal);
1688 },
1689 m_qmlDirectoryWithPath, options);
1690}
1691
1692std::shared_ptr<ExternalItemInfo<QmldirFile>>
1693DomEnvironment::qmldirFileWithPath(DomItem &self, QString path, EnvLookup options) const
1694{
1695 if (options != EnvLookup::BaseOnly) {
1696 QMutexLocker l(mutex());
1697 auto it = m_qmldirFileWithPath.find(path);
1698 if (it != m_qmldirFileWithPath.end())
1699 return *it;
1700 }
1701 if (options != EnvLookup::NoBase && m_base)
1702 return m_base->qmldirFileWithPath(self, path, options);
1703 return {};
1704}
1705
1706QSet<QString> DomEnvironment::qmldirFilePaths(DomItem &, EnvLookup lOptions) const
1707{
1708 return getStrings<std::shared_ptr<ExternalItemInfo<QmldirFile>>>(
1709 [this] {
1710 DomItem baseObj(m_base);
1711 return m_base->qmldirFilePaths(baseObj, EnvLookup::Normal);
1712 },
1713 m_qmldirFileWithPath, lOptions);
1714}
1715
1716std::shared_ptr<ExternalItemInfoBase> DomEnvironment::qmlDirWithPath(DomItem &self, QString path,
1717 EnvLookup options) const
1718{
1719 if (auto qmldirFile = qmldirFileWithPath(self, path + QLatin1String("/qmldir"), options))
1720 return qmldirFile;
1721 return qmlDirectoryWithPath(self, path, options);
1722}
1723
1724QSet<QString> DomEnvironment::qmlDirPaths(DomItem &self, EnvLookup options) const
1725{
1726 QSet<QString> res = qmlDirectoryPaths(self, options);
1727 const auto qmldirFiles = qmldirFilePaths(self, options);
1728 for (const QString &p : qmldirFiles) {
1729 if (p.endsWith(u"/qmldir")) {
1730 res.insert(p.left(p.size() - 7));
1731 } else {
1732 myErrors()
1733 .warning(tr("Unexpected path not ending with qmldir in qmldirFilePaths: %1")
1734 .arg(p))
1735 .handle();
1736 }
1737 }
1738 return res;
1739}
1740
1741std::shared_ptr<ExternalItemInfo<QmlFile>>
1742DomEnvironment::qmlFileWithPath(DomItem &self, QString path, EnvLookup options) const
1743{
1744 if (options != EnvLookup::BaseOnly) {
1745 QMutexLocker l(mutex());
1746 auto it = m_qmlFileWithPath.find(path);
1747 if (it != m_qmlFileWithPath.end())
1748 return *it;
1749 }
1750 if (options != EnvLookup::NoBase && m_base)
1751 return m_base->qmlFileWithPath(self, path, options);
1752 return {};
1753}
1754
1755QSet<QString> DomEnvironment::qmlFilePaths(DomItem &, EnvLookup lookup) const
1756{
1757 return getStrings<std::shared_ptr<ExternalItemInfo<QmlFile>>>(
1758 [this] {
1759 DomItem baseObj(m_base);
1760 return m_base->qmlFilePaths(baseObj, EnvLookup::Normal);
1761 },
1762 m_qmlFileWithPath, lookup);
1763}
1764
1765std::shared_ptr<ExternalItemInfo<JsFile>>
1766DomEnvironment::jsFileWithPath(DomItem &self, QString path, EnvLookup options) const
1767{
1768 if (options != EnvLookup::BaseOnly) {
1769 QMutexLocker l(mutex());
1770 if (m_jsFileWithPath.contains(path))
1771 return m_jsFileWithPath.value(path);
1772 }
1773 if (options != EnvLookup::NoBase && m_base)
1774 return m_base->jsFileWithPath(self, path, EnvLookup::Normal);
1775 return {};
1776}
1777
1778QSet<QString> DomEnvironment::jsFilePaths(DomItem &, EnvLookup lookup) const
1779{
1780 return getStrings<std::shared_ptr<ExternalItemInfo<JsFile>>>(
1781 [this] {
1782 DomItem baseObj(m_base);
1783 return m_base->jsFilePaths(baseObj, EnvLookup::Normal);
1784 },
1785 m_jsFileWithPath, lookup);
1786}
1787
1788std::shared_ptr<ExternalItemInfo<QmltypesFile>>
1789DomEnvironment::qmltypesFileWithPath(DomItem &self, QString path, EnvLookup options) const
1790{
1791 if (options != EnvLookup::BaseOnly) {
1792 QMutexLocker l(mutex());
1793 if (m_qmltypesFileWithPath.contains(path))
1794 return m_qmltypesFileWithPath.value(path);
1795 }
1796 if (options != EnvLookup::NoBase && m_base)
1797 return m_base->qmltypesFileWithPath(self, path, EnvLookup::Normal);
1798 return {};
1799}
1800
1801QSet<QString> DomEnvironment::qmltypesFilePaths(DomItem &, EnvLookup lookup) const
1802{
1803 return getStrings<std::shared_ptr<ExternalItemInfo<QmltypesFile>>>(
1804 [this] {
1805 DomItem baseObj(m_base);
1806 return m_base->qmltypesFilePaths(baseObj, EnvLookup::Normal);
1807 },
1808 m_qmltypesFileWithPath, lookup);
1809}
1810
1811std::shared_ptr<ExternalItemInfo<GlobalScope>>
1812DomEnvironment::globalScopeWithName(DomItem &self, QString name, EnvLookup lookupOptions) const
1813{
1814 if (lookupOptions != EnvLookup::BaseOnly) {
1815 QMutexLocker l(mutex());
1816 auto id = m_globalScopeWithName.find(name);
1817 if (id != m_globalScopeWithName.end())
1818 return *id;
1819 }
1820 if (lookupOptions != EnvLookup::NoBase && m_base)
1821 return m_base->globalScopeWithName(self, name, lookupOptions);
1822 return {};
1823}
1824
1825std::shared_ptr<ExternalItemInfo<GlobalScope>>
1826DomEnvironment::ensureGlobalScopeWithName(DomItem &self, QString name, EnvLookup lookupOptions)
1827{
1828 if (auto current = globalScopeWithName(self, name, lookupOptions))
1829 return current;
1830 if (auto u = universe()) {
1831 if (auto newVal = u->ensureGlobalScopeWithName(name)) {
1832 if (auto current = newVal->current) {
1833 DomItem currentObj = DomItem(u).copy(current);
1834 auto newScope = current->makeCopy(currentObj);
1835 auto newCopy = std::make_shared<ExternalItemInfo<GlobalScope>>(
1836 newScope);
1837 QMutexLocker l(mutex());
1838 if (auto oldVal = m_globalScopeWithName.value(name))
1839 return oldVal;
1840 m_globalScopeWithName.insert(name, newCopy);
1841 return newCopy;
1842 }
1843 }
1844 }
1845 Q_ASSERT_X(false, "DomEnvironment::ensureGlobalScopeWithName", "could not ensure globalScope");
1846 return {};
1847}
1848
1849QSet<QString> DomEnvironment::globalScopeNames(DomItem &, EnvLookup lookupOptions) const
1850{
1852 if (lookupOptions != EnvLookup::NoBase && m_base) {
1853 if (m_base) {
1854 DomItem baseObj(m_base);
1855 res = m_base->globalScopeNames(baseObj, EnvLookup::Normal);
1856 }
1857 }
1858 if (lookupOptions != EnvLookup::BaseOnly) {
1860 {
1861 QMutexLocker l(mutex());
1862 map = m_globalScopeWithName;
1863 }
1864 auto it = map.keyBegin();
1865 auto end = map.keyEnd();
1866 while (it != end) {
1867 res += *it;
1868 ++it;
1869 }
1870 }
1871 return res;
1872}
1873
1874void DomEnvironment::addLoadInfo(DomItem &self, std::shared_ptr<LoadInfo> loadInfo)
1875{
1876 if (!loadInfo)
1877 return;
1878 Path p = loadInfo->elementCanonicalPath();
1879 bool addWork = loadInfo->status() != LoadInfo::Status::Done;
1880 std::shared_ptr<LoadInfo> oldVal;
1881 {
1882 QMutexLocker l(mutex());
1883 oldVal = m_loadInfos.value(p);
1884 m_loadInfos.insert(p, loadInfo);
1885 if (addWork)
1886 m_loadsWithWork.enqueue(p);
1887 }
1888 if (oldVal && oldVal->status() != LoadInfo::Status::Done) {
1889 self.addError(myErrors()
1890 .error(tr("addLoadinfo replaces unfinished load info for %1")
1891 .arg(p.toString()))
1892 .handle());
1893 }
1894}
1895
1896std::shared_ptr<LoadInfo> DomEnvironment::loadInfo(Path path) const
1897{
1898 QMutexLocker l(mutex());
1899 return m_loadInfos.value(path);
1900}
1901
1902QHash<Path, std::shared_ptr<LoadInfo>> DomEnvironment::loadInfos() const
1903{
1904 QMutexLocker l(mutex());
1905 return m_loadInfos;
1906}
1907
1908QList<Path> DomEnvironment::loadInfoPaths() const
1909{
1910 auto lInfos = loadInfos();
1911 return lInfos.keys();
1912}
1913
1914DomItem::Callback DomEnvironment::callbackForQmlDirectory(DomItem &self, Callback loadCallback,
1915 Callback allDirectDepsCallback,
1916 Callback endCallback)
1917{
1918 return envCallbackForFile<QmlDirectory>(self, &DomEnvironment::m_qmlDirectoryWithPath,
1919 &DomEnvironment::qmlDirectoryWithPath, loadCallback,
1920 allDirectDepsCallback, endCallback);
1921}
1922
1923DomItem::Callback DomEnvironment::callbackForQmlFile(DomItem &self, Callback loadCallback,
1924 Callback allDirectDepsCallback,
1925 Callback endCallback)
1926{
1927 return envCallbackForFile<QmlFile>(self, &DomEnvironment::m_qmlFileWithPath,
1928 &DomEnvironment::qmlFileWithPath, loadCallback,
1929 allDirectDepsCallback, endCallback);
1930}
1931
1932DomTop::Callback DomEnvironment::callbackForQmltypesFile(DomItem &self,
1933 DomTop::Callback loadCallback,
1934 Callback allDirectDepsCallback,
1935 DomTop::Callback endCallback)
1936{
1937 return envCallbackForFile<QmltypesFile>(
1938 self, &DomEnvironment::m_qmltypesFileWithPath, &DomEnvironment::qmltypesFileWithPath,
1939 [loadCallback](Path p, DomItem &oldV, DomItem &newV) {
1940 DomItem newFile = newV.field(Fields::currentItem);
1941 if (std::shared_ptr<QmltypesFile> newFilePtr = newFile.ownerAs<QmltypesFile>())
1942 newFilePtr->ensureInModuleIndex(newFile);
1943 if (loadCallback)
1944 loadCallback(p, oldV, newV);
1945 },
1946 allDirectDepsCallback, endCallback);
1947}
1948
1949DomTop::Callback DomEnvironment::callbackForQmldirFile(DomItem &self, DomTop::Callback loadCallback,
1950 Callback allDirectDepsCallback,
1951 DomTop::Callback endCallback)
1952{
1953 return envCallbackForFile<QmldirFile>(self, &DomEnvironment::m_qmldirFileWithPath,
1954 &DomEnvironment::qmldirFileWithPath, loadCallback,
1955 allDirectDepsCallback, endCallback);
1956}
1957
1958DomEnvironment::DomEnvironment(QStringList loadPaths, Options options,
1959 shared_ptr<DomUniverse> universe)
1960 : m_options(options),
1961 m_universe(DomUniverse::guaranteeUniverse(universe)),
1962 m_loadPaths(loadPaths),
1963 m_implicitImports(defaultImplicitImports())
1964{}
1965
1967{
1968 std::shared_ptr<DomUniverse> universePtr = universe.ownerAs<DomUniverse>();
1969 auto envPtr = std::make_shared<DomEnvironment>(loadPaths, options, universePtr);
1970 return DomItem(envPtr);
1971}
1972
1973DomEnvironment::DomEnvironment(shared_ptr<DomEnvironment> parent, QStringList loadPaths,
1974 Options options)
1975 : m_options(options),
1976 m_base(parent),
1977 m_loadPaths(loadPaths),
1978 m_implicitImports(defaultImplicitImports())
1979{}
1980
1981template<typename T>
1982std::shared_ptr<ExternalItemInfo<T>>
1983addExternalItem(std::shared_ptr<T> file, QString key,
1984 QMap<QString, std::shared_ptr<ExternalItemInfo<T>>> &map, AddOption option,
1986{
1987 if (!file)
1988 return {};
1989 auto eInfo = std::make_shared<ExternalItemInfo<T>>(
1991 {
1993 auto it = map.find(key);
1994 if (it != map.end()) {
1995 switch (option) {
1997 eInfo = *it;
1998 break;
2000 map.insert(key, eInfo);
2001 break;
2002 }
2003 } else {
2004 map.insert(key, eInfo);
2005 }
2006 }
2007 return eInfo;
2008}
2009
2010std::shared_ptr<ExternalItemInfo<QmlFile>> DomEnvironment::addQmlFile(std::shared_ptr<QmlFile> file,
2011 AddOption options)
2012{
2013 return addExternalItem<QmlFile>(file, file->canonicalFilePath(), m_qmlFileWithPath, options,
2014 mutex());
2015}
2016
2017std::shared_ptr<ExternalItemInfo<QmlDirectory>>
2018DomEnvironment::addQmlDirectory(std::shared_ptr<QmlDirectory> file, AddOption options)
2019{
2020 return addExternalItem<QmlDirectory>(file, file->canonicalFilePath(), m_qmlDirectoryWithPath,
2021 options, mutex());
2022}
2023
2024std::shared_ptr<ExternalItemInfo<QmldirFile>>
2025DomEnvironment::addQmldirFile(std::shared_ptr<QmldirFile> file, AddOption options)
2026{
2027 return addExternalItem<QmldirFile>(file, file->canonicalFilePath(), m_qmldirFileWithPath,
2028 options, mutex());
2029}
2030
2031std::shared_ptr<ExternalItemInfo<QmltypesFile>>
2032DomEnvironment::addQmltypesFile(std::shared_ptr<QmltypesFile> file, AddOption options)
2033{
2034 return addExternalItem<QmltypesFile>(file, file->canonicalFilePath(), m_qmltypesFileWithPath,
2035 options, mutex());
2036}
2037
2038std::shared_ptr<ExternalItemInfo<JsFile>> DomEnvironment::addJsFile(std::shared_ptr<JsFile> file,
2039 AddOption options)
2040{
2041 return addExternalItem<JsFile>(file, file->canonicalFilePath(), m_jsFileWithPath, options,
2042 mutex());
2043}
2044
2045std::shared_ptr<ExternalItemInfo<GlobalScope>>
2046DomEnvironment::addGlobalScope(std::shared_ptr<GlobalScope> scope, AddOption options)
2047{
2048 return addExternalItem<GlobalScope>(scope, scope->name(), m_globalScopeWithName, options,
2049 mutex());
2050}
2051
2052bool DomEnvironment::commitToBase(DomItem &self, shared_ptr<DomEnvironment> validEnvPtr)
2053{
2054 if (!base())
2055 return false;
2064 {
2065 QMutexLocker l(mutex());
2066 my_moduleIndexWithUri = m_moduleIndexWithUri;
2067 my_globalScopeWithName = m_globalScopeWithName;
2068 my_qmlDirectoryWithPath = m_qmlDirectoryWithPath;
2069 my_qmldirFileWithPath = m_qmldirFileWithPath;
2070 my_qmlFileWithPath = m_qmlFileWithPath;
2071 my_jsFileWithPath = m_jsFileWithPath;
2072 my_qmltypesFileWithPath = m_qmltypesFileWithPath;
2073 my_loadInfos = m_loadInfos;
2074 }
2075 {
2076 QMutexLocker lBase(base()->mutex()); // be more careful about makeCopy calls with lock?
2077 m_base->m_globalScopeWithName.insert(my_globalScopeWithName);
2078 m_base->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
2079 m_base->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
2080 m_base->m_qmlFileWithPath.insert(my_qmlFileWithPath);
2081 m_base->m_jsFileWithPath.insert(my_jsFileWithPath);
2082 m_base->m_qmltypesFileWithPath.insert(my_qmltypesFileWithPath);
2083 m_base->m_loadInfos.insert(my_loadInfos);
2084 {
2085 auto it = my_moduleIndexWithUri.cbegin();
2086 auto end = my_moduleIndexWithUri.cend();
2087 while (it != end) {
2089 m_base->m_moduleIndexWithUri[it.key()];
2090 auto it2 = it.value().cbegin();
2091 auto end2 = it.value().cend();
2092 while (it2 != end2) {
2093 auto oldV = myVersions.value(it2.key());
2094 DomItem it2Obj = self.copy(it2.value());
2095 auto newV = it2.value()->makeCopy(it2Obj);
2096 newV->mergeWith(oldV);
2097 myVersions.insert(it2.key(), newV);
2098 ++it2;
2099 }
2100 ++it;
2101 }
2102 }
2103 }
2104 if (validEnvPtr) {
2105 QMutexLocker lValid(
2106 validEnvPtr->mutex()); // be more careful about makeCopy calls with lock?
2107 validEnvPtr->m_globalScopeWithName.insert(my_globalScopeWithName);
2108 validEnvPtr->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
2109 validEnvPtr->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
2110 for (auto it = my_qmlFileWithPath.cbegin(), end = my_qmlFileWithPath.cend(); it != end;
2111 ++it) {
2112 if (it.value() && it.value()->current && it.value()->current->isValid())
2113 validEnvPtr->m_qmlFileWithPath.insert(it.key(), it.value());
2114 }
2115 for (auto it = my_jsFileWithPath.cbegin(), end = my_jsFileWithPath.cend(); it != end;
2116 ++it) {
2117 if (it.value() && it.value()->current && it.value()->current->isValid())
2118 validEnvPtr->m_jsFileWithPath.insert(it.key(), it.value());
2119 }
2120 validEnvPtr->m_qmltypesFileWithPath.insert(my_qmltypesFileWithPath);
2121 validEnvPtr->m_loadInfos.insert(my_loadInfos);
2122 for (auto it = my_moduleIndexWithUri.cbegin(), end = my_moduleIndexWithUri.cend();
2123 it != end; ++it) {
2125 validEnvPtr->m_moduleIndexWithUri[it.key()];
2126 for (auto it2 = it.value().cbegin(), end2 = it.value().cend(); it2 != end2; ++it2) {
2127 auto oldV = myVersions.value(it2.key());
2128 DomItem it2Obj = self.copy(it2.value());
2129 auto newV = it2.value()->makeCopy(it2Obj);
2130 newV->mergeWith(oldV);
2131 myVersions.insert(it2.key(), newV);
2132 }
2133 }
2134 }
2135 return true;
2136}
2137
2139{
2140 while (true) {
2141 Path elToDo;
2142 std::shared_ptr<LoadInfo> loadInfo;
2143 {
2144 QMutexLocker l(mutex());
2145 if (m_loadsWithWork.isEmpty())
2146 break;
2147 elToDo = m_loadsWithWork.dequeue();
2148 m_inProgress.append(elToDo);
2149 loadInfo = m_loadInfos.value(elToDo);
2150 }
2151 if (loadInfo) {
2152 auto cleanup = qScopeGuard([this, elToDo, &self] {
2153 QList<Callback> endCallbacks;
2154 {
2155 QMutexLocker l(mutex());
2156 m_inProgress.removeOne(elToDo);
2157 if (m_inProgress.isEmpty() && m_loadsWithWork.isEmpty()) {
2158 endCallbacks = m_allLoadedCallback;
2159 m_allLoadedCallback.clear();
2160 }
2161 }
2162 for (const Callback &cb : std::as_const(endCallbacks))
2163 cb(self.canonicalPath(), self, self);
2164 });
2165 DomItem loadInfoObj = self.copy(loadInfo);
2166 loadInfo->advanceLoad(loadInfoObj);
2167 } else {
2168 self.addError(myErrors().error(u"DomEnvironment::loadPendingDependencies could not "
2169 u"find loadInfo listed in m_loadsWithWork"));
2170 {
2171 QMutexLocker l(mutex());
2172 m_inProgress.removeOne(elToDo);
2173 }
2174 Q_ASSERT(false
2175 && "DomEnvironment::loadPendingDependencies could not find loadInfo listed in "
2176 "m_loadsWithWork");
2177 }
2178 }
2179}
2180
2182{
2183 bool hasPendingLoads = true;
2184 QDateTime endTime = QDateTime::currentDateTimeUtc().addMSecs(waitMSec);
2185 for (int i = 0; i < waitMSec / 10 + 2; ++i) {
2187 auto lInfos = loadInfos();
2188 auto it = lInfos.cbegin();
2189 auto end = lInfos.cend();
2190 hasPendingLoads = false;
2191 while (it != end) {
2192 if (*it && (*it)->status() != LoadInfo::Status::Done)
2193 hasPendingLoads = true;
2194 }
2195 if (!hasPendingLoads)
2196 break;
2197 auto missing = QDateTime::currentDateTimeUtc().msecsTo(endTime);
2198 if (missing < 0)
2199 break;
2200 if (missing > 100)
2201 missing = 100;
2202#if QT_FEATURE_thread
2203 QThread::msleep(missing);
2204#endif
2205 }
2206 return !hasPendingLoads;
2207}
2208
2210{
2211 QMutexLocker l(mutex());
2212 m_loadsWithWork.enqueue(elementCanonicalPath);
2213}
2214
2215DomEnvironment::Options DomEnvironment::options() const
2216{
2217 return m_options;
2218}
2219
2220std::shared_ptr<DomEnvironment> DomEnvironment::base() const
2221{
2222 return m_base;
2223}
2224
2226{
2227 QMutexLocker l(mutex());
2228 m_loadPaths = v;
2229}
2230
2232{
2233 QMutexLocker l(mutex());
2234 return m_loadPaths;
2235}
2236
2238{
2239 QMutexLocker l(mutex());
2240 return m_qmldirFileWithPath.keys();
2241}
2242
2244{
2245 return m_globalScopeName;
2246}
2247
2249{
2250 return QList<Import>({ Import::fromUriString(u"QML"_s, Version(1, 0)),
2251 Import(QmlUri::fromUriString(u"QtQml"_s), Version(6, 0)) });
2252}
2253
2255{
2256 return m_implicitImports;
2257}
2258
2260{
2261 if (c) {
2262 bool immediate = false;
2263 {
2264 QMutexLocker l(mutex());
2265 if (m_loadsWithWork.isEmpty() && m_inProgress.isEmpty())
2266 immediate = true;
2267 else
2268 m_allLoadedCallback.append(c);
2269 }
2270 if (immediate)
2271 c(Path(), self, self);
2272 }
2273}
2274
2276{
2277 m_referenceCache.clear();
2278}
2279
2281{
2282 shared_ptr<ExternalOwningItem> current = currentItem();
2283 DomItem currentObj = currentItem(self);
2284 return current->canonicalFilePath(currentObj);
2285}
2286
2288{
2289 if (!self.dvValueLazyField(visitor, Fields::currentRevision,
2290 [this, &self]() { return currentRevision(self); }))
2291 return false;
2292 if (!self.dvValueLazyField(visitor, Fields::lastRevision,
2293 [this, &self]() { return lastRevision(self); }))
2294 return false;
2295 if (!self.dvValueLazyField(visitor, Fields::lastValidRevision,
2296 [this, &self]() { return lastValidRevision(self); }))
2297 return false;
2298 if (!visitor(PathEls::Field(Fields::currentItem),
2299 [&self, this]() { return currentItem(self); }))
2300 return false;
2301 if (!self.dvValueLazyField(visitor, Fields::currentExposedAt,
2302 [this]() { return currentExposedAt(); }))
2303 return false;
2304 return true;
2305}
2306
2308{
2309 return currentItem()->revision();
2310}
2311
2313{
2314 Path p = currentItem()->canonicalPath();
2315 DomItem lastValue = self.universe()[p.mid(1, p.length() - 1)].field(u"revision");
2316 return static_cast<int>(lastValue.value().toInteger(0));
2317}
2318
2320{
2321 Path p = currentItem()->canonicalPath();
2322 DomItem lastValidValue = self.universe()[p.mid(1, p.length() - 2)].field(u"validItem").field(u"revision");
2323 return static_cast<int>(lastValidValue.value().toInteger(0));
2324}
2325
2327{
2328 shared_ptr<ExternalOwningItem> current = currentItem();
2329 return current->canonicalFilePath();
2330}
2331
2333{
2334 shared_ptr<ExternalOwningItem> current = currentItem();
2335 return current->canonicalPath().dropTail();
2336}
2337
2339{
2340 if (!self.dvValueLazyField(visitor, Fields::currentIsValid,
2341 [this]() { return currentIsValid(); }))
2342 return false;
2343 if (!visitor(PathEls::Field(Fields::validItem), [this, &self]() { return validItem(self); }))
2344 return false;
2345 if (!visitor(PathEls::Field(Fields::currentItem),
2346 [this, &self]() { return currentItem(self); }))
2347 return false;
2348 if (!self.dvValueField(visitor, Fields::validExposedAt, validExposedAt))
2349 return false;
2350 if (!self.dvValueField(visitor, Fields::currentExposedAt, currentExposedAt))
2351 return false;
2352 return true;
2353}
2354
2356{
2357 return currentItem() == validItem();
2358}
2359
2361{
2362 DomItem env = el.environment();
2363 std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>();
2365 if (envPtr) {
2366 QMutexLocker l(envPtr->mutex());
2367 cached = envPtr->m_referenceCache.value(canonicalPath, {});
2368 } else {
2369 qCWarning(domLog) << "No Env for reference" << canonicalPath << "from"
2370 << el.internalKindStr() << el.canonicalPath();
2371 Q_ASSERT(false);
2372 }
2373 return cached;
2374}
2375
2377 AddOption addOption)
2378{
2379 DomItem env = el.environment();
2380 std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>();
2381 bool didSet = false;
2382 if (envPtr) {
2383 QMutexLocker l(envPtr->mutex());
2384 RefCacheEntry &cached = envPtr->m_referenceCache[canonicalPath];
2385 switch (cached.cached) {
2387 cached = entry;
2388 didSet = true;
2389 break;
2391 if (addOption == AddOption::Overwrite || entry.cached == RefCacheEntry::Cached::All) {
2392 cached = entry;
2393 didSet = true;
2394 }
2395 break;
2397 if (addOption == AddOption::Overwrite || entry.cached == RefCacheEntry::Cached::All) {
2398 cached = entry;
2399 didSet = true;
2400 }
2401 }
2402 if (cached.cached == RefCacheEntry::Cached::First && cached.canonicalPaths.isEmpty())
2404 } else {
2405 Q_ASSERT(false);
2406 }
2407 return didSet;
2408}
2409
2410} // end namespace Dom
2411} // end namespace QQmlJS
2412
2414
2415#include "moc_qqmldomtop_p.cpp"
\inmodule QtCore
Definition qatomic.h:112
qint64 toInteger(qint64 defaultValue=0) const
Returns the integer value stored in this QCborValue, if it is of the integer type.
Definition qcborvalue.h:190
\inmodule QtCore
Definition qchar.h:48
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
\inmodule QtCore\reentrant
Definition qdatetime.h:257
static QDateTime fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
QDateTime addMSecs(qint64 msecs) const
Returns a QDateTime object containing a datetime msecs milliseconds later than the datetime of this o...
qint64 msecsTo(const QDateTime &) const
Returns the number of milliseconds from this datetime to the other datetime.
static QDateTime currentDateTimeUtc()
QDate date() const
Returns the date part of the datetime.
\inmodule QtCore
Definition qdir.h:19
QStringList entryList(Filters filters=NoFilter, SortFlags sort=NoSort) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qdir.cpp:1364
@ Name
Definition qdir.h:49
@ Files
Definition qdir.h:22
@ NoDotAndDotDot
Definition qdir.h:43
@ Dirs
Definition qdir.h:21
FileError error() const
Returns the file error status.
void close() override
Calls QFileDevice::flush() and closes the file.
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
bool isFile() const
Returns true if this object points to a file or to a symbolic link to a file.
QString canonicalFilePath() const
Returns the canonical path including the file name, i.e.
\inmodule QtCore
Definition qfile.h:93
bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:881
\inmodule QtCore
Definition qhash.h:818
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:991
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
QString errorString() const
Returns a human-readable description of the last device error that occurred.
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
Definition qmap.h:186
iterator insert(const Key &key, const T &value)
Definition qmap.h:687
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:356
const_iterator cend() const
Definition qmap.h:604
const_iterator cbegin() const
Definition qmap.h:600
iterator find(const Key &key)
Definition qmap.h:640
iterator end()
Definition qmap.h:601
key_iterator keyBegin() const
Definition qmap.h:605
Key key(const T &value, const Key &defaultKey=Key()) const
Definition qmap.h:348
key_iterator keyEnd() const
Definition qmap.h:606
\inmodule QtCore
Definition qmutex.h:317
\inmodule QtCore
Definition qmutex.h:285
Represents a consistent set of types organized in modules, it is the top level of the DOM.
std::shared_ptr< ExternalItemInfo< QmlDirectory > > addQmlDirectory(std::shared_ptr< QmlDirectory > file, AddOption option=AddOption::KeepExisting)
void loadPendingDependencies(DomItem &self)
QString globalScopeName() const
QStringList qmldirFiles() const
std::shared_ptr< LoadInfo > loadInfo(Path path) const
std::shared_ptr< ExternalItemInfo< QmldirFile > > addQmldirFile(std::shared_ptr< QmldirFile > file, AddOption option=AddOption::KeepExisting)
void addWorkForLoadInfo(Path elementCanonicalPath)
void addAllLoadedCallback(DomItem &self, Callback c)
static ErrorGroups myErrors()
static QList< Import > defaultImplicitImports()
void setLoadPaths(const QStringList &v)
std::shared_ptr< ExternalItemInfo< JsFile > > addJsFile(std::shared_ptr< JsFile > file, AddOption option=AddOption::KeepExisting)
std::shared_ptr< DomEnvironment > base() const
std::shared_ptr< ExternalItemInfo< QmltypesFile > > addQmltypesFile(std::shared_ptr< QmltypesFile > file, AddOption option=AddOption::KeepExisting)
std::shared_ptr< ExternalItemInfo< GlobalScope > > addGlobalScope(std::shared_ptr< GlobalScope > file, AddOption option=AddOption::KeepExisting)
static DomItem create(QStringList loadPaths, Options options=Option::SingleThreaded, DomItem &universe=DomItem::empty)
std::shared_ptr< ExternalItemInfo< QmlFile > > addQmlFile(std::shared_ptr< QmlFile > file, AddOption option=AddOption::KeepExisting)
std::shared_ptr< DomUniverse > universe() const
DomEnvironment(QStringList loadPaths, Options options=Option::SingleThreaded, std::shared_ptr< DomUniverse > universe=nullptr)
QList< Import > implicitImports() const
QHash< Path, std::shared_ptr< LoadInfo > > loadInfos() const
bool finishLoadingDependencies(DomItem &self, int waitMSec=30000)
bool commitToBase(DomItem &self, std::shared_ptr< DomEnvironment > validEnv=nullptr)
QStringList loadPaths() const
std::shared_ptr< T > ownerAs()
function< void(Path, DomItem &, DomItem &)> Callback
bool iterateErrors(function_ref< bool(DomItem source, ErrorMessage msg)> visitor, bool iterate, Path inPath=Path())
DomItem copy(Owner owner, Path ownerPath, T base)
MutableDomItem makeCopy(CopyOption option=CopyOption::EnvConnected)
DomItem path(Path p, ErrorHandler h=&defaultErrorHandler)
QCborValue value()
static DomItem empty
QString canonicalFilePath()
void addError(ErrorMessage msg)
bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override
DomItem containingObject(DomItem &) const override
virtual Path canonicalPath() const =0
DomItem::Callback Callback
Represents a set of parsed/loaded modules libraries and a plugins.
bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override
QSet< QString > globalScopeNames() const
std::shared_ptr< ExternalItemPair< QmltypesFile > > qmltypesFileWithPath(QString path) const
std::shared_ptr< ExternalItemPair< QmlDirectory > > qmlDirectoryWithPath(QString path) const
std::shared_ptr< ExternalItemPair< GlobalScope > > globalScopeWithName(QString name) const
static ErrorGroups myErrors()
QSet< QString > qmltypesFilePaths() const
std::shared_ptr< ExternalItemPair< QmldirFile > > qmldirFileWithPath(QString path) const
std::shared_ptr< ExternalItemPair< QmlFile > > qmlFileWithPath(QString path) const
std::shared_ptr< ExternalItemPair< JsFile > > jsFileWithPath(QString path) const
void removePath(const QString &dir)
static std::shared_ptr< DomUniverse > guaranteeUniverse(std::shared_ptr< DomUniverse > univ)
std::shared_ptr< OwningItem > doCopy(DomItem &self) const override
QSet< QString > qmlDirectoryPaths() const
QSet< QString > jsFilePaths() const
Options options() const
QSet< QString > qmldirFilePaths() const
static DomItem create(QString universeName, Options options=Option::SingleThreaded)
void loadFile(DomItem &self, const FileToLoad &file, Callback callback, LoadOptions loadOptions, std::optional< DomType > fileType=std::optional< DomType >())
Path canonicalPath() const override
QQueue< ParsingTask > queue() const
QSet< QString > qmlFilePaths() const
Represents a set of tags grouping a set of related error messages.
ErrorMessage warning(QString message) const
ErrorMessage error(QString message) const
Represents an error message connected to the dom.
ErrorMessage handle(const ErrorHandler &errorHandler=nullptr)
int lastRevision(DomItem &self) const
virtual std::shared_ptr< ExternalOwningItem > currentItem() const =0
bool iterateDirectSubpaths(DomItem &self, DirectVisitor) final override
int currentRevision(DomItem &self) const
QString canonicalFilePath(DomItem &) const final override
int lastValidRevision(DomItem &self) const
bool iterateDirectSubpaths(DomItem &self, DirectVisitor) final override
Path canonicalPath(DomItem &self) const final override
QString canonicalFilePath(DomItem &) const final override
virtual std::shared_ptr< ExternalOwningItem > currentItem() const =0
virtual std::shared_ptr< ExternalOwningItem > validItem() const =0
static FileToLoad fromFileSystem(const std::weak_ptr< DomEnvironment > &environment, const QString &canonicalPath, DomCreationOptions options=None)
static Import fromUriString(QString importStr, Version v=Version(), QString importId=QString(), ErrorHandler handler=nullptr)
std::shared_ptr< OwningItem > doCopy(DomItem &self) const override
void addEndCallback(DomItem &self, std::function< void(Path, DomItem &, DomItem &)> callback)
void execEnd(DomItem &self)
Status status() const
Path canonicalPath(DomItem &self) const override
bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override
Path elementCanonicalPath() const
void advanceLoad(DomItem &self)
void finishedLoadingDep(DomItem &self, const Dependency &d)
QBasicMutex * mutex() const
void addErrorLocal(ErrorMessage msg)
bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override
virtual void refreshedDataAt(QDateTime tNew)
static Path Root(PathRoot r)
Path key(QString name) const
QString headName() const
Path field(QString name) const
static Path Field(QStringView s=u"")
static QmlUri fromUriString(const QString &importStr)
static std::shared_ptr< QmldirFile > fromPathAndCode(QString path, QString code)
static bool addForPath(DomItem &el, Path canonicalPath, const RefCacheEntry &entry, AddOption addOption=AddOption::KeepExisting)
static RefCacheEntry forPath(DomItem &el, Path canonicalPath)
Represents an immutable JsonPath like path in the Qml code model (from a DomItem to another DomItem)
\inmodule QtCore
Definition qqueue.h:14
QString captured(int nth=0) const
Returns the substring captured by the nth capturing group.
\inmodule QtCore \reentrant
static QString escape(const QString &str)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QRegularExpressionMatch match(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
Attempts to match the regular expression against the given subject string, starting at the position o...
static QString anchoredPattern(const QString &expression)
Definition qset.h:18
iterator end()
Definition qset.h:140
const_iterator cend() const noexcept
Definition qset.h:142
iterator find(const T &value)
Definition qset.h:159
const_iterator cbegin() const noexcept
Definition qset.h:138
iterator insert(const T &value)
Definition qset.h:155
qsizetype removeIf(Pred predicate)
Definition qset.h:66
bool empty() const
Definition qset.h:177
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
int toInt(bool *ok=nullptr, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition qstring.h:660
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
Definition qstring.cpp:7956
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:898
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1095
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1217
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
static void msleep(unsigned long)
QMap< QString, QString > map
[6]
cache insert(employee->id(), employee)
QSet< QString >::iterator it
short next
Definition keywords.cpp:445
Path qmlDirectoryInfoPath(QString path)
Path qmldirFileInfoPath(QString path)
Path qmlFileInfoPath(QString canonicalFilePath)
Path qmltypesFileInfoPath(QString path)
void createDom(MutableDomItem qmlFile, DomCreationOptions options=None)
std::function< void(const ErrorMessage &)> ErrorHandler
DomTop::Callback envCallbackForFile(DomItem &self, QMap< QString, std::shared_ptr< ExternalItemInfo< T > > > DomEnvironment::*map, std::shared_ptr< ExternalItemInfo< T > >(DomEnvironment::*lookupF)(DomItem &, QString, EnvLookup) const, DomTop::Callback loadCallback, DomTop::Callback allDirectDepsCallback, DomTop::Callback endCallback)
std::shared_ptr< ExternalItemInfo< T > > addExternalItem(std::shared_ptr< T > file, QString key, QMap< QString, std::shared_ptr< ExternalItemInfo< T > > > &map, AddOption option, QBasicMutex *mutex)
QMLDOM_EXPORT QString domTypeToString(DomType k)
qint64 index_type
static QString toString(const UiQualifiedId *qualifiedId, QChar delimiter=QLatin1Char('.'))
static DomType fileTypeForPath(DomItem &self, QString canonicalFilePath)
QPair< std::shared_ptr< ExternalItemPair< T > >, std::shared_ptr< ExternalItemPair< T > > > updateEntry(DomItem &univ, std::shared_ptr< T > newItem, QMap< QString, std::shared_ptr< ExternalItemPair< T > > > &map, QBasicMutex *mutex)
Combined button and popup list for selecting options.
@ CaseInsensitive
QString self
Definition language.cpp:57
SharedPointerFileDialogOptions m_options
std::pair< T1, T2 > QPair
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qCWarning(category,...)
static ControlElement< T > * ptr(QWidget *widget)
GLsizei const GLfloat * v
[13]
GLuint64 GLenum void * handle
const GLfloat * m
GLsizei GLuint * groups
GLuint64 key
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint id
[7]
GLfloat GLfloat f
GLint ref
GLuint name
GLfloat GLfloat GLfloat GLfloat h
GLuint counter
GLuint res
const GLubyte * c
GLuint entry
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLsizei const GLchar *const * path
GLsizei GLenum GLboolean sink
GLfloat GLfloat p
[1]
GLuint GLenum option
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
#define NewErrorGroup(name)
QT_BEGIN_NAMESPACE typedef void(* Callback)(QQmlNotifierEndpoint *, void **)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
SSL_CTX int(*) void arg)
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
static QString canonicalPath(const QString &rootPath)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
static FileType fileType(const QFileInfo &fi)
#define tr(X)
static int compare(quint64 a, quint64 b)
QList< int > list
[14]
if(qFloatDistance(a, b)<(1<< 7))
[0]
QFile file
[0]
QMutex mutex
[2]
QString dir
[11]
char * toString(const MyType &t)
[31]
QStringView el
\inmodule QtCore \reentrant
Definition qchar.h:17
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent