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()
622 for (
auto const &
dir : imports) {
624 while (
it.hasNext() && !qmltypesFiles.
isEmpty()) {
626 qmltypesFiles.removeOne(
it.fileName());
628 setQualifiedNamesOn(
result);
629 importDependencies(
result, &builtins);
631 if (qmltypesFiles.isEmpty())
637 if (!qmltypesFiles.isEmpty()) {
639 m_importPaths.isEmpty() ? u
"<empty>"_s : m_importPaths.join(u
"\n\t");
641 "qrc). Import paths used:\n\t%2")
642 .arg(qmltypesFiles.join(u
", "), pathsString),
657 if (exported.scope->internalName() == u
"int"_s) {
658 intType = exported.scope;
661 }
else if (exported.scope->internalName() == u
"Array"_s) {
662 arrayType = exported.scope;
671 m_builtins = AvailableTypes(
676 processImport(builtinImport,
result, &(*m_builtins));
686 for (
const auto &
file : qmldirFiles) {
691 setQualifiedNamesOn(
result);
695 QStringLiteral(
"Argument %1 to -i option is not a qmldir file. Assuming qmltypes.")
711 for (
const auto &
object : std::as_const(
result.objects)) {
712 for (
const auto &ex :
object.exports) {
713 m_seenImports.
insert({ex.package(), ex.version()}, qmldirName);
726 const AvailableTypes builtins = builtinImportHelper();
727 AvailableTypes
result(builtins.cppNames);
728 if (!importHelper(module, &
result, prefix, version)) {
730 QStringLiteral(
"Failed to import %1. Are your import paths set up properly?").arg(module),
737 if (
result.hasSystemModule) {
738 for (
auto nameIt = builtins.qmlNames.types().keyBegin(),
739 end = builtins.qmlNames.types().keyEnd();
740 nameIt !=
end; ++nameIt)
741 result.qmlNames.setType(
prefixedName(prefix, *nameIt), builtins.qmlNames.type(*nameIt));
744 if (staticModuleList)
745 *staticModuleList <<
result.staticModules;
752 return builtinImportHelper().cppNames;
755bool QQmlJSImporter::importHelper(
const QString &module, AvailableTypes *
types,
767 auto getTypesFromCache = [&]() ->
bool {
771 const auto &cacheEntry = m_cachedImportTypes[
cacheKey];
773 types->cppNames.addTypes(cacheEntry->cppNames);
774 types->staticModules << cacheEntry->staticModules;
775 types->hasSystemModule |= cacheEntry->hasSystemModule;
779 types->qmlNames.addTypes(cacheEntry->qmlNames);
786 if (module == u
"QML"_s)
789 if (getTypesFromCache())
792 auto cacheTypes = QSharedPointer<QQmlJSImporter::AvailableTypes>(
793 new QQmlJSImporter::AvailableTypes(
795 m_cachedImportTypes[
cacheKey] = cacheTypes;
797 const QPair<QString, QTypeRevision> importId { module, version };
805 const QQmlJSImporter::Import
import = m_seenQmldirFiles.value(*it);
807 importDependencies(
import, cacheTypes.get(), prefix, version, isDependency);
808 processImport(
cacheKey,
import, cacheTypes.get());
810 const bool typesFromCache = getTypesFromCache();
812 return typesFromCache;
817 const auto import = readDirectory(module);
818 m_seenQmldirFiles.
insert(module,
import);
819 m_seenImports.
insert(importId, module);
820 importDependencies(
import, cacheTypes.get(), prefix, version, isDependency);
821 processImport(
cacheKey,
import, cacheTypes.get());
824 modulePaths.append(module);
829 for (
auto const &modulePath : modulePaths) {
831 if (modulePath.startsWith(u
':')) {
834 1, modulePath.endsWith(u
'/') ? modulePath.size() - 2 : -1)
838 qmldirPath =
entry.filePath;
840 qWarning() <<
"Cannot read files from resource directory" << modulePath
841 <<
"because no resource file mapper was provided";
847 const auto it = m_seenQmldirFiles.
constFind(qmldirPath);
849 const QQmlJSImporter::Import
import = *it;
850 m_seenImports.
insert(importId, qmldirPath);
851 importDependencies(
import, cacheTypes.get(), prefix, version, isDependency);
852 processImport(
cacheKey,
import, cacheTypes.get());
854 const bool typesFromCache = getTypesFromCache();
856 return typesFromCache;
861 const auto import = readQmldir(file.canonicalPath());
862 setQualifiedNamesOn(
import);
863 m_seenQmldirFiles.
insert(qmldirPath,
import);
864 m_seenImports.
insert(importId, qmldirPath);
865 importDependencies(
import, cacheTypes.get(), prefix, version, isDependency);
868 processImport(
cacheKey,
import, cacheTypes.get());
870 const bool typesFromCache = getTypesFromCache();
872 return typesFromCache;
878 const bool typesFromCache = getTypesFromCache();
880 return typesFromCache;
889 const auto seen = m_importedFiles.find(filePath);
890 if (seen != m_importedFiles.end())
893 return *m_importedFiles.insert(filePath, {
895 QSharedPointer<QDeferredFactory<QQmlJSScope>>(
902 return localFile2ScopeTree(
file);
908 const AvailableTypes builtins = builtinImportHelper();
909 QQmlJSImporter::AvailableTypes
types(
913 return types.qmlNames;
922 m_seenImports.
clear();
923 m_cachedImportTypes.
clear();
929 m_seenImports.
clear();
930 m_cachedImportTypes.
clear();
931 m_seenQmldirFiles.
clear();
932 m_importedFiles.clear();
937 return m_builtins->cppNames.type(u
"GlobalObject"_s).scope;
940void QQmlJSImporter::setQualifiedNamesOn(
const Import &
import)
942 for (
auto &
object : import.objects) {
943 if (
object.exports.isEmpty())
948 object.scope->setOwnModuleName(
import.
name);
956 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