10#include <QtQml/private/qqmlimportresolver_p.h>
12#include <QtCore/qfileinfo.h>
13#include <QtCore/qdiriterator.h>
25 m_prefix(
std::move(prefix)),
29 m_isDependency(isDependency)
35 return !m_name.isEmpty();
62void QQmlJSImporter::readQmltypes(
63 const QString &filename, QList<QQmlJSExportedScope> *objects,
64 QList<QQmlDirParser::Import> *dependencies)
67 if (!fileInfo.exists()) {
76 if (fileInfo.isDir()) {
78 QStringLiteral(
"QML types file cannot be a directory: ") + filename,
97 auto succ =
reader(objects, &dependencyStrings);
105 if (dependencyStrings.isEmpty())
109 QStringLiteral(
"Found deprecated dependency specifications in %1."
110 "Specify dependencies in qmldir and use qmltyperegistrar "
111 "to generate qmltypes files without dependencies.")
117 for (
const QString &dependency :
std::as_const(dependencyStrings)) {
118 const auto blank = dependency.indexOf(u
' ');
125 const QString module = dependency.left(blank);
132 const auto dot = versionString.indexOf(u
'.');
137 versionString.mid(
dot + 1).toUShort());
147 return factory->internalName();
165 bool useOptionalImports)
166 : m_importPaths(importPaths),
168 m_useOptionalImports(useOptionalImports),
172 p.m_target, self,
p.m_logger,
p.m_implicitImportDirectory,
p.m_qmldirFiles));
181 if (prefer.isEmpty())
184 if (!prefer.endsWith(u
'/')) {
185 qWarning() <<
"Ignoring invalid prefer path" << prefer <<
"(has to end with slash)";
189 if (prefer.startsWith(u
':')) {
207 const QString canonical =
f.canonicalFilePath();
208 if (canonical.isEmpty()) {
209 qWarning() <<
"No qmldir at" << prefer;
215QQmlJSImporter::Import QQmlJSImporter::readQmldir(
const QString &modulePath)
218 auto reader = createQmldirParserForFile(moduleQmldirPath);
220 const QString resolvedQmldirPath
222 if (resolvedQmldirPath != moduleQmldirPath)
223 reader = createQmldirParserForFile(resolvedQmldirPath);
237 const auto typeInfos =
reader.typeInfos();
238 for (
const auto &typeInfo : typeInfos) {
240 ? resolvedPath + typeInfo
242 readQmltypes(typeInfoPath, &
result.objects, &
result.dependencies);
245 if (typeInfos.isEmpty() && !
reader.plugins().isEmpty()) {
250 + defaultTypeInfoPath,
254 readQmltypes(defaultTypeInfoPath, &
result.objects, &
result.dependencies);
258 QHash<QString, QQmlJSExportedScope> qmlComponents;
261 const QString filePath = resolvedPath +
it->fileName;
273 auto mo = qmlComponents.find(
it->fileName);
274 if (
mo == qmlComponents.end()) {
276 if (
auto *
factory = imported.factory()) {
281 mo = qmlComponents.insert(
it->fileName, {imported, QList<QQmlJSScope::Export>() });
287 for (
auto it = qmlComponents.
begin(),
end = qmlComponents.end();
it !=
end; ++
it)
290 const auto scripts =
reader.scripts();
291 for (
const auto &script : scripts) {
292 const QString filePath = resolvedPath + script.fileName;
293 auto mo =
result.scripts.find(script.fileName);
295 mo =
result.scripts.insert(script.fileName, { localFile2ScopeTree(filePath), {} });
298 reader.typeNamespace(), script.nameSpace,
304QQmlJSImporter::Import QQmlJSImporter::readDirectory(
const QString &
directory)
309 const auto resources = m_mapper->
filter(
311 for (
const auto &
entry : resources) {
313 if (
name.front().isUpper()) {
315 localFile2ScopeTree(
entry.filePath),
322 <<
"because no resource file mapper was provided";
333 while (
it.hasNext()) {
337 if (!
name.front().isUpper())
341 if (
name.endsWith(u
".ui"))
345 if (
name.contains(u
'.'))
348 import.objects.append({
349 localFile2ScopeTree(
it.filePath()),
356void QQmlJSImporter::importDependencies(
const QQmlJSImporter::Import &
import,
357 QQmlJSImporter::AvailableTypes *
types,
363 for (
auto const &dependency :
std::as_const(import.dependencies))
364 importHelper(dependency.module,
types,
QString(), dependency.version, true);
366 bool hasOptionalImports =
false;
367 for (
auto const &
import :
std::as_const(import.imports)) {
369 hasOptionalImports =
true;
370 if (!m_useOptionalImports) {
378 importHelper(
import.module,
types, isDependency ?
QString() : prefix,
383 if (hasOptionalImports && !m_useOptionalImports) {
385 { u
"%1 uses optional imports which are not supported. Some types might not be found."_s
394 const QTypeRevision importVersion = importDescription.version();
396 if (!importVersion.hasMajorVersion())
398 if (importVersion.majorVersion() != exportVersion.majorVersion())
401 || exportVersion.minorVersion() <= importVersion.minorVersion();
404void QQmlJSImporter::processImport(
const QQmlJS::Import &importDescription,
405 const QQmlJSImporter::Import &
import,
406 QQmlJSImporter::AvailableTypes *
types)
415 QHash<QString, QList<QQmlJSScope::Export>> seenExports;
419 for (
const QString &alias : cppAliases)
427 for (
const auto &valExport :
val.exports) {
434 if (!bestExport.isValid() || valExport.version() > bestExport.version())
435 bestExport = valExport;
437 const auto it =
types->qmlNames.types().
find(qmlName);
445 if (
it->scope ==
val.scope &&
it->revision == valExport.version())
448 const auto existingExports = seenExports.value(qmlName);
449 enum { LowerVersion, SameVersion, HigherVersion } seenVersion = LowerVersion;
454 if (valExport.version() <
entry.version()) {
455 seenVersion = HigherVersion;
459 if (seenVersion == LowerVersion && valExport.version() ==
entry.version())
460 seenVersion = SameVersion;
463 switch (seenVersion) {
469 "%1 %2.%3 is defined multiple times.")
471 .arg(valExport.version().majorVersion())
472 .arg(valExport.version().minorVersion()),
478 types->qmlNames.clearType(qmlName);
486 types->qmlNames.setType(qmlName, {
val.scope, valExport.version() });
487 seenExports[qmlName].append(valExport);
491 ? bestExport.revision()
493 types->cppNames.setType(cppName, {
val.scope, bestRevision });
495 insertAliases(
val.scope, bestRevision);
498 ? bestExport.version()
504 if (!importDescription.prefix().isEmpty())
505 types->qmlNames.setType(importDescription.prefix(), {});
508 if (!importDescription.isDependency())
509 types->qmlNames.setType(
prefixedName(modulePrefix, importDescription.name()), {});
511 if (!importDescription.isDependency()) {
512 if (
import.isStaticModule)
513 types->staticModules <<
import.name;
515 if (
import.isSystemModule)
516 types->hasSystemModule =
true;
519 for (
auto it =
import.scripts.
begin();
it !=
import.scripts.
end(); ++
it) {
526 for (
const auto &
val : import.objects) {
531 if (
val.exports.isEmpty()) {
533 types->qmlNames.setType(
538 insertExports(
val, cppName);
563 QQmlJSImporter::AvailableTypes tempTypes(builtinImportHelper().cppNames);
564 tempTypes.cppNames.addTypes(
types->cppNames);
572 for (
auto it =
import.objects.begin();
it !=
import.objects.
end(); ++
it) {
573 if (!
it->scope.factory()) {
579 for (
const auto &
val :
std::as_const(import.objects)) {
581 if (!
val.scope.factory() &&
val.scope->baseType().isNull()) {
586 if (
val.scope->isComposite()) {
588 QStringLiteral(
"Found incomplete composite type %1. Do not use qmlplugindump.")
589 .arg(
val.scope->internalName()),
605 return builtinImportHelper().qmlNames;
609QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
620 for (
auto const &
dir : imports) {
622 if (!importDir.exists(qmltypesFile))
626 importDir.filePath(qmltypesFile), &
result.objects, &
result.dependencies);
627 setQualifiedNamesOn(
result);
628 importDependencies(
result, &builtins);
638 const QStringList builtinsPath{ u
":/qt-project.org/qml/builtins"_s };
639 for (
const QString qmltypesFile : {
"jsroot.qmltypes"_L1,
"builtins.qmltypes"_L1 }) {
641 qFatal() << u
"Failed to find the following builtin:" << qmltypesFile;
654 if (exported.scope->internalName() == u
"int"_s) {
655 intType = exported.scope;
658 }
else if (exported.scope->internalName() == u
"Array"_s) {
659 arrayType = exported.scope;
668 m_builtins = AvailableTypes(
673 processImport(builtinImport,
result, &(*m_builtins));
683 for (
const auto &
file : qmldirFiles) {
688 setQualifiedNamesOn(
result);
692 QStringLiteral(
"Argument %1 to -i option is not a qmldir file. Assuming qmltypes.")
708 for (
const auto &
object : std::as_const(
result.objects)) {
709 for (
const auto &ex :
object.exports) {
710 m_seenImports.
insert({ex.package(), ex.version()}, qmldirName);
723 const AvailableTypes builtins = builtinImportHelper();
724 AvailableTypes
result(builtins.cppNames);
725 if (!importHelper(module, &
result, prefix, version)) {
727 QStringLiteral(
"Failed to import %1. Are your import paths set up properly?").arg(module),
734 if (
result.hasSystemModule) {
735 for (
auto nameIt = builtins.qmlNames.types().keyBegin(),
736 end = builtins.qmlNames.types().keyEnd();
737 nameIt !=
end; ++nameIt)
738 result.qmlNames.setType(
prefixedName(prefix, *nameIt), builtins.qmlNames.type(*nameIt));
741 if (staticModuleList)
742 *staticModuleList <<
result.staticModules;
749 return builtinImportHelper().cppNames;
752bool QQmlJSImporter::importHelper(
const QString &module, AvailableTypes *
types,
764 auto getTypesFromCache = [&]() ->
bool {
768 const auto &cacheEntry = m_cachedImportTypes[
cacheKey];
770 types->cppNames.addTypes(cacheEntry->cppNames);
771 types->staticModules << cacheEntry->staticModules;
772 types->hasSystemModule |= cacheEntry->hasSystemModule;
776 types->qmlNames.addTypes(cacheEntry->qmlNames);
783 if (module == u
"QML"_s)
786 if (getTypesFromCache())
789 auto cacheTypes = QSharedPointer<QQmlJSImporter::AvailableTypes>(
790 new QQmlJSImporter::AvailableTypes(
792 m_cachedImportTypes[
cacheKey] = cacheTypes;
794 const QPair<QString, QTypeRevision> importId { module, version };
802 const QQmlJSImporter::Import
import = m_seenQmldirFiles.value(*it);
804 importDependencies(
import, cacheTypes.get(), prefix, version, isDependency);
805 processImport(
cacheKey,
import, cacheTypes.get());
807 const bool typesFromCache = getTypesFromCache();
809 return typesFromCache;
814 const auto import = readDirectory(module);
815 m_seenQmldirFiles.
insert(module,
import);
816 m_seenImports.
insert(importId, module);
817 importDependencies(
import, cacheTypes.get(), prefix, version, isDependency);
818 processImport(
cacheKey,
import, cacheTypes.get());
821 modulePaths.append(module);
826 for (
auto const &modulePath : modulePaths) {
828 if (modulePath.startsWith(u
':')) {
831 1, modulePath.endsWith(u
'/') ? modulePath.size() - 2 : -1)
835 qmldirPath =
entry.filePath;
837 qWarning() <<
"Cannot read files from resource directory" << modulePath
838 <<
"because no resource file mapper was provided";
844 const auto it = m_seenQmldirFiles.
constFind(qmldirPath);
846 const QQmlJSImporter::Import
import = *it;
847 m_seenImports.
insert(importId, qmldirPath);
848 importDependencies(
import, cacheTypes.get(), prefix, version, isDependency);
849 processImport(
cacheKey,
import, cacheTypes.get());
851 const bool typesFromCache = getTypesFromCache();
853 return typesFromCache;
858 const auto import = readQmldir(file.canonicalPath());
859 setQualifiedNamesOn(
import);
860 m_seenQmldirFiles.
insert(qmldirPath,
import);
861 m_seenImports.
insert(importId, qmldirPath);
862 importDependencies(
import, cacheTypes.get(), prefix, version, isDependency);
865 processImport(
cacheKey,
import, cacheTypes.get());
867 const bool typesFromCache = getTypesFromCache();
869 return typesFromCache;
875 const bool typesFromCache = getTypesFromCache();
877 return typesFromCache;
886 const auto seen = m_importedFiles.find(filePath);
887 if (seen != m_importedFiles.end())
890 return *m_importedFiles.insert(filePath, {
892 QSharedPointer<QDeferredFactory<QQmlJSScope>>(
899 return localFile2ScopeTree(
file);
905 const AvailableTypes builtins = builtinImportHelper();
906 QQmlJSImporter::AvailableTypes
types(
910 return types.qmlNames;
919 m_seenImports.
clear();
920 m_cachedImportTypes.
clear();
926 m_seenImports.
clear();
927 m_cachedImportTypes.
clear();
928 m_seenQmldirFiles.
clear();
929 m_importedFiles.clear();
934 return m_builtins->cppNames.type(u
"GlobalObject"_s).scope;
937void QQmlJSImporter::setQualifiedNamesOn(
const Import &
import)
939 for (
auto &
object : import.objects) {
940 if (
object.exports.isEmpty())
945 object.scope->setOwnModuleName(
import.
name);
953 m_importVisitor(rootNode,
this,
p);
Factory * factory() const
The QDirIterator class provides an iterator for directory entrylists.
QString baseName() const
Returns the base name of the file without the path.
bool isRelative() const
Returns true if the file system entry's path is relative, otherwise returns false (that is,...
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
const_iterator constFind(const Key &key) const noexcept
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
void append(parameter_type t)
bool parse(const QString &source)
url is used for generating errors.
QQmlJSImporter(const QStringList &importPaths, QQmlJSResourceFileMapper *mapper, bool useOptionalImports=false)
void importQmldirs(const QStringList &qmltypesFiles)
Imports types from the specified qmltypesFiles.
void runImportVisitor(QQmlJS::AST::Node *rootNode, const ImportVisitorPrerequisites &prerequisites)
QQmlJS::ContextualTypes ImportedTypes
QStringList importPaths() const
ImportedTypes builtinInternalNames()
QQmlJSScope::Ptr importFile(const QString &file)
ImportedTypes importBuiltins()
Imports builtins.qmltypes and jsroot.qmltypes found in any of the import paths.
friend class QDeferredFactory< QQmlJSScope >
void setImportPaths(const QStringList &importPaths)
ImportedTypes importDirectory(const QString &directory, const QString &prefix=QString())
ImportedTypes importModule(const QString &module, const QString &prefix=QString(), QTypeRevision version=QTypeRevision(), QStringList *staticModuleList=nullptr)
QQmlJSScope::ConstPtr jsGlobalObject() const
static QQmlJSScope::Ptr create()
static void resolveNonEnumTypes(const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes, QSet< QString > *usedTypes=nullptr)
QString internalName() const
static void resolveList(const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &arrayType)
static void resolveEnums(const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes, QSet< QString > *usedTypes=nullptr)
QStringList aliases() const
void accept(BaseVisitor *visitor)
iterator find(const T &value)
constexpr QStringView chopped(qsizetype n) const noexcept
Returns the substring of length size() - length starting at the beginning of this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
QString & replace(qsizetype i, qsizetype len, QChar after)
QString mid(qsizetype position, qsizetype n=-1) const &
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
QString & append(QChar c)
QString trimmed() const &
static constexpr QTypeRevision fromMajorVersion(Major majorVersion)
Produces a QTypeRevision from the given majorVersion with an invalid minor version.
static constexpr QTypeRevision fromVersion(Major majorVersion, Minor minorVersion)
Produces a QTypeRevision from the given majorVersion and minorVersion, both of which need to be a val...
constexpr bool hasMinorVersion() const
Returns true if the minor version is known, otherwise false.
static constexpr QTypeRevision zero()
Produces a QTypeRevision with major and minor version {0}.
constexpr bool isValid() const
Returns true if the major version or the minor version is known, otherwise false.
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QImageReader reader("image.png")
[1]
QList< QString > QStringList
Constructs a string list that contains the given string, str.
static QByteArray cacheKey(Args &&...args)
GLint GLenum GLint components
GLsizei GLenum GLenum * types
static qreal dot(const QPointF &a, const QPointF &b)
QStringList qQmlResolveImportPaths(QStringView uri, const QStringList &basePaths, QTypeRevision version)
static QStringList aliases(const QQmlJSScope::ConstPtr &scope)
static bool isVersionAllowed(const QQmlJSScope::Export &exportEntry, const QQmlJS::Import &importDescription)
static bool isComposite(const QQmlJSScope::ConstPtr &scope)
static QString resolvePreferredPath(const QString &qmldirPath, const QString &prefer, QQmlJSResourceFileMapper *mapper)
static const QString prefixedName(const QString &prefix, const QString &name)
static QString internalName(const QQmlJSScope::ConstPtr &scope)
static const QLatin1String PluginsDotQmltypes
static const QLatin1String SlashQmldir
QLatin1StringView QLatin1String
#define QStringLiteral(str)
QItemEditorFactory * factory
proxy setType(QNetworkProxy::Socks5Proxy)
\inmodule QtCore \reentrant
Entry entry(const Filter &filter) const
static Filter resourceFileFilter(const QString &file)
static Filter resourceQmlDirectoryFilter(const QString &directory)
QList< Entry > filter(const Filter &filter) const