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 | #ifndef DOMTOP_H |
5 | #define DOMTOP_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include "qqmldomitem_p.h" |
19 | #include "qqmldomelements_p.h" |
20 | #include "qqmldomexternalitems_p.h" |
21 | |
22 | #include <QtCore/QQueue> |
23 | #include <QtCore/QString> |
24 | #include <QtCore/QDateTime> |
25 | |
26 | #include <QtCore/QCborValue> |
27 | #include <QtCore/QCborMap> |
28 | |
29 | #include <memory> |
30 | #include <optional> |
31 | |
32 | QT_BEGIN_NAMESPACE |
33 | |
34 | using namespace Qt::Literals::StringLiterals; |
35 | |
36 | namespace QQmlJS { |
37 | namespace Dom { |
38 | |
39 | class QMLDOM_EXPORT ParsingTask { |
40 | public: |
41 | QCborMap toCbor() const { |
42 | return QCborMap({ { QString::fromUtf16(Fields::requestedAt), QCborValue(requestedAt) }, |
43 | { QString::fromUtf16(Fields::loadOptions), int(loadOptions) }, |
44 | { QString::fromUtf16(Fields::kind), int(kind) }, |
45 | { QString::fromUtf16(Fields::canonicalPath), file.canonicalPath() }, |
46 | { QString::fromUtf16(Fields::logicalPath), file.logicalPath() }, |
47 | { QString::fromUtf16(Fields::contents), |
48 | file.content() ? file.content()->data : QString() }, |
49 | { QString::fromUtf16(Fields::contentsDate), |
50 | QCborValue(file.content() ? file.content()->date |
51 | : QDateTime::fromMSecsSinceEpoch( |
52 | msecs: 0, timeZone: QTimeZone::UTC)) }, |
53 | { QString::fromUtf16(Fields::hasCallback), bool(callback) } }); |
54 | } |
55 | |
56 | QDateTime requestedAt; |
57 | LoadOptions loadOptions; |
58 | DomType kind; |
59 | FileToLoad file; |
60 | std::weak_ptr<DomUniverse> requestingUniverse; // make it a shared_ptr? |
61 | function<void(Path, DomItem &, DomItem &)> callback; |
62 | }; |
63 | |
64 | class QMLDOM_EXPORT ExternalItemPairBase: public OwningItem { // all access should have the lock of the DomUniverse containing this |
65 | Q_DECLARE_TR_FUNCTIONS(ExternalItemPairBase); |
66 | public: |
67 | constexpr static DomType kindValue = DomType::ExternalItemPair; |
68 | DomType kind() const final override { return kindValue; } |
69 | ExternalItemPairBase(QDateTime validExposedAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC), |
70 | QDateTime currentExposedAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC), |
71 | int derivedFrom = 0, |
72 | QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC)) |
73 | : OwningItem(derivedFrom, lastDataUpdateAt), |
74 | validExposedAt(validExposedAt), |
75 | currentExposedAt(currentExposedAt) |
76 | {} |
77 | ExternalItemPairBase(const ExternalItemPairBase &o): |
78 | OwningItem(o), validExposedAt(o.validExposedAt), currentExposedAt(o.currentExposedAt) |
79 | {} |
80 | virtual std::shared_ptr<ExternalOwningItem> validItem() const = 0; |
81 | virtual DomItem validItem(DomItem &self) const = 0; |
82 | virtual std::shared_ptr<ExternalOwningItem> currentItem() const = 0; |
83 | virtual DomItem currentItem(DomItem &self) const = 0; |
84 | |
85 | QString canonicalFilePath(DomItem &) const final override; |
86 | Path canonicalPath(DomItem &self) const final override; |
87 | bool iterateDirectSubpaths(DomItem &self, DirectVisitor) final override; |
88 | DomItem field(DomItem &self, QStringView name) const final override |
89 | { |
90 | return OwningItem::field(self, name); |
91 | } |
92 | |
93 | bool currentIsValid() const; |
94 | |
95 | std::shared_ptr<ExternalItemPairBase> makeCopy(DomItem &self) const |
96 | { |
97 | return std::static_pointer_cast<ExternalItemPairBase>(r: doCopy(self)); |
98 | } |
99 | |
100 | QDateTime lastDataUpdateAt() const final override |
101 | { |
102 | if (currentItem()) |
103 | return currentItem()->lastDataUpdateAt(); |
104 | return ExternalItemPairBase::lastDataUpdateAt(); |
105 | } |
106 | |
107 | void refreshedDataAt(QDateTime tNew) final override |
108 | { |
109 | return OwningItem::refreshedDataAt(tNew); |
110 | if (currentItem()) |
111 | currentItem()->refreshedDataAt(tNew); |
112 | } |
113 | |
114 | friend class DomUniverse; |
115 | |
116 | QDateTime validExposedAt; |
117 | QDateTime currentExposedAt; |
118 | }; |
119 | |
120 | template<class T> |
121 | class QMLDOM_EXPORT ExternalItemPair final : public ExternalItemPairBase |
122 | { // all access should have the lock of the DomUniverse containing this |
123 | protected: |
124 | std::shared_ptr<OwningItem> doCopy(DomItem &) const override |
125 | { |
126 | return std::make_shared<ExternalItemPair>(*this); |
127 | } |
128 | |
129 | public: |
130 | constexpr static DomType kindValue = DomType::ExternalItemPair; |
131 | friend class DomUniverse; |
132 | ExternalItemPair(std::shared_ptr<T> valid = {}, std::shared_ptr<T> current = {}, |
133 | QDateTime validExposedAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC), |
134 | QDateTime currentExposedAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC), |
135 | int derivedFrom = 0, |
136 | QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC)) |
137 | : ExternalItemPairBase(validExposedAt, currentExposedAt, derivedFrom, lastDataUpdateAt), |
138 | valid(valid), |
139 | current(current) |
140 | {} |
141 | ExternalItemPair(const ExternalItemPair &o): |
142 | ExternalItemPairBase(o), valid(o.valid), current(o.current) |
143 | { |
144 | } |
145 | std::shared_ptr<ExternalOwningItem> validItem() const override { return valid; } |
146 | DomItem validItem(DomItem &self) const override { return self.copy(valid); } |
147 | std::shared_ptr<ExternalOwningItem> currentItem() const override { return current; } |
148 | DomItem currentItem(DomItem &self) const override { return self.copy(current); } |
149 | std::shared_ptr<ExternalItemPair> makeCopy(DomItem &self) const |
150 | { |
151 | return std::static_pointer_cast<ExternalItemPair>(doCopy(self)); |
152 | } |
153 | |
154 | std::shared_ptr<T> valid; |
155 | std::shared_ptr<T> current; |
156 | }; |
157 | |
158 | class QMLDOM_EXPORT DomTop: public OwningItem { |
159 | public: |
160 | DomTop(QMap<QString, OwnerT> = {}, int derivedFrom = 0) |
161 | : OwningItem(derivedFrom), m_extraOwningItems(extraOwningItems) |
162 | {} |
163 | DomTop(const DomTop &o): |
164 | OwningItem(o) |
165 | { |
166 | QMap<QString, OwnerT> items = o.extraOwningItems(); |
167 | { |
168 | QMutexLocker l(mutex()); |
169 | m_extraOwningItems = items; |
170 | } |
171 | } |
172 | using Callback = DomItem::Callback; |
173 | |
174 | virtual Path canonicalPath() const = 0; |
175 | |
176 | Path canonicalPath(DomItem &) const override; |
177 | DomItem containingObject(DomItem &) const override; |
178 | bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override; |
179 | template<typename T> |
180 | void (QString fieldName, std::shared_ptr<T> item) |
181 | { |
182 | QMutexLocker l(mutex()); |
183 | if (!item) |
184 | m_extraOwningItems.remove(key: fieldName); |
185 | else |
186 | m_extraOwningItems.insert(fieldName, item); |
187 | } |
188 | |
189 | void (); |
190 | QMap<QString, OwnerT> () const; |
191 | |
192 | private: |
193 | QMap<QString, OwnerT> ; |
194 | }; |
195 | |
196 | class QMLDOM_EXPORT DomUniverse final : public DomTop |
197 | { |
198 | Q_GADGET |
199 | Q_DECLARE_TR_FUNCTIONS(DomUniverse); |
200 | protected: |
201 | std::shared_ptr<OwningItem> doCopy(DomItem &self) const override; |
202 | |
203 | public: |
204 | enum class Option{ |
205 | Default, |
206 | SingleThreaded |
207 | }; |
208 | Q_ENUM(Option) |
209 | Q_DECLARE_FLAGS(Options, Option); |
210 | constexpr static DomType kindValue = DomType::DomUniverse; |
211 | DomType kind() const override { return kindValue; } |
212 | |
213 | static ErrorGroups myErrors(); |
214 | |
215 | DomUniverse(QString universeName, Options options = Option::SingleThreaded); |
216 | DomUniverse(const DomUniverse &) = delete; |
217 | static std::shared_ptr<DomUniverse> guaranteeUniverse(std::shared_ptr<DomUniverse> univ); |
218 | static DomItem create(QString universeName, Options options = Option::SingleThreaded); |
219 | |
220 | Path canonicalPath() const override; |
221 | using DomTop::canonicalPath; |
222 | bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override; |
223 | std::shared_ptr<DomUniverse> makeCopy(DomItem &self) const |
224 | { |
225 | return std::static_pointer_cast<DomUniverse>(r: doCopy(self)); |
226 | } |
227 | |
228 | void loadFile(DomItem &self, const FileToLoad &file, Callback callback, LoadOptions loadOptions, |
229 | std::optional<DomType> fileType = std::optional<DomType>()); |
230 | void execQueue(); |
231 | |
232 | void removePath(const QString &dir); |
233 | |
234 | std::shared_ptr<ExternalItemPair<GlobalScope>> globalScopeWithName(QString name) const |
235 | { |
236 | QMutexLocker l(mutex()); |
237 | return m_globalScopeWithName.value(key: name); |
238 | } |
239 | |
240 | std::shared_ptr<ExternalItemPair<GlobalScope>> ensureGlobalScopeWithName(QString name) |
241 | { |
242 | if (auto current = globalScopeWithName(name)) |
243 | return current; |
244 | auto newScope = std::make_shared<GlobalScope>(args&: name); |
245 | auto newValue = std::make_shared<ExternalItemPair<GlobalScope>>( |
246 | args&: newScope, args&: newScope); |
247 | QMutexLocker l(mutex()); |
248 | if (auto current = m_globalScopeWithName.value(key: name)) |
249 | return current; |
250 | m_globalScopeWithName.insert(key: name, value: newValue); |
251 | return newValue; |
252 | } |
253 | |
254 | QSet<QString> globalScopeNames() const |
255 | { |
256 | QMap<QString, std::shared_ptr<ExternalItemPair<GlobalScope>>> map; |
257 | { |
258 | QMutexLocker l(mutex()); |
259 | map = m_globalScopeWithName; |
260 | } |
261 | return QSet<QString>(map.keyBegin(), map.keyEnd()); |
262 | } |
263 | |
264 | std::shared_ptr<ExternalItemPair<QmlDirectory>> qmlDirectoryWithPath(QString path) const |
265 | { |
266 | QMutexLocker l(mutex()); |
267 | return m_qmlDirectoryWithPath.value(key: path); |
268 | } |
269 | QSet<QString> qmlDirectoryPaths() const |
270 | { |
271 | QMap<QString, std::shared_ptr<ExternalItemPair<QmlDirectory>>> map; |
272 | { |
273 | QMutexLocker l(mutex()); |
274 | map = m_qmlDirectoryWithPath; |
275 | } |
276 | return QSet<QString>(map.keyBegin(), map.keyEnd()); |
277 | } |
278 | |
279 | std::shared_ptr<ExternalItemPair<QmldirFile>> qmldirFileWithPath(QString path) const |
280 | { |
281 | QMutexLocker l(mutex()); |
282 | return m_qmldirFileWithPath.value(key: path); |
283 | } |
284 | QSet<QString> qmldirFilePaths() const |
285 | { |
286 | QMap<QString, std::shared_ptr<ExternalItemPair<QmldirFile>>> map; |
287 | { |
288 | QMutexLocker l(mutex()); |
289 | map = m_qmldirFileWithPath; |
290 | } |
291 | return QSet<QString>(map.keyBegin(), map.keyEnd()); |
292 | } |
293 | |
294 | std::shared_ptr<ExternalItemPair<QmlFile>> qmlFileWithPath(QString path) const |
295 | { |
296 | QMutexLocker l(mutex()); |
297 | return m_qmlFileWithPath.value(key: path); |
298 | } |
299 | QSet<QString> qmlFilePaths() const |
300 | { |
301 | QMap<QString, std::shared_ptr<ExternalItemPair<QmlFile>>> map; |
302 | { |
303 | QMutexLocker l(mutex()); |
304 | map = m_qmlFileWithPath; |
305 | } |
306 | return QSet<QString>(map.keyBegin(), map.keyEnd()); |
307 | } |
308 | |
309 | std::shared_ptr<ExternalItemPair<JsFile>> jsFileWithPath(QString path) const |
310 | { |
311 | QMutexLocker l(mutex()); |
312 | return m_jsFileWithPath.value(key: path); |
313 | } |
314 | QSet<QString> jsFilePaths() const |
315 | { |
316 | QMap<QString, std::shared_ptr<ExternalItemPair<JsFile>>> map; |
317 | { |
318 | QMutexLocker l(mutex()); |
319 | map = m_jsFileWithPath; |
320 | } |
321 | return QSet<QString>(map.keyBegin(), map.keyEnd()); |
322 | } |
323 | |
324 | std::shared_ptr<ExternalItemPair<QmltypesFile>> qmltypesFileWithPath(QString path) const |
325 | { |
326 | QMutexLocker l(mutex()); |
327 | return m_qmltypesFileWithPath.value(key: path); |
328 | } |
329 | QSet<QString> qmltypesFilePaths() const |
330 | { |
331 | QMap<QString, std::shared_ptr<ExternalItemPair<QmltypesFile>>> map; |
332 | { |
333 | QMutexLocker l(mutex()); |
334 | map = m_qmltypesFileWithPath; |
335 | } |
336 | return QSet<QString>(map.keyBegin(), map.keyEnd()); |
337 | } |
338 | |
339 | QString name() const { |
340 | return m_name; |
341 | } |
342 | Options options() const { |
343 | return m_options; |
344 | } |
345 | QQueue<ParsingTask> queue() const { |
346 | QMutexLocker l(mutex()); |
347 | return m_queue; |
348 | } |
349 | |
350 | private: |
351 | QString m_name; |
352 | Options m_options; |
353 | QMap<QString, std::shared_ptr<ExternalItemPair<GlobalScope>>> m_globalScopeWithName; |
354 | QMap<QString, std::shared_ptr<ExternalItemPair<QmlDirectory>>> m_qmlDirectoryWithPath; |
355 | QMap<QString, std::shared_ptr<ExternalItemPair<QmldirFile>>> m_qmldirFileWithPath; |
356 | QMap<QString, std::shared_ptr<ExternalItemPair<QmlFile>>> m_qmlFileWithPath; |
357 | QMap<QString, std::shared_ptr<ExternalItemPair<JsFile>>> m_jsFileWithPath; |
358 | QMap<QString, std::shared_ptr<ExternalItemPair<QmltypesFile>>> m_qmltypesFileWithPath; |
359 | QQueue<ParsingTask> m_queue; |
360 | }; |
361 | |
362 | Q_DECLARE_OPERATORS_FOR_FLAGS(DomUniverse::Options) |
363 | |
364 | class QMLDOM_EXPORT ExternalItemInfoBase: public OwningItem { |
365 | Q_DECLARE_TR_FUNCTIONS(ExternalItemInfoBase); |
366 | public: |
367 | constexpr static DomType kindValue = DomType::ExternalItemInfo; |
368 | DomType kind() const final override { return kindValue; } |
369 | ExternalItemInfoBase(Path canonicalPath, |
370 | QDateTime currentExposedAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC), |
371 | int derivedFrom = 0, |
372 | QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC)) |
373 | : OwningItem(derivedFrom, lastDataUpdateAt), |
374 | m_canonicalPath(canonicalPath), |
375 | m_currentExposedAt(currentExposedAt) |
376 | {} |
377 | ExternalItemInfoBase(const ExternalItemInfoBase &o) = default; |
378 | |
379 | virtual std::shared_ptr<ExternalOwningItem> currentItem() const = 0; |
380 | virtual DomItem currentItem(DomItem &) const = 0; |
381 | |
382 | QString canonicalFilePath(DomItem &) const final override; |
383 | Path canonicalPath() const { return m_canonicalPath; } |
384 | Path canonicalPath(DomItem &) const final override { return canonicalPath(); } |
385 | bool iterateDirectSubpaths(DomItem &self, DirectVisitor) final override; |
386 | DomItem field(DomItem &self, QStringView name) const final override |
387 | { |
388 | return OwningItem::field(self, name); |
389 | } |
390 | |
391 | int currentRevision(DomItem &self) const; |
392 | int lastRevision(DomItem &self) const; |
393 | int lastValidRevision(DomItem &self) const; |
394 | |
395 | std::shared_ptr<ExternalItemInfoBase> makeCopy(DomItem &self) const |
396 | { |
397 | return std::static_pointer_cast<ExternalItemInfoBase>(r: doCopy(self)); |
398 | } |
399 | |
400 | QDateTime lastDataUpdateAt() const final override |
401 | { |
402 | if (currentItem()) |
403 | return currentItem()->lastDataUpdateAt(); |
404 | return OwningItem::lastDataUpdateAt(); |
405 | } |
406 | |
407 | void refreshedDataAt(QDateTime tNew) final override |
408 | { |
409 | return OwningItem::refreshedDataAt(tNew); |
410 | if (currentItem()) |
411 | currentItem()->refreshedDataAt(tNew); |
412 | } |
413 | |
414 | void ensureLogicalFilePath(QString path) { |
415 | QMutexLocker l(mutex()); |
416 | if (!m_logicalFilePaths.contains(str: path)) |
417 | m_logicalFilePaths.append(t: path); |
418 | } |
419 | |
420 | QDateTime currentExposedAt() const { |
421 | QMutexLocker l(mutex()); // should not be needed, as it should not change... |
422 | return m_currentExposedAt; |
423 | } |
424 | |
425 | void setCurrentExposedAt(QDateTime d) { |
426 | QMutexLocker l(mutex()); // should not be needed, as it should not change... |
427 | m_currentExposedAt = d; |
428 | } |
429 | |
430 | |
431 | QStringList logicalFilePaths() const { |
432 | QMutexLocker l(mutex()); |
433 | return m_logicalFilePaths; |
434 | } |
435 | |
436 | private: |
437 | friend class DomEnvironment; |
438 | Path m_canonicalPath; |
439 | QDateTime m_currentExposedAt; |
440 | QStringList m_logicalFilePaths; |
441 | }; |
442 | |
443 | template<typename T> |
444 | class ExternalItemInfo final : public ExternalItemInfoBase |
445 | { |
446 | protected: |
447 | std::shared_ptr<OwningItem> doCopy(DomItem &) const override |
448 | { |
449 | return std::make_shared<ExternalItemInfo>(*this); |
450 | } |
451 | |
452 | public: |
453 | constexpr static DomType kindValue = DomType::ExternalItemInfo; |
454 | ExternalItemInfo(std::shared_ptr<T> current = std::shared_ptr<T>(), |
455 | QDateTime currentExposedAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC), |
456 | int derivedFrom = 0, |
457 | QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC)) |
458 | : ExternalItemInfoBase(current->canonicalPath().dropTail(), currentExposedAt, derivedFrom, |
459 | lastDataUpdateAt), |
460 | current(current) |
461 | {} |
462 | ExternalItemInfo(QString canonicalPath) : current(new T(canonicalPath)) { } |
463 | ExternalItemInfo(const ExternalItemInfo &o): |
464 | ExternalItemInfoBase(o), current(o.current) |
465 | { |
466 | } |
467 | |
468 | std::shared_ptr<ExternalItemInfo> makeCopy(DomItem &self) const |
469 | { |
470 | return std::static_pointer_cast<ExternalItemInfo>(doCopy(self)); |
471 | } |
472 | |
473 | std::shared_ptr<ExternalOwningItem> currentItem() const override { |
474 | return current; |
475 | } |
476 | DomItem currentItem(DomItem &self) const override { return self.copy(current); } |
477 | |
478 | std::shared_ptr<T> current; |
479 | }; |
480 | |
481 | class Dependency |
482 | { // internal, should be cleaned, but nobody should use this... |
483 | public: |
484 | bool operator==(Dependency const &o) const |
485 | { |
486 | return uri == o.uri && version.majorVersion == o.version.majorVersion |
487 | && version.minorVersion == o.version.minorVersion && filePath == o.filePath; |
488 | } |
489 | QString uri; // either dotted uri or file:, http: https: uri |
490 | Version version; |
491 | QString filePath; // for file deps |
492 | DomType fileType; |
493 | }; |
494 | |
495 | class QMLDOM_EXPORT LoadInfo final : public OwningItem |
496 | { |
497 | Q_DECLARE_TR_FUNCTIONS(LoadInfo); |
498 | |
499 | protected: |
500 | std::shared_ptr<OwningItem> doCopy(DomItem &self) const override; |
501 | |
502 | public: |
503 | constexpr static DomType kindValue = DomType::LoadInfo; |
504 | DomType kind() const override { return kindValue; } |
505 | |
506 | enum class Status { |
507 | NotStarted, // dependencies non checked yet |
508 | Starting, // adding deps |
509 | InProgress, // waiting for all deps to be loaded |
510 | CallingCallbacks, // calling callbacks |
511 | Done // fully loaded |
512 | }; |
513 | |
514 | LoadInfo(Path elPath = Path(), Status status = Status::NotStarted, int nLoaded = 0, |
515 | int derivedFrom = 0, |
516 | QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC)) |
517 | : OwningItem(derivedFrom, lastDataUpdateAt), |
518 | m_elementCanonicalPath(elPath), |
519 | m_status(status), |
520 | m_nLoaded(nLoaded) |
521 | { |
522 | } |
523 | LoadInfo(const LoadInfo &o) : OwningItem(o), m_elementCanonicalPath(o.elementCanonicalPath()) |
524 | { |
525 | { |
526 | QMutexLocker l(o.mutex()); |
527 | m_status = o.m_status; |
528 | m_nLoaded = o.m_nLoaded; |
529 | m_toDo = o.m_toDo; |
530 | m_inProgress = o.m_inProgress; |
531 | m_endCallbacks = o.m_endCallbacks; |
532 | } |
533 | } |
534 | |
535 | Path canonicalPath(DomItem &self) const override; |
536 | |
537 | bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override; |
538 | std::shared_ptr<LoadInfo> makeCopy(DomItem &self) const |
539 | { |
540 | return std::static_pointer_cast<LoadInfo>(r: doCopy(self)); |
541 | } |
542 | void addError(DomItem &self, ErrorMessage msg) override |
543 | { |
544 | self.path(p: elementCanonicalPath()).addError(msg); |
545 | } |
546 | |
547 | void addEndCallback(DomItem &self, std::function<void(Path, DomItem &, DomItem &)> callback); |
548 | |
549 | void advanceLoad(DomItem &self); |
550 | void finishedLoadingDep(DomItem &self, const Dependency &d); |
551 | void execEnd(DomItem &self); |
552 | |
553 | Status status() const |
554 | { |
555 | QMutexLocker l(mutex()); |
556 | return m_status; |
557 | } |
558 | |
559 | int nLoaded() const |
560 | { |
561 | QMutexLocker l(mutex()); |
562 | return m_nLoaded; |
563 | } |
564 | |
565 | Path elementCanonicalPath() const |
566 | { |
567 | QMutexLocker l(mutex()); // we should never change this, remove lock? |
568 | return m_elementCanonicalPath; |
569 | } |
570 | |
571 | int nNotDone() const |
572 | { |
573 | QMutexLocker l(mutex()); |
574 | return m_toDo.size() + m_inProgress.size(); |
575 | } |
576 | |
577 | QList<Dependency> inProgress() const |
578 | { |
579 | QMutexLocker l(mutex()); |
580 | return m_inProgress; |
581 | } |
582 | |
583 | QList<Dependency> toDo() const |
584 | { |
585 | QMutexLocker l(mutex()); |
586 | return m_toDo; |
587 | } |
588 | |
589 | int nCallbacks() const |
590 | { |
591 | QMutexLocker l(mutex()); |
592 | return m_endCallbacks.size(); |
593 | } |
594 | |
595 | private: |
596 | void doAddDependencies(DomItem &self); |
597 | void addDependency(DomItem &self, const Dependency &dep); |
598 | |
599 | Path m_elementCanonicalPath; |
600 | Status m_status; |
601 | int m_nLoaded; |
602 | QQueue<Dependency> m_toDo; |
603 | QList<Dependency> m_inProgress; |
604 | QList<std::function<void(Path, DomItem &, DomItem &)>> m_endCallbacks; |
605 | }; |
606 | |
607 | enum class EnvLookup { Normal, NoBase, BaseOnly }; |
608 | |
609 | enum class Changeable { ReadOnly, Writable }; |
610 | |
611 | class QMLDOM_EXPORT RefCacheEntry |
612 | { |
613 | Q_GADGET |
614 | public: |
615 | enum class Cached { None, First, All }; |
616 | Q_ENUM(Cached) |
617 | |
618 | static RefCacheEntry forPath(DomItem &el, Path canonicalPath); |
619 | static bool addForPath(DomItem &el, Path canonicalPath, const RefCacheEntry &entry, |
620 | AddOption addOption = AddOption::KeepExisting); |
621 | |
622 | Cached cached = Cached::None; |
623 | QList<Path> canonicalPaths; |
624 | }; |
625 | |
626 | class QMLDOM_EXPORT DomEnvironment final : public DomTop |
627 | { |
628 | Q_GADGET |
629 | Q_DECLARE_TR_FUNCTIONS(DomEnvironment); |
630 | protected: |
631 | std::shared_ptr<OwningItem> doCopy(DomItem &self) const override; |
632 | |
633 | public: |
634 | enum class Option { |
635 | Default = 0x0, |
636 | KeepValid = 0x1, // if there is a previous valid version, use that instead of the latest |
637 | Exported = 0x2, // the current environment is accessible by multiple threads, one should only modify whole OwningItems, and in general load and do other operations in other (Child) environments |
638 | NoReload = 0x4, // never reload something that was already loaded by the parent environment |
639 | WeakLoad = 0x8, // load only the names of the available types, not the types (qml files) themselves |
640 | SingleThreaded = 0x10, // do all operations in a single thread |
641 | NoDependencies = 0x20 // will not load dependencies (useful when editing) |
642 | }; |
643 | Q_ENUM(Option) |
644 | Q_DECLARE_FLAGS(Options, Option); |
645 | |
646 | static ErrorGroups myErrors(); |
647 | constexpr static DomType kindValue = DomType::DomEnvironment; |
648 | DomType kind() const override; |
649 | |
650 | Path canonicalPath() const override; |
651 | using DomTop::canonicalPath; |
652 | bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override; |
653 | DomItem field(DomItem &self, QStringView name) const final override; |
654 | |
655 | std::shared_ptr<DomEnvironment> makeCopy(DomItem &self) const; |
656 | |
657 | void loadFile(DomItem &self, FileToLoad file, Callback loadCallback, |
658 | Callback directDepsCallback, Callback endCallback, LoadOptions loadOptions, |
659 | std::optional<DomType> fileType = std::optional<DomType>(), |
660 | ErrorHandler h = nullptr); |
661 | void loadModuleDependency(DomItem &self, QString uri, Version v, |
662 | Callback loadCallback = nullptr, Callback endCallback = nullptr, |
663 | ErrorHandler = nullptr); |
664 | void loadBuiltins(DomItem &self, Callback callback = nullptr, ErrorHandler h = nullptr); |
665 | void removePath(const QString &path); |
666 | |
667 | std::shared_ptr<DomUniverse> universe() const; |
668 | |
669 | QSet<QString> moduleIndexUris(DomItem &self, EnvLookup lookup = EnvLookup::Normal) const; |
670 | QSet<int> moduleIndexMajorVersions(DomItem &self, QString uri, |
671 | EnvLookup lookup = EnvLookup::Normal) const; |
672 | std::shared_ptr<ModuleIndex> moduleIndexWithUri(DomItem &self, QString uri, int majorVersion, |
673 | EnvLookup lookup, Changeable changeable, |
674 | ErrorHandler errorHandler = nullptr); |
675 | std::shared_ptr<ModuleIndex> moduleIndexWithUri(DomItem &self, QString uri, int majorVersion, |
676 | EnvLookup lookup = EnvLookup::Normal) const; |
677 | std::shared_ptr<ExternalItemInfo<QmlDirectory>> |
678 | qmlDirectoryWithPath(DomItem &self, QString path, EnvLookup options = EnvLookup::Normal) const; |
679 | QSet<QString> qmlDirectoryPaths(DomItem &self, EnvLookup options = EnvLookup::Normal) const; |
680 | std::shared_ptr<ExternalItemInfo<QmldirFile>> |
681 | qmldirFileWithPath(DomItem &self, QString path, EnvLookup options = EnvLookup::Normal) const; |
682 | QSet<QString> qmldirFilePaths(DomItem &self, EnvLookup options = EnvLookup::Normal) const; |
683 | std::shared_ptr<ExternalItemInfoBase> |
684 | qmlDirWithPath(DomItem &self, QString path, EnvLookup options = EnvLookup::Normal) const; |
685 | QSet<QString> qmlDirPaths(DomItem &self, EnvLookup options = EnvLookup::Normal) const; |
686 | std::shared_ptr<ExternalItemInfo<QmlFile>> |
687 | qmlFileWithPath(DomItem &self, QString path, EnvLookup options = EnvLookup::Normal) const; |
688 | QSet<QString> qmlFilePaths(DomItem &self, EnvLookup lookup = EnvLookup::Normal) const; |
689 | std::shared_ptr<ExternalItemInfo<JsFile>> |
690 | jsFileWithPath(DomItem &self, QString path, EnvLookup options = EnvLookup::Normal) const; |
691 | QSet<QString> jsFilePaths(DomItem &self, EnvLookup lookup = EnvLookup::Normal) const; |
692 | std::shared_ptr<ExternalItemInfo<QmltypesFile>> |
693 | qmltypesFileWithPath(DomItem &self, QString path, EnvLookup options = EnvLookup::Normal) const; |
694 | QSet<QString> qmltypesFilePaths(DomItem &self, EnvLookup lookup = EnvLookup::Normal) const; |
695 | std::shared_ptr<ExternalItemInfo<GlobalScope>> |
696 | globalScopeWithName(DomItem &self, QString name, EnvLookup lookup = EnvLookup::Normal) const; |
697 | std::shared_ptr<ExternalItemInfo<GlobalScope>> |
698 | ensureGlobalScopeWithName(DomItem &self, QString name, EnvLookup lookup = EnvLookup::Normal); |
699 | QSet<QString> globalScopeNames(DomItem &self, EnvLookup lookup = EnvLookup::Normal) const; |
700 | |
701 | explicit DomEnvironment(QStringList loadPaths, Options options = Option::SingleThreaded, |
702 | std::shared_ptr<DomUniverse> universe = nullptr); |
703 | explicit DomEnvironment(std::shared_ptr<DomEnvironment> parent, QStringList loadPaths, |
704 | Options options = Option::SingleThreaded); |
705 | DomEnvironment(const DomEnvironment &o) = delete; |
706 | static DomItem create(QStringList loadPaths, Options options = Option::SingleThreaded, |
707 | DomItem &universe = DomItem::empty); |
708 | |
709 | std::shared_ptr<ExternalItemInfo<QmlFile>> |
710 | addQmlFile(std::shared_ptr<QmlFile> file, AddOption option = AddOption::KeepExisting); |
711 | std::shared_ptr<ExternalItemInfo<QmlDirectory>> |
712 | addQmlDirectory(std::shared_ptr<QmlDirectory> file, AddOption option = AddOption::KeepExisting); |
713 | std::shared_ptr<ExternalItemInfo<QmldirFile>> |
714 | addQmldirFile(std::shared_ptr<QmldirFile> file, AddOption option = AddOption::KeepExisting); |
715 | std::shared_ptr<ExternalItemInfo<QmltypesFile>> |
716 | addQmltypesFile(std::shared_ptr<QmltypesFile> file, AddOption option = AddOption::KeepExisting); |
717 | std::shared_ptr<ExternalItemInfo<JsFile>> addJsFile(std::shared_ptr<JsFile> file, |
718 | AddOption option = AddOption::KeepExisting); |
719 | std::shared_ptr<ExternalItemInfo<GlobalScope>> |
720 | addGlobalScope(std::shared_ptr<GlobalScope> file, AddOption option = AddOption::KeepExisting); |
721 | |
722 | bool commitToBase(DomItem &self, std::shared_ptr<DomEnvironment> validEnv = nullptr); |
723 | |
724 | void addLoadInfo(DomItem &self, std::shared_ptr<LoadInfo> loadInfo); |
725 | std::shared_ptr<LoadInfo> loadInfo(Path path) const; |
726 | QList<Path> loadInfoPaths() const; |
727 | QHash<Path, std::shared_ptr<LoadInfo>> loadInfos() const; |
728 | void loadPendingDependencies(DomItem &self); |
729 | bool finishLoadingDependencies(DomItem &self, int waitMSec = 30000); |
730 | void addWorkForLoadInfo(Path elementCanonicalPath); |
731 | |
732 | Options options() const; |
733 | |
734 | std::shared_ptr<DomEnvironment> base() const; |
735 | |
736 | QStringList loadPaths() const; |
737 | QStringList qmldirFiles() const; |
738 | |
739 | QString globalScopeName() const; |
740 | |
741 | static QList<Import> defaultImplicitImports(); |
742 | QList<Import> implicitImports() const; |
743 | |
744 | void addAllLoadedCallback(DomItem &self, Callback c); |
745 | |
746 | void clearReferenceCache(); |
747 | void setLoadPaths(const QStringList &v); |
748 | |
749 | private: |
750 | friend class RefCacheEntry; |
751 | template<typename T> |
752 | QSet<QString> getStrings(function_ref<QSet<QString>()> getBase, const QMap<QString, T> &selfMap, |
753 | EnvLookup lookup) const; |
754 | |
755 | Callback callbackForQmlDirectory(DomItem &self, Callback loadCallback, |
756 | Callback directDepsCallback, Callback endCallback); |
757 | Callback callbackForQmlFile(DomItem &self, Callback loadCallback, Callback directDepsCallback, |
758 | Callback endCallback); |
759 | Callback callbackForQmltypesFile(DomItem &self, Callback loadCallback, |
760 | Callback directDepsCallback, Callback endCallback); |
761 | Callback callbackForQmldirFile(DomItem &self, Callback loadCallback, |
762 | Callback directDepsCallback, Callback endCallback); |
763 | |
764 | std::shared_ptr<ModuleIndex> lookupModuleInEnv(const QString &uri, int majorVersion) const; |
765 | // ModuleLookupResult contains the ModuleIndex pointer, and an indicator whether it was found |
766 | // in m_base or in m_moduleIndexWithUri |
767 | struct ModuleLookupResult { |
768 | enum Origin : bool {FromBase, FromGlobal}; |
769 | std::shared_ptr<ModuleIndex> module; |
770 | Origin fromBase = FromGlobal; |
771 | }; |
772 | // helper function used by the moduleIndexWithUri methods |
773 | ModuleLookupResult moduleIndexWithUriHelper(DomItem &self, QString uri, int majorVersion, |
774 | EnvLookup lookup = EnvLookup::Normal) const; |
775 | |
776 | const Options m_options; |
777 | const std::shared_ptr<DomEnvironment> m_base; |
778 | const std::shared_ptr<DomUniverse> m_universe; |
779 | QStringList m_loadPaths; // paths for qml |
780 | QString m_globalScopeName; |
781 | QMap<QString, QMap<int, std::shared_ptr<ModuleIndex>>> m_moduleIndexWithUri; |
782 | QMap<QString, std::shared_ptr<ExternalItemInfo<GlobalScope>>> m_globalScopeWithName; |
783 | QMap<QString, std::shared_ptr<ExternalItemInfo<QmlDirectory>>> m_qmlDirectoryWithPath; |
784 | QMap<QString, std::shared_ptr<ExternalItemInfo<QmldirFile>>> m_qmldirFileWithPath; |
785 | QMap<QString, std::shared_ptr<ExternalItemInfo<QmlFile>>> m_qmlFileWithPath; |
786 | QMap<QString, std::shared_ptr<ExternalItemInfo<JsFile>>> m_jsFileWithPath; |
787 | QMap<QString, std::shared_ptr<ExternalItemInfo<QmltypesFile>>> m_qmltypesFileWithPath; |
788 | QQueue<Path> m_loadsWithWork; |
789 | QQueue<Path> m_inProgress; |
790 | QHash<Path, std::shared_ptr<LoadInfo>> m_loadInfos; |
791 | QList<Import> m_implicitImports; |
792 | QList<Callback> m_allLoadedCallback; |
793 | QHash<Path, RefCacheEntry> m_referenceCache; |
794 | }; |
795 | Q_DECLARE_OPERATORS_FOR_FLAGS(DomEnvironment::Options) |
796 | |
797 | } // end namespace Dom |
798 | } // end namespace QQmlJS |
799 | QT_END_NAMESPACE |
800 | #endif // DOMTOP_H |
801 | |