Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qqmldommoduleindex.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#include "qqmldomtop_p.h"
4#include "qqmldomelements_p.h"
5
6#include <QtCore/QDir>
7#include <QtCore/QFileInfo>
8#include <QtCore/QScopeGuard>
9
10#include <memory>
11
13namespace QQmlJS {
14namespace Dom {
15
17{
18 static ErrorGroups res = { { DomItem::domErrorGroup, NewErrorGroup("Exports"),
19 NewErrorGroup("Version") } };
20 return res;
21}
22
24{
25 static ErrorGroups res = { { DomItem::domErrorGroup, NewErrorGroup("Exports") } };
26 return res;
27}
28
30{
31 bool cont = true;
32 cont = cont && self.dvValueField(visitor, Fields::uri, uri);
33 cont = cont && self.dvWrapField(visitor, Fields::version, version);
34 cont = cont && self.dvItemField(visitor, Fields::exports, [this, &self]() {
35 int minorVersion = version.minorVersion;
36 return self.subMapItem(Map(
37 self.pathFromOwner().field(Fields::exports),
38 [minorVersion](DomItem &mapExp, QString name) -> DomItem {
39 DomItem mapExpOw = mapExp.owner();
40 QList<DomItem> exports =
41 mapExp.ownerAs<ModuleIndex>()->exportsWithNameAndMinorVersion(
42 mapExpOw, name, minorVersion);
43 return mapExp.subListItem(List::fromQList<DomItem>(
44 mapExp.pathFromOwner().key(name), exports,
45 [](DomItem &, const PathEls::PathComponent &, DomItem &el) {
46 return el;
47 },
49 },
50 [](DomItem &mapExp) {
51 DomItem mapExpOw = mapExp.owner();
52 return mapExp.ownerAs<ModuleIndex>()->exportNames(mapExpOw);
53 },
54 QLatin1String("List<Exports>")));
55 });
56 cont = cont && self.dvItemField(visitor, Fields::symbols, [&self]() {
57 Path basePath = Path::Current(PathCurrent::Obj).field(Fields::exports);
58 return self.subMapItem(Map(
59 self.pathFromOwner().field(Fields::symbols),
60 [basePath](DomItem &mapExp, QString name) -> DomItem {
61 QList<Path> symb({ basePath.key(name) });
62 return mapExp.subReferencesItem(PathEls::Key(name), symb);
63 },
64 [](DomItem &mapExp) {
65 DomItem mapExpOw = mapExp.owner();
66 return mapExp.ownerAs<ModuleIndex>()->exportNames(mapExpOw);
67 },
68 QLatin1String("List<References>")));
69 });
70 cont = cont && self.dvItemField(visitor, Fields::autoExports, [this, &self]() {
71 return containingObject(self).field(Fields::autoExports);
72 });
73 return cont;
74}
75
76std::shared_ptr<OwningItem> ModuleIndex::doCopy(DomItem &) const
77{
78 return std::make_shared<ModuleIndex>(*this);
79}
80
81ModuleIndex::ModuleIndex(const ModuleIndex &o)
82 : OwningItem(o), m_uri(o.uri()), m_majorVersion(o.majorVersion())
83{
85 {
86 QMutexLocker l2(o.mutex());
87 m_qmltypesFilesPaths += o.m_qmltypesFilesPaths;
88 m_qmldirPaths += o.m_qmldirPaths;
89 m_directoryPaths += o.m_directoryPaths;
90 scopes = o.m_moduleScope;
91 }
92 auto it = scopes.begin();
93 auto end = scopes.end();
94 while (it != end) {
95 ensureMinorVersion((*it)->version.minorVersion);
96 ++it;
97 }
98}
99
101{
103 {
104 QMutexLocker l(mutex());
105 scopes = m_moduleScope;
106 m_moduleScope.clear();
107 }
108 auto it = scopes.begin();
109 auto end = scopes.end();
110 while (it != end) {
111 delete *it;
112 ++it;
113 }
114}
115
117{
118 bool cont = self.dvValueField(visitor, Fields::uri, uri());
119 cont = cont && self.dvValueField(visitor, Fields::majorVersion, majorVersion());
120 cont = cont && self.dvItemField(visitor, Fields::moduleScope, [this, &self]() {
121 return self.subMapItem(Map(
122 pathFromOwner(self).field(Fields::moduleScope),
123 [](DomItem &map, QString minorVersionStr) {
124 bool ok;
125 int minorVersion = minorVersionStr.toInt(&ok);
126 if (minorVersionStr.isEmpty()
127 || minorVersionStr.compare(u"Latest", Qt::CaseInsensitive) == 0)
128 minorVersion = Version::Latest;
129 else if (!ok)
130 return DomItem();
131 return map.copy(map.ownerAs<ModuleIndex>()->ensureMinorVersion(minorVersion));
132 },
133 [this](DomItem &) {
135 for (int el : minorVersions())
136 if (el >= 0)
137 res.insert(QString::number(el));
138 if (!minorVersions().isEmpty())
139 res.insert(QString());
140 return res;
141 },
142 QLatin1String("Map<List<Exports>>")));
143 });
144 cont = cont && self.dvItemField(visitor, Fields::sources, [this, &self]() {
145 return self.subReferencesItem(PathEls::Field(Fields::sources), sources());
146 });
147 cont = cont && self.dvValueLazyField(visitor, Fields::autoExports, [this, &self]() {
148 return autoExports(self);
149 });
150 return cont;
151}
152
154{
156 QList<Path> mySources = sources();
157 for (int i = 0; i < mySources.size(); ++i) {
158 DomItem source = self.path(mySources.at(i));
159 res += source.field(Fields::exports).keys();
160 }
161 return res;
162}
163
165{
167 Path selfPath = canonicalPath(self).field(Fields::autoExports);
168 RefCacheEntry cached = RefCacheEntry::forPath(self, selfPath);
169 QList<Path> cachedPaths;
170 switch (cached.cached) {
173 break;
175 cachedPaths += cached.canonicalPaths;
176 if (cachedPaths.isEmpty())
177 return res;
178 }
179 DomItem env = self.environment();
180 if (!cachedPaths.isEmpty()) {
181 bool outdated = false;
182 for (Path p : cachedPaths) {
183 DomItem newEl = env.path(p);
184 if (!newEl) {
185 outdated = true;
186 qWarning() << "referenceCache outdated, reference at " << selfPath
187 << " leads to invalid path " << p;
188 break;
189 } else {
190 res.append(newEl);
191 }
192 }
193 if (outdated) {
194 res.clear();
195 } else {
196 return res;
197 }
198 }
199 QList<Path> mySources = sources();
200 QSet<QString> knownAutoImportUris;
201 QList<ModuleAutoExport> knownExports;
202 for (Path p : mySources) {
203 DomItem autoExports = self.path(p).field(Fields::autoExports);
204 for (DomItem i : autoExports.values()) {
205 if (const ModuleAutoExport *iPtr = i.as<ModuleAutoExport>()) {
206 if (!knownAutoImportUris.contains(iPtr->import.uri.toString())
207 || !knownExports.contains(*iPtr)) {
208 knownAutoImportUris.insert(iPtr->import.uri.toString());
209 knownExports.append(*iPtr);
210 res.append(i);
211 cachedPaths.append(i.canonicalPath());
212 }
213 }
214 }
215 }
216 RefCacheEntry::addForPath(self, selfPath,
218 return res;
219}
220
222 int minorVersion) const
223{
224 Path myPath = Paths::moduleScopePath(uri(), Version(majorVersion(), minorVersion))
225 .field(Fields::exports)
226 .key(name);
227 QList<Path> mySources = sources();
229 QList<DomItem> undef;
230 if (minorVersion < 0)
231 minorVersion = std::numeric_limits<int>::max();
232 int vNow = Version::Undefined;
233 for (int i = 0; i < mySources.size(); ++i) {
234 DomItem source = self.path(mySources.at(i));
235 DomItem exports = source.field(Fields::exports).key(name);
236 int nExports = exports.indexes();
237 if (nExports == 0)
238 continue;
239 for (int j = 0; j < nExports; ++j) {
240 DomItem exportItem = exports.index(j);
241 if (!exportItem)
242 continue;
243 Version const *versionPtr = exportItem.field(Fields::version).as<Version>();
244 if (versionPtr == nullptr || !versionPtr->isValid()) {
245 undef.append(exportItem);
246 } else {
247 if (majorVersion() < 0)
248 self.addError(myVersioningErrors()
249 .error(tr("Module %1 (unversioned) has versioned entries "
250 "for '%2' from %3")
251 .arg(uri(), name,
252 source.canonicalPath().toString()))
253 .withPath(myPath));
254 if ((versionPtr->majorVersion == majorVersion()
255 || versionPtr->majorVersion == Version::Undefined)
256 && versionPtr->minorVersion >= vNow
257 && versionPtr->minorVersion <= minorVersion) {
258 if (versionPtr->minorVersion > vNow)
259 res.clear();
260 res.append(exportItem);
261 vNow = versionPtr->minorVersion;
262 }
263 }
264 }
265 }
266 if (!undef.isEmpty()) {
267 if (!res.isEmpty()) {
268 self.addError(myVersioningErrors()
269 .error(tr("Module %1 (major version %2) has versioned and "
270 "unversioned entries for '%3'")
272 .withPath(myPath));
273 return res + undef;
274 } else {
275 return undef;
276 }
277 }
278 return res;
279}
280
282{
284 QMutexLocker l(mutex());
285 res += m_qmltypesFilesPaths;
286 if (!m_qmldirPaths.isEmpty())
287 res += m_qmldirPaths.first();
288 else if (!m_directoryPaths.isEmpty())
289 res += m_directoryPaths.first();
290 return res;
291}
292
294{
295 if (minorVersion < 0)
296 minorVersion = Version::Latest;
297 {
298 QMutexLocker l(mutex());
299 auto it = m_moduleScope.find(minorVersion);
300 if (it != m_moduleScope.end())
301 return *it;
302 }
303 ModuleScope *res = nullptr;
304 ModuleScope *newScope = new ModuleScope(m_uri, Version(majorVersion(), minorVersion));
305 auto cleanup = qScopeGuard([&newScope] { delete newScope; });
306 {
307 QMutexLocker l(mutex());
308 auto it = m_moduleScope.find(minorVersion);
309 if (it != m_moduleScope.end()) {
310 res = *it;
311 } else {
312 res = newScope;
313 newScope = nullptr;
314 m_moduleScope.insert(minorVersion, res);
315 }
316 }
317 return res;
318}
319
320void ModuleIndex::mergeWith(std::shared_ptr<ModuleIndex> o)
321{
322 if (o) {
323 QList<Path> qmltypesPaths;
325 {
326 QMutexLocker l2(o->mutex());
327 qmltypesPaths = o->m_qmltypesFilesPaths;
328 scopes = o->m_moduleScope;
329 }
330 {
331 QMutexLocker l(mutex());
332 for (Path qttPath : qmltypesPaths) {
333 if (!m_qmltypesFilesPaths.contains((qttPath)))
334 m_qmltypesFilesPaths.append(qttPath);
335 }
336 }
337 auto it = scopes.begin();
338 auto end = scopes.end();
339 while (it != end) {
340 ensureMinorVersion((*it)->version.minorVersion);
341 ++it;
342 }
343 }
344}
345
347{
348 // this always checks the filesystem to the qmldir file to load
349 DomItem env = self.environment();
350 std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>();
351 QStringList subPathComponents = uri().split(u'.');
352 QString subPath = subPathComponents.join(u'/');
353 QString logicalPath;
355 + QLatin1String("/qmldir");
356 QString dirPath;
357 if (majorVersion() >= 0) {
358 for (QString path : envPtr->loadPaths()) {
359 QDir dir(path);
360 QFileInfo fInfo(dir.filePath(subPathV));
361 if (fInfo.isFile()) {
362 logicalPath = subPathV;
363 dirPath = fInfo.canonicalFilePath();
364 break;
365 }
366 }
367 }
368 if (dirPath.isEmpty()) {
369 for (QString path : envPtr->loadPaths()) {
370 QDir dir(path);
371 QFileInfo fInfo(dir.filePath(subPath + QLatin1String("/qmldir")));
372 if (fInfo.isFile()) {
373 logicalPath = subPath + QLatin1String("/qmldir");
374 dirPath = fInfo.canonicalFilePath();
375 break;
376 }
377 }
378 }
379 if (!dirPath.isEmpty()) {
380 QMutexLocker l(mutex());
381 m_qmldirPaths = QList<Path>({ Paths::qmldirFilePath(dirPath) });
382 } else if (uri() != u"QML") {
384 .warning(tr("Failed to find main qmldir file for %1 %2")
386 .handle());
387 }
388 return qmldirPaths();
389}
390
391} // end namespace Dom
392} // end namespace QQmlJS
static constexpr QChar fromLatin1(char c) noexcept
Converts the Latin-1 character c to its equivalent QChar.
Definition qchar.h:461
\inmodule QtCore
Definition qdir.h:19
\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.
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void append(parameter_type t)
Definition qlist.h:441
Definition qmap.h:186
iterator begin()
Definition qmap.h:597
iterator end()
Definition qmap.h:601
\inmodule QtCore
Definition qmutex.h:317
virtual DomItem field(DomItem &self, QStringView name) const
Represents a consistent set of types organized in modules, it is the top level of the DOM.
static ErrorGroup domErrorGroup
DomItem key(QString name)
std::shared_ptr< T > ownerAs()
index_type indexes()
DomItem index(index_type)
DomItem path(Path p, ErrorHandler h=&defaultErrorHandler)
DomItem field(QStringView name)
Represents a set of tags grouping a set of related error messages.
ErrorMessage error(QString message) const
ErrorMessage & withPath(const Path &)
void mergeWith(std::shared_ptr< ModuleIndex > o)
ModuleScope * ensureMinorVersion(int minorVersion)
QList< Path > qmldirPaths() const
QList< Path > sources() const
QList< int > minorVersions() const
QList< DomItem > exportsWithNameAndMinorVersion(DomItem &self, QString name, int minorVersion) const
Path canonicalPath(DomItem &) const override
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override
QList< DomItem > autoExports(DomItem &self) const
QList< Path > qmldirsToLoad(DomItem &self)
QSet< QString > exportNames(DomItem &self) const
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override
QBasicMutex * mutex() const
void addErrorLocal(ErrorMessage msg)
Path key(QString name) const
Path field(QString name) const
static Path Current(PathCurrent c)
static bool addForPath(DomItem &el, Path canonicalPath, const RefCacheEntry &entry, AddOption addOption=AddOption::KeepExisting)
static RefCacheEntry forPath(DomItem &el, Path canonicalPath)
static constexpr qint32 Undefined
static constexpr qint32 Latest
Definition qset.h:18
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
\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
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1107
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.cpp:6498
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
QMap< QString, QString > map
[6]
QSet< QString >::iterator it
Path moduleScopePath(QString uri, Version version, ErrorHandler)
Path qmldirFilePath(QString path)
static ErrorGroups myVersioningErrors()
static ErrorGroups myExportErrors()
Combined button and popup list for selecting options.
@ CaseInsensitive
QString self
Definition language.cpp:57
static const QPainterPath::ElementType * subPath(const QPainterPath::ElementType *t, const QPainterPath::ElementType *end, const qreal *points, bool *closed)
#define qWarning
Definition qlogging.h:162
GLuint64 GLenum void * handle
GLuint GLuint end
GLuint name
GLsizei GLsizei GLchar * source
GLuint res
GLsizei const GLchar *const * path
GLfloat GLfloat p
[1]
#define NewErrorGroup(name)
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
SSL_CTX int(*) void arg)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define tr(X)
QString dir
[11]
QStringView el
bool contains(const AT &t) const noexcept
Definition qlist.h:44