10#include <QtQml/private/qqmlimportresolver_p.h>
12#include <QtCore/qfileinfo.h>
13#include <QtCore/qdiriterator.h>
37void QQmlJSImporter::readQmltypes(
42 if (!fileInfo.exists()) {
51 if (fileInfo.isDir()) {
53 QStringLiteral(
"QML types file cannot be a directory: ") + filename,
72 auto succ =
reader(objects, &dependencyStrings);
80 if (dependencyStrings.isEmpty())
85 "Specify dependencies in qmldir and use qmltyperegistrar "
86 "to generate qmltypes files without dependencies.")
92 for (
const QString &dependency :
std::as_const(dependencyStrings)) {
93 const auto blank = dependency.indexOf(u
' ');
112 versionString.mid(
dot + 1).toUShort());
122 return factory->internalName();
133 bool useOptionalImports)
134 : m_importPaths(importPaths),
136 m_useOptionalImports(useOptionalImports),
146QQmlJSImporter::Import QQmlJSImporter::readQmldir(
const QString &
path)
157 const auto typeInfos =
reader.typeInfos();
158 for (
const auto &typeInfo : typeInfos) {
160 ?
path + u
'/' + typeInfo : typeInfo;
161 readQmltypes(typeInfoPath, &
result.objects, &
result.dependencies);
164 if (typeInfos.isEmpty() && !
reader.plugins().isEmpty()) {
169 + defaultTypeInfoPath,
173 readQmltypes(defaultTypeInfoPath, &
result.objects, &
result.dependencies);
192 auto mo = qmlComponents.
find(
it->fileName);
193 if (
mo == qmlComponents.
end()) {
200 mo = qmlComponents.
insert(
it->fileName, {imported, QList<QQmlJSScope::Export>() });
209 const auto scripts =
reader.scripts();
210 for (
const auto &script : scripts) {
212 auto mo =
result.scripts.find(script.fileName);
214 mo =
result.scripts.insert(script.fileName, { localFile2ScopeTree(filePath), {} });
217 reader.typeNamespace(), script.nameSpace,
223QQmlJSImporter::Import QQmlJSImporter::readDirectory(
const QString &
directory)
228 const auto resources = m_mapper->
filter(
230 for (
const auto &
entry : resources) {
232 if (
name.front().isUpper()) {
234 localFile2ScopeTree(
entry.filePath),
241 <<
"because no resource file mapper was provided";
252 while (
it.hasNext()) {
256 if (!
name.front().isUpper())
260 if (
name.endsWith(u
".ui"))
264 if (
name.contains(u
'.'))
267 import.objects.append({
268 localFile2ScopeTree(
it.filePath()),
275void QQmlJSImporter::importDependencies(
const QQmlJSImporter::Import &
import,
276 QQmlJSImporter::AvailableTypes *
types,
282 for (
auto const &dependency :
std::as_const(import.dependencies))
283 importHelper(dependency.module,
types,
QString(), dependency.version, true);
285 bool hasOptionalImports =
false;
286 for (
auto const &
import :
std::as_const(import.imports)) {
288 hasOptionalImports =
true;
289 if (!m_useOptionalImports) {
297 importHelper(
import.module,
types, isDependency ?
QString() : prefix,
302 if (hasOptionalImports && !m_useOptionalImports) {
304 { u
"%1 uses optional imports which are not supported. Some types might not be found."_s
324 const QQmlJSImporter::Import &
import,
325 QQmlJSImporter::AvailableTypes *
types)
340 for (
const auto &valExport :
val.exports) {
347 if (!bestExport.
isValid() || valExport.version() > bestExport.
version())
348 bestExport = valExport;
350 const auto it =
types->qmlNames.types().
find(qmlName);
358 if (
it->scope ==
val.scope &&
it->revision == valExport.version())
361 const auto existingExports = seenExports.
value(qmlName);
362 enum { LowerVersion, SameVersion, HigherVersion } seenVersion = LowerVersion;
367 if (valExport.version() <
entry.version()) {
368 seenVersion = HigherVersion;
372 if (seenVersion == LowerVersion && valExport.version() ==
entry.version())
373 seenVersion = SameVersion;
376 switch (seenVersion) {
382 "%1 %2.%3 is defined multiple times.")
384 .arg(valExport.version().majorVersion())
385 .arg(valExport.version().minorVersion()),
391 types->qmlNames.clearType(qmlName);
399 types->qmlNames.setType(qmlName, {
val.scope, valExport.version() });
400 seenExports[qmlName].append(valExport);
406 types->cppNames.setType(cppName, {
val.scope, bestRevision });
416 types->qmlNames.setType(importDescription.
prefix(), {});
423 if (
import.isStaticModule)
424 types->staticModules <<
import.name;
426 if (
import.isSystemModule)
427 types->hasSystemModule =
true;
430 for (
auto it =
import.scripts.
begin();
it !=
import.scripts.
end(); ++
it) {
437 for (
const auto &
val : import.objects) {
442 if (
val.exports.isEmpty()) {
444 types->qmlNames.setType(
448 insertExports(
val, cppName);
473 QQmlJSImporter::AvailableTypes tempTypes(builtinImportHelper().cppNames);
474 tempTypes.cppNames.addTypes(
types->cppNames);
482 for (
auto it =
import.objects.
begin();
it !=
import.objects.
end(); ++
it) {
483 if (!
it->scope.factory()) {
489 for (
const auto &
val :
std::as_const(import.objects)) {
491 if (!
val.scope.factory() &&
val.scope->baseType().isNull()) {
496 if (
val.scope->isComposite()) {
498 QStringLiteral(
"Found incomplete composite type %1. Do not use qmlplugindump.")
499 .arg(
val.scope->internalName()),
515 return builtinImportHelper().qmlNames;
519QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
532 for (
auto const &
dir : imports) {
534 while (
it.hasNext() && !qmltypesFiles.isEmpty()) {
536 qmltypesFiles.removeOne(
it.fileName());
538 setQualifiedNamesOn(
result);
539 importDependencies(
result, &builtins);
541 if (qmltypesFiles.isEmpty())
547 if (!qmltypesFiles.isEmpty()) {
549 m_importPaths.isEmpty() ? u
"<empty>"_s : m_importPaths.join(u
"\n\t");
551 "qrc). Import paths used:\n\t%2")
552 .arg(qmltypesFiles.join(u
", "), pathsString),
567 if (exported.scope->internalName() == u
"int"_s) {
568 intType = exported.scope;
571 }
else if (exported.scope->internalName() == u
"Array"_s) {
572 arrayType = exported.scope;
581 m_builtins = AvailableTypes(
586 processImport(builtinImport,
result, &(*m_builtins));
596 for (
const auto &
file : qmldirFiles) {
604 QStringLiteral(
"Argument %1 to -i option is not a qmldir file. Assuming qmltypes.")
620 for (
const auto &
object : std::as_const(
result.objects)) {
621 for (
const auto &ex :
object.exports) {
622 m_seenImports.
insert({ex.package(), ex.version()}, qmldirName);
635 const AvailableTypes builtins = builtinImportHelper();
636 AvailableTypes
result(builtins.cppNames);
637 if (!importHelper(module, &
result, prefix, version)) {
639 QStringLiteral(
"Failed to import %1. Are your import paths set up properly?").arg(module),
646 if (
result.hasSystemModule) {
647 for (
auto nameIt = builtins.qmlNames.types().keyBegin(),
648 end = builtins.qmlNames.types().keyEnd();
649 nameIt !=
end; ++nameIt)
650 result.qmlNames.setType(
prefixedName(prefix, *nameIt), builtins.qmlNames.type(*nameIt));
653 if (staticModuleList)
654 *staticModuleList <<
result.staticModules;
661 return builtinImportHelper().cppNames;
664bool QQmlJSImporter::importHelper(
const QString &module, AvailableTypes *
types,
674 const QQmlJSScope::Import cacheKey(prefix, moduleCacheName, version, isFile, isDependency);
676 auto getTypesFromCache = [&]() ->
bool {
677 if (!m_cachedImportTypes.
contains(cacheKey))
680 const auto &cacheEntry = m_cachedImportTypes[cacheKey];
682 types->cppNames.addTypes(cacheEntry->cppNames);
683 types->staticModules << cacheEntry->staticModules;
684 types->hasSystemModule |= cacheEntry->hasSystemModule;
688 types->qmlNames.addTypes(cacheEntry->qmlNames);
695 if (module == u
"QML"_s)
698 if (getTypesFromCache())
702 new QQmlJSImporter::AvailableTypes(
704 m_cachedImportTypes[cacheKey] = cacheTypes;
714 const QQmlJSImporter::Import
import = m_seenQmldirFiles.
value(*
it);
716 importDependencies(
import, cacheTypes.get(), prefix, version, isDependency);
717 processImport(cacheKey,
import, cacheTypes.get());
719 const bool typesFromCache = getTypesFromCache();
721 return typesFromCache;
726 const auto import = readDirectory(module);
727 m_seenQmldirFiles.
insert(module,
import);
728 m_seenImports.
insert(importId, module);
729 importDependencies(
import, cacheTypes.get(), prefix, version, isDependency);
730 processImport(cacheKey,
import, cacheTypes.get());
733 modulePaths.append(module);
738 for (
auto const &modulePath : modulePaths) {
740 if (modulePath.startsWith(u
':')) {
743 1, modulePath.endsWith(u
'/') ? modulePath.size() - 2 : -1)
747 qmldirPath =
entry.filePath;
749 qWarning() <<
"Cannot read files from resource directory" << modulePath
750 <<
"because no resource file mapper was provided";
756 const auto it = m_seenQmldirFiles.
constFind(qmldirPath);
758 const QQmlJSImporter::Import
import = *
it;
759 m_seenImports.
insert(importId, qmldirPath);
760 importDependencies(
import, cacheTypes.get(), prefix, version, isDependency);
761 processImport(cacheKey,
import, cacheTypes.get());
763 const bool typesFromCache = getTypesFromCache();
765 return typesFromCache;
770 const auto import = readQmldir(
file.canonicalPath());
771 setQualifiedNamesOn(
import);
772 m_seenQmldirFiles.
insert(qmldirPath,
import);
773 m_seenImports.
insert(importId, qmldirPath);
774 importDependencies(
import, cacheTypes.get(), prefix, version, isDependency);
777 processImport(cacheKey,
import, cacheTypes.get());
779 const bool typesFromCache = getTypesFromCache();
781 return typesFromCache;
787 const bool typesFromCache = getTypesFromCache();
789 return typesFromCache;
798 const auto seen = m_importedFiles.find(filePath);
799 if (seen != m_importedFiles.end())
802 return *m_importedFiles.insert(filePath, {
811 return localFile2ScopeTree(
file);
817 const AvailableTypes builtins = builtinImportHelper();
818 QQmlJSImporter::AvailableTypes
types(
822 return types.qmlNames;
831 m_seenImports.
clear();
832 m_cachedImportTypes.
clear();
838 m_seenImports.
clear();
839 m_cachedImportTypes.
clear();
840 m_seenQmldirFiles.
clear();
841 m_importedFiles.clear();
846 return m_builtins->cppNames.type(u
"GlobalObject"_s).scope;
849void QQmlJSImporter::setQualifiedNamesOn(
const Import &
import)
851 for (
auto &
object : import.objects) {
852 if (
object.exports.isEmpty())
855 import.
name,
object.exports.first().type(),
856 object.exports.first().revision(),
857 object.exports.last().revision());
858 if (
auto *
factory =
object.scope.factory()) {
859 factory->setQualifiedName(qualifiedName);
862 object.scope->setQualifiedName(qualifiedName);
863 object.scope->setModuleName(
import.
name);
868std::unique_ptr<QQmlJSImportVisitor>
873 return std::unique_ptr<QQmlJSImportVisitor>(
874 m_createImportVisitor(
target, importer, logger, implicitImportDirectory, qmldirFiles));
Factory * factory() const
The QDirIterator class provides an iterator for directory entrylists.
\inmodule QtCore \reentrant
QString baseName() const
Returns the base name of the file without the path.
bool isRelative() const
Returns true if the file path is relative, otherwise returns false (i.e.
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...
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
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 ...
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
T value(const Key &key) const noexcept
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
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.
constexpr qsizetype size() const noexcept
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.
QQmlJSScope::ContextualTypes ImportedTypes
std::unique_ptr< QQmlJSImportVisitor > makeImportVisitor(const QQmlJSScope::Ptr &target, QQmlJSImporter *importer, QQmlJSLogger *logger, const QString &implicitImportDirectory, const QStringList &qmldirFiles=QStringList())
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
QTypeRevision revision() const
QTypeRevision version() const
bool isDependency() const
QTypeRevision version() const
Tracks the types for the QmlCompiler.
static QQmlJSScope::Ptr create()
QString internalName() const
static void resolveEnums(const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes, QSet< QString > *usedTypes=nullptr)
static void resolveList(const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &arrayType)
static QString qualifiedNameFrom(const QString &moduleName, const QString &typeName, const QTypeRevision &firstRevision, const QTypeRevision &lastRevision)
static void resolveNonEnumTypes(const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes, QSet< QString > *usedTypes=nullptr)
iterator find(const T &value)
\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)
ushort toUShort(bool *ok=nullptr, int base=10) const
Returns the string converted to an {unsigned short} using base base, which is 10 by default and must ...
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
QString & append(QChar c)
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
QString trimmed() const &
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 hasMajorVersion() const
Returns true if the major version is known, otherwise false.
constexpr quint8 minorVersion() const
Returns the minor version encoded in the revision.
static constexpr QTypeRevision fromMajorVersion(Major majorVersion)
Produces a QTypeRevision from the given majorVersion with an invalid minor version.
constexpr quint8 majorVersion() const
Returns the major version encoded in the revision.
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QImageReader reader("image.png")
[1]
std::pair< T1, T2 > QPair
GLint GLenum GLint components
GLsizei GLenum GLenum * types
GLsizei const GLchar *const * path
static qreal dot(const QPointF &a, const QPointF &b)
QStringList qQmlResolveImportPaths(QStringView uri, const QStringList &basePaths, QTypeRevision version)
static const QLatin1String SlashPluginsDotQmltypes
static QQmlDirParser createQmldirParserForFile(const QString &filename)
static bool isComposite(const QQmlJSScope::ConstPtr &scope)
static const QString prefixedName(const QString &prefix, const QString &name)
static bool isVersionAllowed(const QQmlJSScope::Export &exportEntry, const QQmlJSScope::Import &importDescription)
static QString internalName(const QQmlJSScope::ConstPtr &scope)
static const QLatin1String SlashQmldir
QLatin1StringView QLatin1String
#define QStringLiteral(str)
QItemEditorFactory * factory
\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