aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmldom/qqmldomtop_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmldom/qqmldomtop_p.h')
-rw-r--r--src/qmldom/qqmldomtop_p.h1038
1 files changed, 870 insertions, 168 deletions
diff --git a/src/qmldom/qqmldomtop_p.h b/src/qmldom/qqmldomtop_p.h
index 6145d9edd1..33a921af93 100644
--- a/src/qmldom/qqmldomtop_p.h
+++ b/src/qmldom/qqmldomtop_p.h
@@ -1,40 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
#ifndef DOMTOP_H
#define DOMTOP_H
@@ -50,7 +16,7 @@
//
#include "qqmldomitem_p.h"
-
+#include "qqmldomelements_p.h"
#include "qqmldomexternalitems_p.h"
#include <QtCore/QQueue>
@@ -61,75 +27,64 @@
#include <QtCore/QCborMap>
#include <memory>
+#include <optional>
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
namespace QQmlJS {
namespace Dom {
-class QMLDOM_EXPORT ParsingTask {
- Q_GADGET
-public:
- QCborMap toCbor() const {
- return QCborMap(
- {{ QString::fromUtf16(Fields::requestedAt), QCborValue(requestedAt)},
- { QString::fromUtf16(Fields::loadOptions), int(loadOptions)},
- { QString::fromUtf16(Fields::kind), int(kind)},
- { QString::fromUtf16(Fields::canonicalPath), canonicalPath},
- { QString::fromUtf16(Fields::logicalPath), logicalPath},
- { QString::fromUtf16(Fields::contents), contents},
- { QString::fromUtf16(Fields::contentsDate), QCborValue(contentsDate)},
- { QString::fromUtf16(Fields::hasCallback), bool(callback)}});
- }
-
- QDateTime requestedAt;
- LoadOptions loadOptions;
- DomType kind;
- QString canonicalPath;
- QString logicalPath;
- QString contents;
- QDateTime contentsDate;
- std::weak_ptr<DomUniverse> requestingUniverse; // make it a shared_ptr?
- function<void(Path, DomItem, DomItem)> callback;
-};
-
class QMLDOM_EXPORT ExternalItemPairBase: public OwningItem { // all access should have the lock of the DomUniverse containing this
Q_DECLARE_TR_FUNCTIONS(ExternalItemPairBase);
public:
constexpr static DomType kindValue = DomType::ExternalItemPair;
- DomType kind() const override { return kindValue; }
- ExternalItemPairBase(QDateTime validExposedAt = QDateTime::fromMSecsSinceEpoch(0),
- QDateTime currentExposedAt = QDateTime::fromMSecsSinceEpoch(0),
- int derivedFrom=0, QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0)):
- OwningItem(derivedFrom, lastDataUpdateAt), validExposedAt(validExposedAt), currentExposedAt(currentExposedAt)
+ DomType kind() const final override { return kindValue; }
+ ExternalItemPairBase(
+ const QDateTime &validExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ const QDateTime &currentExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0,
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
+ : OwningItem(derivedFrom, lastDataUpdateAt),
+ validExposedAt(validExposedAt),
+ currentExposedAt(currentExposedAt)
{}
ExternalItemPairBase(const ExternalItemPairBase &o):
OwningItem(o), validExposedAt(o.validExposedAt), currentExposedAt(o.currentExposedAt)
{}
virtual std::shared_ptr<ExternalOwningItem> validItem() const = 0;
+ virtual DomItem validItem(const DomItem &self) const = 0;
virtual std::shared_ptr<ExternalOwningItem> currentItem() const = 0;
+ virtual DomItem currentItem(const DomItem &self) const = 0;
- QString canonicalFilePath(const DomItem &) const override;
- Path pathFromOwner(const DomItem &self) const override;
- Path canonicalPath(const DomItem &self) const override;
- bool iterateDirectSubpaths(DomItem &self, function<bool(Path, DomItem &)>) override;
+ QString canonicalFilePath(const DomItem &) const final override;
+ Path canonicalPath(const DomItem &self) const final override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const final override;
+ DomItem field(const DomItem &self, QStringView name) const final override
+ {
+ return OwningItem::field(self, name);
+ }
bool currentIsValid() const;
- std::shared_ptr<ExternalItemPairBase> makeCopy(const DomItem &self) {
+ std::shared_ptr<ExternalItemPairBase> makeCopy(const DomItem &self) const
+ {
return std::static_pointer_cast<ExternalItemPairBase>(doCopy(self));
}
- QDateTime lastDataUpdateAt() const override {
+ QDateTime lastDataUpdateAt() const final override
+ {
if (currentItem())
return currentItem()->lastDataUpdateAt();
return ExternalItemPairBase::lastDataUpdateAt();
}
- void refreshedDataAt(QDateTime tNew) override {
- return OwningItem::refreshedDataAt(tNew);
+ void refreshedDataAt(QDateTime tNew) final override
+ {
if (currentItem())
currentItem()->refreshedDataAt(tNew);
+ return OwningItem::refreshedDataAt(tNew);
}
friend class DomUniverse;
@@ -139,29 +94,37 @@ public:
};
template<class T>
-class QMLDOM_EXPORT ExternalItemPair: public ExternalItemPairBase { // all access should have the lock of the DomUniverse containing this
+class QMLDOM_EXPORT ExternalItemPair final : public ExternalItemPairBase
+{ // all access should have the lock of the DomUniverse containing this
protected:
- std::shared_ptr<OwningItem> doCopy(const DomItem &) override {
+ std::shared_ptr<OwningItem> doCopy(const DomItem &) const override
+ {
return std::make_shared<ExternalItemPair>(*this);
}
public:
+ constexpr static DomType kindValue = DomType::ExternalItemPair;
friend class DomUniverse;
- ExternalItemPair(std::shared_ptr<T> valid = {}, std::shared_ptr<T> current = {},
- QDateTime validExposedAt = QDateTime::fromMSecsSinceEpoch(0),
- QDateTime currentExposedAt = QDateTime::fromMSecsSinceEpoch(0),
- int derivedFrom = 0, QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0)):
- ExternalItemPairBase(validExposedAt, currentExposedAt, derivedFrom, lastDataUpdateAt),
- valid(valid), current(current)
+ ExternalItemPair(
+ const std::shared_ptr<T> &valid = {}, const std::shared_ptr<T> &current = {},
+ const QDateTime &validExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ const QDateTime &currentExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0,
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
+ : ExternalItemPairBase(validExposedAt, currentExposedAt, derivedFrom, lastDataUpdateAt),
+ valid(valid),
+ current(current)
{}
ExternalItemPair(const ExternalItemPair &o):
ExternalItemPairBase(o), valid(o.valid), current(o.current)
{
- QMutexLocker l(mutex());
}
std::shared_ptr<ExternalOwningItem> validItem() const override { return valid; }
+ DomItem validItem(const DomItem &self) const override { return self.copy(valid); }
std::shared_ptr<ExternalOwningItem> currentItem() const override { return current; }
- std::shared_ptr<ExternalItemPair> makeCopy(const DomItem &self) {
+ DomItem currentItem(const DomItem &self) const override { return self.copy(current); }
+ std::shared_ptr<ExternalItemPair> makeCopy(const DomItem &self) const
+ {
return std::static_pointer_cast<ExternalItemPair>(doCopy(self));
}
@@ -171,13 +134,13 @@ public:
class QMLDOM_EXPORT DomTop: public OwningItem {
public:
- DomTop(QMap<QString, std::shared_ptr<OwningItem>> extraOwningItems = {}, int derivedFrom=0):
- OwningItem(derivedFrom), m_extraOwningItems(extraOwningItems)
+ DomTop(QMap<QString, OwnerT> extraOwningItems = {}, int derivedFrom = 0)
+ : OwningItem(derivedFrom), m_extraOwningItems(extraOwningItems)
{}
DomTop(const DomTop &o):
OwningItem(o)
{
- QMap<QString, std::shared_ptr<OwningItem>> items = o.extraOwningItems();
+ QMap<QString, OwnerT> items = o.extraOwningItems();
{
QMutexLocker l(mutex());
m_extraOwningItems = items;
@@ -187,109 +150,357 @@ public:
virtual Path canonicalPath() const = 0;
- Path pathFromOwner(const DomItem &) const override;
Path canonicalPath(const DomItem &) const override;
- DomItem containingObject(const DomItem&) const override;
- bool iterateDirectSubpaths(DomItem &self, function<bool(Path, DomItem &)>) override;
+ DomItem containingObject(const DomItem &) const override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ template<typename T>
+ void setExtraOwningItem(const QString &fieldName, const std::shared_ptr<T> &item)
+ {
+ QMutexLocker l(mutex());
+ if (!item)
+ m_extraOwningItems.remove(fieldName);
+ else
+ m_extraOwningItems.insert(fieldName, item);
+ }
- void setExtraOwningItem(QString fieldName, std::shared_ptr<OwningItem> item);
void clearExtraOwningItems();
- QMap<QString, std::shared_ptr<OwningItem>> extraOwningItems() const;
+ QMap<QString, OwnerT> extraOwningItems() const;
+
private:
- QMap<QString, std::shared_ptr<OwningItem>> m_extraOwningItems;
+ QMap<QString, OwnerT> m_extraOwningItems;
};
-class QMLDOM_EXPORT DomUniverse: public DomTop {
+class QMLDOM_EXPORT DomUniverse final : public DomTop,
+ public std::enable_shared_from_this<DomUniverse>
+{
+ Q_GADGET
Q_DECLARE_TR_FUNCTIONS(DomUniverse);
protected:
- std::shared_ptr<OwningItem> doCopy(const DomItem &self) override;
+ std::shared_ptr<OwningItem> doCopy(const DomItem &self) const override;
+
public:
- enum class Option{
- Default,
- SingleThreaded
- };
- Q_DECLARE_FLAGS(Options, Option);
constexpr static DomType kindValue = DomType::DomUniverse;
DomType kind() const override { return kindValue; }
static ErrorGroups myErrors();
- DomUniverse(QString universeName, Options options = Option::SingleThreaded);
+ DomUniverse(const QString &universeName);
DomUniverse(const DomUniverse &) = delete;
+ static std::shared_ptr<DomUniverse> guaranteeUniverse(const std::shared_ptr<DomUniverse> &univ);
+ static DomItem create(const QString &universeName);
Path canonicalPath() const override;
- bool iterateDirectSubpaths(DomItem &self, function<bool(Path, DomItem &)>) override;
- std::shared_ptr<DomUniverse> makeCopy(const DomItem &self) {
+ using DomTop::canonicalPath;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ std::shared_ptr<DomUniverse> makeCopy(const DomItem &self) const
+ {
return std::static_pointer_cast<DomUniverse>(doCopy(self));
}
- void loadFile(const DomItem &self, QString filePath, QString logicalPath,
- Callback callback, LoadOptions loadOptions);
- void loadFile(const DomItem &self, QString canonicalFilePath, QString logicalPath,
- QString code, QDateTime codeDate, Callback callback, LoadOptions loadOptions);
- void execQueue();
+ // Helper structure reflecting the change in the map once loading && parsing is completed
+ // formerItem - DomItem representing value (ExternalItemPair) existing in the map before the
+ // loading && parsing. Might be empty (if didn't exist / failure) or equal to currentItem
+ // currentItem - DomItem representing current map value
+ struct LoadResult
+ {
+ DomItem formerItem;
+ DomItem currentItem;
+ };
+
+ LoadResult loadFile(const FileToLoad &file, DomType fileType,
+ DomCreationOptions creationOptions = {});
+
+ void removePath(const QString &dir);
+
+ std::shared_ptr<ExternalItemPair<GlobalScope>> globalScopeWithName(const QString &name) const
+ {
+ QMutexLocker l(mutex());
+ return m_globalScopeWithName.value(name);
+ }
+
+ std::shared_ptr<ExternalItemPair<GlobalScope>> ensureGlobalScopeWithName(const QString &name)
+ {
+ if (auto current = globalScopeWithName(name))
+ return current;
+ auto newScope = std::make_shared<GlobalScope>(name);
+ auto newValue = std::make_shared<ExternalItemPair<GlobalScope>>(
+ newScope, newScope);
+ QMutexLocker l(mutex());
+ if (auto current = m_globalScopeWithName.value(name))
+ return current;
+ m_globalScopeWithName.insert(name, newValue);
+ return newValue;
+ }
+
+ QSet<QString> globalScopeNames() const
+ {
+ QMap<QString, std::shared_ptr<ExternalItemPair<GlobalScope>>> map;
+ {
+ QMutexLocker l(mutex());
+ map = m_globalScopeWithName;
+ }
+ return QSet<QString>(map.keyBegin(), map.keyEnd());
+ }
+
+ std::shared_ptr<ExternalItemPair<QmlDirectory>> qmlDirectoryWithPath(const QString &path) const
+ {
+ QMutexLocker l(mutex());
+ return m_qmlDirectoryWithPath.value(path);
+ }
+ QSet<QString> qmlDirectoryPaths() const
+ {
+ QMap<QString, std::shared_ptr<ExternalItemPair<QmlDirectory>>> map;
+ {
+ QMutexLocker l(mutex());
+ map = m_qmlDirectoryWithPath;
+ }
+ return QSet<QString>(map.keyBegin(), map.keyEnd());
+ }
+
+ std::shared_ptr<ExternalItemPair<QmldirFile>> qmldirFileWithPath(const QString &path) const
+ {
+ QMutexLocker l(mutex());
+ return m_qmldirFileWithPath.value(path);
+ }
+ QSet<QString> qmldirFilePaths() const
+ {
+ QMap<QString, std::shared_ptr<ExternalItemPair<QmldirFile>>> map;
+ {
+ QMutexLocker l(mutex());
+ map = m_qmldirFileWithPath;
+ }
+ return QSet<QString>(map.keyBegin(), map.keyEnd());
+ }
+
+ std::shared_ptr<ExternalItemPair<QmlFile>> qmlFileWithPath(const QString &path) const
+ {
+ QMutexLocker l(mutex());
+ return m_qmlFileWithPath.value(path);
+ }
+ QSet<QString> qmlFilePaths() const
+ {
+ QMap<QString, std::shared_ptr<ExternalItemPair<QmlFile>>> map;
+ {
+ QMutexLocker l(mutex());
+ map = m_qmlFileWithPath;
+ }
+ return QSet<QString>(map.keyBegin(), map.keyEnd());
+ }
+
+ std::shared_ptr<ExternalItemPair<JsFile>> jsFileWithPath(const QString &path) const
+ {
+ QMutexLocker l(mutex());
+ return m_jsFileWithPath.value(path);
+ }
+ QSet<QString> jsFilePaths() const
+ {
+ QMap<QString, std::shared_ptr<ExternalItemPair<JsFile>>> map;
+ {
+ QMutexLocker l(mutex());
+ map = m_jsFileWithPath;
+ }
+ return QSet<QString>(map.keyBegin(), map.keyEnd());
+ }
+
+ std::shared_ptr<ExternalItemPair<QmltypesFile>> qmltypesFileWithPath(const QString &path) const
+ {
+ QMutexLocker l(mutex());
+ return m_qmltypesFileWithPath.value(path);
+ }
+ QSet<QString> qmltypesFilePaths() const
+ {
+ QMap<QString, std::shared_ptr<ExternalItemPair<QmltypesFile>>> map;
+ {
+ QMutexLocker l(mutex());
+ map = m_qmltypesFileWithPath;
+ }
+ return QSet<QString>(map.keyBegin(), map.keyEnd());
+ }
QString name() const {
return m_name;
}
- Options options() const {
- return m_options;
+
+private:
+ struct ContentWithDate
+ {
+ QString content;
+ QDateTime date;
+ };
+ // contains either Content with the timestamp when it was read or an Error
+ using ReadResult = std::variant<ContentWithDate, ErrorMessage>;
+ ReadResult readFileContent(const QString &canonicalPath) const;
+
+ LoadResult load(const ContentWithDate &codeWithDate, const FileToLoad &file, DomType fType,
+ DomCreationOptions creationOptions = {});
+
+ // contains either Content to be parsed or LoadResult if loading / parsing is not needed
+ using PreloadResult = std::variant<ContentWithDate, LoadResult>;
+ PreloadResult preload(const DomItem &univ, const FileToLoad &file, DomType fType) const;
+
+ std::shared_ptr<QmlFile> parseQmlFile(const QString &code, const FileToLoad &file,
+ const QDateTime &contentDate,
+ DomCreationOptions creationOptions);
+ std::shared_ptr<JsFile> parseJsFile(const QString &code, const FileToLoad &file,
+ const QDateTime &contentDate);
+ std::shared_ptr<ExternalItemPairBase> getPathValueOrNull(DomType fType,
+ const QString &path) const;
+ std::optional<DomItem> getItemIfMostRecent(const DomItem &univ, DomType fType,
+ const QString &path) const;
+ std::optional<DomItem> getItemIfHasSameCode(const DomItem &univ, DomType fType,
+ const QString &canonicalPath,
+ const ContentWithDate &codeWithDate) const;
+ static bool valueHasMostRecentItem(const ExternalItemPairBase *value,
+ const QDateTime &lastModified);
+ static bool valueHasSameContent(const ExternalItemPairBase *value, const QString &content);
+
+ // TODO better name / consider proper public get/set
+ template <typename T>
+ QMap<QString, std::shared_ptr<ExternalItemPair<T>>> &getMutableRefToMap()
+ {
+ Q_ASSERT(!mutex()->tryLock());
+ if constexpr (std::is_same_v<T, QmlDirectory>) {
+ return m_qmlDirectoryWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmldirFile>) {
+ return m_qmldirFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmlFile>) {
+ return m_qmlFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, JsFile>) {
+ return m_jsFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmltypesFile>) {
+ return m_qmltypesFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, GlobalScope>) {
+ return m_globalScopeWithName;
+ }
+ Q_UNREACHABLE();
}
- QQueue<ParsingTask> queue() const {
- QMutexLocker l(mutex());
- return m_queue;
+
+ // Inserts or updates an entry reflecting ExternalItem in the corresponding map
+ // Returns a pair of:
+ // - current ExternalItemPair, current value in the map (might be empty, or equal to curValue)
+ // - new current ExternalItemPair, value in the map after after the execution of this function
+ template <typename T>
+ QPair<std::shared_ptr<ExternalItemPair<T>>, std::shared_ptr<ExternalItemPair<T>>>
+ insertOrUpdateEntry(std::shared_ptr<T> newItem)
+ {
+ std::shared_ptr<ExternalItemPair<T>> curValue;
+ std::shared_ptr<ExternalItemPair<T>> newCurValue;
+ QString canonicalPath = newItem->canonicalFilePath();
+ QDateTime now = QDateTime::currentDateTimeUtc();
+ {
+ QMutexLocker l(mutex());
+ auto &map = getMutableRefToMap<T>();
+ auto it = map.find(canonicalPath);
+ if (it != map.cend() && (*it) && (*it)->current) {
+ curValue = *it;
+ if (valueHasSameContent(curValue.get(), newItem->code())) {
+ // value in the map has same content as newItem, a.k.a. most recent
+ newCurValue = curValue;
+ if (newCurValue->current->lastDataUpdateAt() < newItem->lastDataUpdateAt()) {
+ // update timestamp in the current, as if its content was refreshed by
+ // NewItem
+ newCurValue->current->refreshedDataAt(newItem->lastDataUpdateAt());
+ }
+ } else if (curValue->current->lastDataUpdateAt() > newItem->lastDataUpdateAt()) {
+ // value in the map is more recent than newItem, nothing to update
+ newCurValue = curValue;
+ } else {
+ // perform update with newItem
+ curValue->current = std::move(newItem);
+ curValue->currentExposedAt = now;
+ if (curValue->current->isValid()) {
+ curValue->valid = curValue->current;
+ curValue->validExposedAt = std::move(now);
+ }
+ newCurValue = curValue;
+ }
+ } else {
+ // not found / invalid, just insert
+ newCurValue = std::make_shared<ExternalItemPair<T>>(
+ (newItem->isValid() ? newItem : std::shared_ptr<T>()), newItem, now, now);
+ map.insert(canonicalPath, newCurValue);
+ }
+ }
+ return qMakePair(curValue, newCurValue);
+ }
+
+ // Inserts or updates an entry reflecting ExternalItem in the corresponding map
+ // returns LoadResult reflecting the change made to the map
+ template <typename T>
+ LoadResult insertOrUpdateExternalItem(std::shared_ptr<T> extItem)
+ {
+ auto change = insertOrUpdateEntry<T>(std::move(extItem));
+ DomItem univ(shared_from_this());
+ return { univ.copy(change.first), univ.copy(change.second) };
}
private:
QString m_name;
- Options m_options;
- QQueue<ParsingTask> m_queue;
+ QMap<QString, std::shared_ptr<ExternalItemPair<GlobalScope>>> m_globalScopeWithName;
+ QMap<QString, std::shared_ptr<ExternalItemPair<QmlDirectory>>> m_qmlDirectoryWithPath;
+ QMap<QString, std::shared_ptr<ExternalItemPair<QmldirFile>>> m_qmldirFileWithPath;
+ QMap<QString, std::shared_ptr<ExternalItemPair<QmlFile>>> m_qmlFileWithPath;
+ QMap<QString, std::shared_ptr<ExternalItemPair<JsFile>>> m_jsFileWithPath;
+ QMap<QString, std::shared_ptr<ExternalItemPair<QmltypesFile>>> m_qmltypesFileWithPath;
};
- Q_DECLARE_OPERATORS_FOR_FLAGS(DomUniverse::Options)
-
class QMLDOM_EXPORT ExternalItemInfoBase: public OwningItem {
Q_DECLARE_TR_FUNCTIONS(ExternalItemInfoBase);
public:
constexpr static DomType kindValue = DomType::ExternalItemInfo;
- DomType kind() const override { return kindValue; }
- ExternalItemInfoBase(QDateTime currentExposedAt = QDateTime::fromMSecsSinceEpoch(0),
- int derivedFrom=0, QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0)):
- OwningItem(derivedFrom, lastDataUpdateAt), m_currentExposedAt(currentExposedAt)
- {}
- ExternalItemInfoBase(const ExternalItemInfoBase &o):
- OwningItem(o), m_currentExposedAt(o.currentExposedAt()),
- m_logicalFilePaths(o.logicalFilePaths())
+ DomType kind() const final override { return kindValue; }
+ ExternalItemInfoBase(
+ const Path &canonicalPath,
+ const QDateTime &currentExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0,
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
+ : OwningItem(derivedFrom, lastDataUpdateAt),
+ m_canonicalPath(canonicalPath),
+ m_currentExposedAt(currentExposedAt)
{}
+ ExternalItemInfoBase(const ExternalItemInfoBase &o) = default;
virtual std::shared_ptr<ExternalOwningItem> currentItem() const = 0;
+ virtual DomItem currentItem(const DomItem &) const = 0;
- QString canonicalFilePath(const DomItem &) const override;
- Path canonicalPath(const DomItem &) const override;
- Path pathFromOwner(const DomItem &self) const override;
- bool iterateDirectSubpaths(DomItem &self, function<bool(Path, DomItem &)>) override;
+ QString canonicalFilePath(const DomItem &) const final override;
+ Path canonicalPath() const { return m_canonicalPath; }
+ Path canonicalPath(const DomItem &) const final override { return canonicalPath(); }
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const final override;
+ DomItem field(const DomItem &self, QStringView name) const final override
+ {
+ return OwningItem::field(self, name);
+ }
int currentRevision(const DomItem &self) const;
int lastRevision(const DomItem &self) const;
int lastValidRevision(const DomItem &self) const;
- std::shared_ptr<ExternalItemInfoBase> makeCopy(const DomItem &self) {
+ std::shared_ptr<ExternalItemInfoBase> makeCopy(const DomItem &self) const
+ {
return std::static_pointer_cast<ExternalItemInfoBase>(doCopy(self));
}
- QDateTime lastDataUpdateAt() const override {
+ QDateTime lastDataUpdateAt() const final override
+ {
if (currentItem())
return currentItem()->lastDataUpdateAt();
return OwningItem::lastDataUpdateAt();
}
- void refreshedDataAt(QDateTime tNew) override {
- return OwningItem::refreshedDataAt(tNew);
+ void refreshedDataAt(QDateTime tNew) final override
+ {
if (currentItem())
currentItem()->refreshedDataAt(tNew);
+ return OwningItem::refreshedDataAt(tNew);
}
- void ensureLogicalFilePath(QString path) {
+ void ensureLogicalFilePath(const QString &path) {
QMutexLocker l(mutex());
if (!m_logicalFilePaths.contains(path))
m_logicalFilePaths.append(path);
@@ -313,51 +524,203 @@ public:
private:
friend class DomEnvironment;
+ Path m_canonicalPath;
QDateTime m_currentExposedAt;
QStringList m_logicalFilePaths;
};
-template <typename T>
-class ExternalItemInfo: public ExternalItemInfoBase {
+template<typename T>
+class ExternalItemInfo final : public ExternalItemInfoBase
+{
protected:
- std::shared_ptr<OwningItem> doCopy(const DomItem &) override {
+ std::shared_ptr<OwningItem> doCopy(const DomItem &) const override
+ {
return std::make_shared<ExternalItemInfo>(*this);
}
+
public:
- ExternalItemInfo(std::shared_ptr<T> current = std::shared_ptr<T>(),
- QDateTime currentExposedAt = QDateTime::fromMSecsSinceEpoch(0),
- int derivedFrom = 0, QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0)):
- ExternalItemInfoBase(currentExposedAt, derivedFrom, lastDataUpdateAt), current(current)
- {}
- ExternalItemInfo(QString canonicalPath):
- current(std::make_shared<T>(canonicalPath))
+ constexpr static DomType kindValue = DomType::ExternalItemInfo;
+ ExternalItemInfo(
+ const std::shared_ptr<T> &current = std::shared_ptr<T>(),
+ const QDateTime &currentExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0,
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
+ : ExternalItemInfoBase(current->canonicalPath().dropTail(), currentExposedAt, derivedFrom,
+ lastDataUpdateAt),
+ current(current)
{}
+ ExternalItemInfo(const QString &canonicalPath) : current(new T(canonicalPath)) { }
ExternalItemInfo(const ExternalItemInfo &o):
ExternalItemInfoBase(o), current(o.current)
{
- QMutexLocker l(mutex());
}
- std::shared_ptr<ExternalItemInfo> makeCopy(const DomItem &self) {
+ std::shared_ptr<ExternalItemInfo> makeCopy(const DomItem &self) const
+ {
return std::static_pointer_cast<ExternalItemInfo>(doCopy(self));
}
std::shared_ptr<ExternalOwningItem> currentItem() const override {
return current;
}
+ DomItem currentItem(const DomItem &self) const override { return self.copy(current); }
std::shared_ptr<T> current;
};
+class Dependency
+{ // internal, should be cleaned, but nobody should use this...
+public:
+ bool operator==(Dependency const &o) const
+ {
+ return uri == o.uri && version.majorVersion == o.version.majorVersion
+ && version.minorVersion == o.version.minorVersion && filePath == o.filePath;
+ }
+ QString uri; // either dotted uri or file:, http: https: uri
+ Version version;
+ QString filePath; // for file deps
+ DomType fileType;
+};
+
+class QMLDOM_EXPORT LoadInfo final : public OwningItem
+{
+ Q_DECLARE_TR_FUNCTIONS(LoadInfo);
+
+protected:
+ std::shared_ptr<OwningItem> doCopy(const DomItem &self) const override;
+
+public:
+ constexpr static DomType kindValue = DomType::LoadInfo;
+ DomType kind() const override { return kindValue; }
+
+ enum class Status {
+ NotStarted, // dependencies non checked yet
+ Starting, // adding deps
+ InProgress, // waiting for all deps to be loaded
+ CallingCallbacks, // calling callbacks
+ Done // fully loaded
+ };
+
+ LoadInfo(const Path &elPath = Path(), Status status = Status::NotStarted, int nLoaded = 0,
+ int derivedFrom = 0,
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
+ : OwningItem(derivedFrom, lastDataUpdateAt),
+ m_elementCanonicalPath(elPath),
+ m_status(status),
+ m_nLoaded(nLoaded)
+ {
+ }
+ LoadInfo(const LoadInfo &o) : OwningItem(o), m_elementCanonicalPath(o.elementCanonicalPath())
+ {
+ {
+ QMutexLocker l(o.mutex());
+ m_status = o.m_status;
+ m_nLoaded = o.m_nLoaded;
+ m_toDo = o.m_toDo;
+ m_inProgress = o.m_inProgress;
+ m_endCallbacks = o.m_endCallbacks;
+ }
+ }
+
+ Path canonicalPath(const DomItem &self) const override;
+
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ std::shared_ptr<LoadInfo> makeCopy(const DomItem &self) const
+ {
+ return std::static_pointer_cast<LoadInfo>(doCopy(self));
+ }
+ void addError(const DomItem &self, ErrorMessage &&msg) override
+ {
+ self.path(elementCanonicalPath()).addError(std::move(msg));
+ }
+
+ void addEndCallback(const DomItem &self, std::function<void(Path, const DomItem &, const DomItem &)> callback);
+
+ void advanceLoad(const DomItem &self);
+ void finishedLoadingDep(const DomItem &self, const Dependency &d);
+ void execEnd(const DomItem &self);
+
+ Status status() const
+ {
+ QMutexLocker l(mutex());
+ return m_status;
+ }
+
+ int nLoaded() const
+ {
+ QMutexLocker l(mutex());
+ return m_nLoaded;
+ }
+
+ Path elementCanonicalPath() const
+ {
+ QMutexLocker l(mutex()); // we should never change this, remove lock?
+ return m_elementCanonicalPath;
+ }
+
+ int nNotDone() const
+ {
+ QMutexLocker l(mutex());
+ return m_toDo.size() + m_inProgress.size();
+ }
+
+ QList<Dependency> inProgress() const
+ {
+ QMutexLocker l(mutex());
+ return m_inProgress;
+ }
+
+ QList<Dependency> toDo() const
+ {
+ QMutexLocker l(mutex());
+ return m_toDo;
+ }
+
+ int nCallbacks() const
+ {
+ QMutexLocker l(mutex());
+ return m_endCallbacks.size();
+ }
+
+private:
+ void doAddDependencies(const DomItem &self);
+ void addDependency(const DomItem &self, const Dependency &dep);
+
+ Path m_elementCanonicalPath;
+ Status m_status;
+ int m_nLoaded;
+ QQueue<Dependency> m_toDo;
+ QList<Dependency> m_inProgress;
+ QList<std::function<void(Path, const DomItem &, const DomItem &)>> m_endCallbacks;
+};
+
enum class EnvLookup { Normal, NoBase, BaseOnly };
enum class Changeable { ReadOnly, Writable };
-class QMLDOM_EXPORT DomEnvironment: public DomTop
+class QMLDOM_EXPORT RefCacheEntry
{
+ Q_GADGET
+public:
+ enum class Cached { None, First, All };
+ Q_ENUM(Cached)
+
+ static RefCacheEntry forPath(const DomItem &el, const Path &canonicalPath);
+ static bool addForPath(const DomItem &el, const Path &canonicalPath, const RefCacheEntry &entry,
+ AddOption addOption = AddOption::KeepExisting);
+
+ Cached cached = Cached::None;
+ QList<Path> canonicalPaths;
+};
+
+class QMLDOM_EXPORT DomEnvironment final : public DomTop,
+ public std::enable_shared_from_this<DomEnvironment>
+{
+ Q_GADGET
Q_DECLARE_TR_FUNCTIONS(DomEnvironment);
protected:
- std::shared_ptr<OwningItem> doCopy(const DomItem &self) override;
+ std::shared_ptr<OwningItem> doCopy(const DomItem &self) const override;
+
public:
enum class Option {
Default = 0x0,
@@ -368,50 +731,389 @@ public:
SingleThreaded = 0x10, // do all operations in a single thread
NoDependencies = 0x20 // will not load dependencies (useful when editing)
};
+ Q_ENUM(Option)
Q_DECLARE_FLAGS(Options, Option);
static ErrorGroups myErrors();
constexpr static DomType kindValue = DomType::DomEnvironment;
- DomType kind() const override { return kindValue; }
+ DomType kind() const override;
Path canonicalPath() const override;
- bool iterateDirectSubpaths(DomItem &self, function<bool(Path, DomItem &)>) override;
- std::shared_ptr<DomEnvironment> makeCopy(const DomItem &self) {
- return std::static_pointer_cast<DomEnvironment>(doCopy(self));
- }
+ using DomTop::canonicalPath;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ DomItem field(const DomItem &self, QStringView name) const final override;
+
+ std::shared_ptr<DomEnvironment> makeCopy(const DomItem &self) const;
+
+ void loadFile(const FileToLoad &file, const Callback &callback,
+ std::optional<DomType> fileType = std::optional<DomType>(),
+ const ErrorHandler &h = nullptr /* used only in loadPendingDependencies*/);
+ void loadBuiltins(const Callback &callback = nullptr, const ErrorHandler &h = nullptr);
+ void loadModuleDependency(const QString &uri, Version v, const Callback &callback = nullptr,
+ const ErrorHandler & = nullptr);
+
+ void removePath(const QString &path);
std::shared_ptr<DomUniverse> universe() const;
- DomEnvironment(std::shared_ptr<DomUniverse> universe, QStringList loadPaths, Options options = Option::SingleThreaded);
- DomEnvironment(std::shared_ptr<DomEnvironment> parent, QStringList loadPaths, Options options = Option::SingleThreaded);
+ QSet<QString> moduleIndexUris(const DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
+ QSet<int> moduleIndexMajorVersions(const DomItem &self, const QString &uri,
+ EnvLookup lookup = EnvLookup::Normal) const;
+ std::shared_ptr<ModuleIndex> moduleIndexWithUri(const DomItem &self, const QString &uri, int majorVersion,
+ EnvLookup lookup, Changeable changeable,
+ const ErrorHandler &errorHandler = nullptr);
+ std::shared_ptr<ModuleIndex> moduleIndexWithUri(const DomItem &self, const QString &uri, int majorVersion,
+ EnvLookup lookup = EnvLookup::Normal) const;
+ std::shared_ptr<ExternalItemInfo<QmlDirectory>>
+ qmlDirectoryWithPath(const DomItem &self, const QString &path, EnvLookup options = EnvLookup::Normal) const;
+ QSet<QString> qmlDirectoryPaths(const DomItem &self, EnvLookup options = EnvLookup::Normal) const;
+ std::shared_ptr<ExternalItemInfo<QmldirFile>>
+ qmldirFileWithPath(const DomItem &self, const QString &path, EnvLookup options = EnvLookup::Normal) const;
+ QSet<QString> qmldirFilePaths(const DomItem &self, EnvLookup options = EnvLookup::Normal) const;
+ std::shared_ptr<ExternalItemInfoBase>
+ qmlDirWithPath(const DomItem &self, const QString &path, EnvLookup options = EnvLookup::Normal) const;
+ QSet<QString> qmlDirPaths(const DomItem &self, EnvLookup options = EnvLookup::Normal) const;
+ std::shared_ptr<ExternalItemInfo<QmlFile>>
+ qmlFileWithPath(const DomItem &self, const QString &path, EnvLookup options = EnvLookup::Normal) const;
+ QSet<QString> qmlFilePaths(const DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
+ std::shared_ptr<ExternalItemInfo<JsFile>>
+ jsFileWithPath(const DomItem &self, const QString &path, EnvLookup options = EnvLookup::Normal) const;
+ QSet<QString> jsFilePaths(const DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
+ std::shared_ptr<ExternalItemInfo<QmltypesFile>>
+ qmltypesFileWithPath(const DomItem &self, const QString &path, EnvLookup options = EnvLookup::Normal) const;
+ QSet<QString> qmltypesFilePaths(const DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
+ std::shared_ptr<ExternalItemInfo<GlobalScope>>
+ globalScopeWithName(const DomItem &self, const QString &name, EnvLookup lookup = EnvLookup::Normal) const;
+ std::shared_ptr<ExternalItemInfo<GlobalScope>>
+ ensureGlobalScopeWithName(const DomItem &self, const QString &name, EnvLookup lookup = EnvLookup::Normal);
+ QSet<QString> globalScopeNames(const DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
+
+ explicit DomEnvironment(const QStringList &loadPaths, Options options = Option::SingleThreaded,
+ DomCreationOptions domCreationOptions = None,
+ const std::shared_ptr<DomUniverse> &universe = nullptr);
+ explicit DomEnvironment(const std::shared_ptr<DomEnvironment> &parent,
+ const QStringList &loadPaths, Options options = Option::SingleThreaded,
+ DomCreationOptions domCreationOptions = None);
DomEnvironment(const DomEnvironment &o) = delete;
+ static std::shared_ptr<DomEnvironment>
+ create(const QStringList &loadPaths, Options options = Option::SingleThreaded,
+ DomCreationOptions creationOptions = DomCreationOption::None,
+ const DomItem &universe = DomItem::empty);
+
+ // TODO AddOption can easily be removed later. KeepExisting option only used in one
+ // place which will be removed in https://codereview.qt-project.org/c/qt/qtdeclarative/+/523217
+ void addQmlFile(const std::shared_ptr<QmlFile> &file,
+ AddOption option = AddOption::KeepExisting);
+ void addQmlDirectory(const std::shared_ptr<QmlDirectory> &file,
+ AddOption option = AddOption::KeepExisting);
+ void addQmldirFile(const std::shared_ptr<QmldirFile> &file,
+ AddOption option = AddOption::KeepExisting);
+ void addQmltypesFile(const std::shared_ptr<QmltypesFile> &file,
+ AddOption option = AddOption::KeepExisting);
+ void addJsFile(const std::shared_ptr<JsFile> &file, AddOption option = AddOption::KeepExisting);
+ void addGlobalScope(const std::shared_ptr<GlobalScope> &file,
+ AddOption option = AddOption::KeepExisting);
+
+ bool commitToBase(
+ const DomItem &self, const std::shared_ptr<DomEnvironment> &validEnv = nullptr);
+
+ void addDependenciesToLoad(const Path &path);
+ void addLoadInfo(
+ const DomItem &self, const std::shared_ptr<LoadInfo> &loadInfo);
+ std::shared_ptr<LoadInfo> loadInfo(const Path &path) const;
+ QList<Path> loadInfoPaths() const;
+ QHash<Path, std::shared_ptr<LoadInfo>> loadInfos() const;
+ void loadPendingDependencies();
+ bool finishLoadingDependencies(int waitMSec = 30000);
+ void addWorkForLoadInfo(const Path &elementCanonicalPath);
+
+ Options options() const;
+
+ std::shared_ptr<DomEnvironment> base() const;
+
+ QStringList loadPaths() const;
+ QStringList qmldirFiles() const;
+
+ QString globalScopeName() const;
+
+ static QList<Import> defaultImplicitImports();
+ QList<Import> implicitImports() const;
+
+ void addAllLoadedCallback(const DomItem &self, Callback c);
+
+ void clearReferenceCache();
+ void setLoadPaths(const QStringList &v);
+
+ // Helper structure reflecting the change in the map once loading / fetching is completed
+ // formerItem - DomItem representing value (ExternalItemInfo) existing in the map before the
+ // loading && parsing. Might be empty (if didn't exist / failure) or equal to currentItem
+ // currentItem - DomItem representing current map value
+ struct LoadResult
+ {
+ DomItem formerItem;
+ DomItem currentItem;
+ };
+ // TODO(QTBUG-121171)
+ template <typename T>
+ LoadResult insertOrUpdateExternalItemInfo(const QString &path, std::shared_ptr<T> extItem)
+ {
+ // maybe in the next revision this all can be just substituted by the addExternalItem
+ DomItem env(shared_from_this());
+ // try to fetch from the current env.
+ if (auto curValue = lookup<T>(path, EnvLookup::NoBase)) {
+ // found in the "initial" env
+ return { env.copy(curValue), env.copy(curValue) };
+ }
+ std::shared_ptr<ExternalItemInfo<T>> newCurValue;
+ // try to fetch from the base env
+ auto valueInBase = lookup<T>(path, EnvLookup::BaseOnly);
+ if (!valueInBase) {
+ // Nothing found. Just create an externalItemInfo which will be inserted
+ newCurValue = std::make_shared<ExternalItemInfo<T>>(std::move(extItem),
+ QDateTime::currentDateTimeUtc());
+ } else {
+ // prepare updated value as a copy of the value from the Base to be inserted
+ newCurValue = valueInBase->makeCopy(env);
+ if (newCurValue->current != extItem) {
+ newCurValue->current = std::move(extItem);
+ newCurValue->setCurrentExposedAt(QDateTime::currentDateTimeUtc());
+ }
+ }
+ // Before inserting new or updated value, check one more time, if ItemInfo is already
+ // present
+ // lookup<> can't be used here because of the data-race
+ {
+ QMutexLocker l(mutex());
+ auto &map = getMutableRefToMap<T>();
+ const auto &it = map.find(path);
+ if (it != map.end())
+ return { env.copy(*it), env.copy(*it) };
+ // otherwise insert
+ map.insert(path, newCurValue);
+ }
+ return { env.copy(valueInBase), env.copy(newCurValue) };
+ }
+
+ template <typename T>
+ void addExternalItemInfo(const DomItem &newExtItem, const Callback &loadCallback,
+ const Callback &endCallback)
+ {
+ // get either Valid "file" from the ExternalItemPair or the current (wip) "file"
+ std::shared_ptr<T> newItemPtr;
+ if (options() & DomEnvironment::Option::KeepValid)
+ newItemPtr = newExtItem.field(Fields::validItem).ownerAs<T>();
+ if (!newItemPtr)
+ newItemPtr = newExtItem.field(Fields::currentItem).ownerAs<T>();
+ Q_ASSERT(newItemPtr && "envCallbackForFile reached without current file");
+
+ auto loadResult = insertOrUpdateExternalItemInfo(newExtItem.canonicalFilePath(),
+ std::move(newItemPtr));
+ Path p = loadResult.currentItem.canonicalPath();
+ {
+ auto depLoad = qScopeGuard([p, this, endCallback] {
+ addDependenciesToLoad(p);
+ // add EndCallback to the queue, which should be called once all dependencies are
+ // loaded
+ if (endCallback) {
+ DomItem env = DomItem(shared_from_this());
+ addAllLoadedCallback(
+ env, [p, endCallback](Path, const DomItem &, const DomItem &env) {
+ DomItem el = env.path(p);
+ endCallback(p, el, el);
+ });
+ }
+ });
+ // call loadCallback
+ if (loadCallback) {
+ loadCallback(p, loadResult.formerItem, loadResult.currentItem);
+ }
+ }
+ }
+ void populateFromQmlFile(MutableDomItem &&qmlFile);
+ DomCreationOptions domCreationOptions() const { return m_domCreationOptions; }
+
+private:
+ friend class RefCacheEntry;
- std::shared_ptr<ExternalItemInfo<QmlFile>> addQmlFile(std::shared_ptr<QmlFile> file);
+ void loadFile(const FileToLoad &file, const Callback &loadCallback, const Callback &endCallback,
+ std::optional<DomType> fileType = std::optional<DomType>(),
+ const ErrorHandler &h = nullptr);
- void commitToBase(const DomItem &self);
+ void loadModuleDependency(const DomItem &self, const QString &uri, Version v,
+ Callback loadCallback = nullptr, Callback endCallback = nullptr,
+ const ErrorHandler & = nullptr);
- Options options() const {
- return m_options;
+ template <typename T>
+ QSet<QString> getStrings(function_ref<QSet<QString>()> getBase, const QMap<QString, T> &selfMap,
+ EnvLookup lookup) const;
+
+ template <typename T>
+ const QMap<QString, std::shared_ptr<ExternalItemInfo<T>>> &getConstRefToMap() const
+ {
+ Q_ASSERT(!mutex()->tryLock());
+ if constexpr (std::is_same_v<T, GlobalScope>) {
+ return m_globalScopeWithName;
+ }
+ if constexpr (std::is_same_v<T, QmlDirectory>) {
+ return m_qmlDirectoryWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmldirFile>) {
+ return m_qmldirFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmlFile>) {
+ return m_qmlFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, JsFile>) {
+ return m_jsFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmltypesFile>) {
+ return m_qmltypesFileWithPath;
+ }
+ Q_UNREACHABLE();
+ }
+
+ template <typename T>
+ std::shared_ptr<ExternalItemInfo<T>> lookup(const QString &path, EnvLookup options) const
+ {
+ if (options != EnvLookup::BaseOnly) {
+ QMutexLocker l(mutex());
+ const auto &map = getConstRefToMap<T>();
+ const auto &it = map.find(path);
+ if (it != map.end())
+ return *it;
+ }
+ if (options != EnvLookup::NoBase && m_base)
+ return m_base->lookup<T>(path, options);
+ return {};
}
- std::shared_ptr<DomEnvironment> base() const {
- return m_base;
+ template <typename T>
+ QMap<QString, std::shared_ptr<ExternalItemInfo<T>>> &getMutableRefToMap()
+ {
+ Q_ASSERT(!mutex()->tryLock());
+ if constexpr (std::is_same_v<T, QmlDirectory>) {
+ return m_qmlDirectoryWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmldirFile>) {
+ return m_qmldirFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmlFile>) {
+ return m_qmlFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, JsFile>) {
+ return m_jsFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmltypesFile>) {
+ return m_qmltypesFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, GlobalScope>) {
+ return m_globalScopeWithName;
+ }
+ Q_UNREACHABLE();
}
- QStringList loadPaths() const {
+ template <typename T>
+ void addExternalItem(std::shared_ptr<T> file, QString key, AddOption option)
+ {
+ if (!file)
+ return;
+
+ auto eInfo = std::make_shared<ExternalItemInfo<T>>(file, QDateTime::currentDateTimeUtc());
+ // Lookup helper can't be used here, because it introduces data-race otherwise
+ // (other modifications might happen between the lookup and the insert)
QMutexLocker l(mutex());
- return m_loadPaths;
+ auto &map = getMutableRefToMap<T>();
+ const auto &it = map.find(key);
+ if (it != map.end() && option == AddOption::KeepExisting)
+ return;
+ map.insert(key, eInfo);
}
-private:
+ using FetchResult =
+ QPair<std::shared_ptr<ExternalItemInfoBase>, std::shared_ptr<ExternalItemInfoBase>>;
+ // This function tries to get an Info object about the ExternalItem from the current env
+ // and depending on the result and options tries to fetch it from the Parent env,
+ // saving a copy with an updated timestamp
+ template <typename T>
+ FetchResult fetchFileFromEnvs(const FileToLoad &file)
+ {
+ const auto &path = file.canonicalPath();
+ // lookup only in the current env
+ if (auto value = lookup<T>(path, EnvLookup::NoBase)) {
+ return qMakePair(value, value);
+ }
+ // try to find the file in the base(parent) Env and insert if found
+ if (options() & Option::NoReload) {
+ if (auto baseV = lookup<T>(path, EnvLookup::BaseOnly)) {
+ // Watch out! QTBUG-121171
+ // It's possible between the lookup and creation of curVal, baseV && baseV->current
+ // might have changed
+ // Prepare a value to be inserted as copy of the value from Base
+ auto curV = std::make_shared<ExternalItemInfo<T>>(
+ baseV->current, QDateTime::currentDateTimeUtc(), baseV->revision(),
+ baseV->lastDataUpdateAt());
+ // Lookup one more time if the value was already inserted to the current env
+ // Lookup can't be used here because of the data-race
+ {
+ QMutexLocker l(mutex());
+ auto &map = getMutableRefToMap<T>();
+ const auto &it = map.find(path);
+ if (it != map.end())
+ return qMakePair(*it, *it);
+ // otherwise insert
+ map.insert(path, curV);
+ }
+ return qMakePair(baseV, curV);
+ }
+ }
+ return qMakePair(nullptr, nullptr);
+ }
+
+ Callback getLoadCallbackFor(DomType fileType, const Callback &loadCallback);
+
+ std::shared_ptr<ModuleIndex> lookupModuleInEnv(const QString &uri, int majorVersion) const;
+ // ModuleLookupResult contains the ModuleIndex pointer, and an indicator whether it was found
+ // in m_base or in m_moduleIndexWithUri
+ struct ModuleLookupResult {
+ enum Origin : bool {FromBase, FromGlobal};
+ std::shared_ptr<ModuleIndex> module;
+ Origin fromBase = FromGlobal;
+ };
+ // helper function used by the moduleIndexWithUri methods
+ ModuleLookupResult moduleIndexWithUriHelper(const DomItem &self, const QString &uri, int majorVersion,
+ EnvLookup lookup = EnvLookup::Normal) const;
+
const Options m_options;
const std::shared_ptr<DomEnvironment> m_base;
+ std::shared_ptr<DomEnvironment> m_lastValidBase;
const std::shared_ptr<DomUniverse> m_universe;
QStringList m_loadPaths; // paths for qml
- bool m_singleThreadedLoadInProgress = false;
+ QString m_globalScopeName;
+ QMap<QString, QMap<int, std::shared_ptr<ModuleIndex>>> m_moduleIndexWithUri;
+ QMap<QString, std::shared_ptr<ExternalItemInfo<GlobalScope>>> m_globalScopeWithName;
+ QMap<QString, std::shared_ptr<ExternalItemInfo<QmlDirectory>>> m_qmlDirectoryWithPath;
+ QMap<QString, std::shared_ptr<ExternalItemInfo<QmldirFile>>> m_qmldirFileWithPath;
+ QMap<QString, std::shared_ptr<ExternalItemInfo<QmlFile>>> m_qmlFileWithPath;
+ QMap<QString, std::shared_ptr<ExternalItemInfo<JsFile>>> m_jsFileWithPath;
+ QMap<QString, std::shared_ptr<ExternalItemInfo<QmltypesFile>>> m_qmltypesFileWithPath;
QQueue<Path> m_loadsWithWork;
QQueue<Path> m_inProgress;
+ QHash<Path, std::shared_ptr<LoadInfo>> m_loadInfos;
+ QList<Import> m_implicitImports;
QList<Callback> m_allLoadedCallback;
+ QHash<Path, RefCacheEntry> m_referenceCache;
+ DomCreationOptions m_domCreationOptions;
+
+ struct SemanticAnalysis
+ {
+ SemanticAnalysis(const QStringList &loadPaths);
+ void setLoadPaths(const QStringList &loadPaths);
+
+ std::shared_ptr<QQmlJSResourceFileMapper> m_mapper;
+ std::shared_ptr<QQmlJSImporter> m_importer;
+ };
+ std::optional<SemanticAnalysis> m_semanticAnalysis;
+ SemanticAnalysis &semanticAnalysis();
};
Q_DECLARE_OPERATORS_FOR_FLAGS(DomEnvironment::Options)