12#include <QtQml/private/qqmlimportresolver_p.h>
14#include <QtCore/qfileinfo.h>
15#include <QtCore/qdiriterator.h>
19using namespace Qt::StringLiterals;
28 m_prefix(std::move(prefix)),
29 m_name(std::move(name)),
32 m_isDependency(isDependency)
38 return !m_name.isEmpty();
43 Q_ASSERT(!prefix.endsWith(u'.'));
44 return prefix.isEmpty() ? name : (prefix + QLatin1Char(
'.') + name);
47QQmlDirParser QQmlJSImporter::createQmldirParserForFile(
const QString &filename, Import *import)
52 if (f.open(QFile::ReadOnly)) {
53 parser.parse(QString::fromUtf8(f.readAll()));
54 import->warnings.append(parser.errors(filename));
56 import->warnings.append({
57 QStringLiteral(
"Could not open qmldir file: ") + filename,
59 QQmlJS::SourceLocation()
66void QQmlJSImporter::readQmltypes(
const QString &filename, Import *result)
68 const QFileInfo fileInfo(filename);
69 if (!fileInfo.exists()) {
70 result->warnings.append({
71 QStringLiteral(
"QML types file does not exist: ") + filename,
73 QQmlJS::SourceLocation()
78 if (fileInfo.isDir()) {
79 result->warnings.append({
80 QStringLiteral(
"QML types file cannot be a directory: ") + filename,
82 QQmlJS::SourceLocation()
88 if (!file.open(QFile::ReadOnly)) {
89 result->warnings.append({
90 QStringLiteral(
"QML types file cannot be opened: ") + filename,
92 QQmlJS::SourceLocation()
97 QQmlJSTypeDescriptionReader reader { filename, QString::fromUtf8(file.readAll()) };
98 QStringList dependencyStrings;
99 auto succ = reader(&result->objects, &dependencyStrings);
101 result->warnings.append({ reader.errorMessage(), QtCriticalMsg, QQmlJS::SourceLocation() });
103 const QString warningMessage = reader.warningMessage();
104 if (!warningMessage.isEmpty())
105 result->warnings.append({ warningMessage, QtWarningMsg, QQmlJS::SourceLocation() });
107 if (dependencyStrings.isEmpty())
110 result->warnings.append({
111 QStringLiteral(
"Found deprecated dependency specifications in %1."
112 "Specify dependencies in qmldir and use qmltyperegistrar "
113 "to generate qmltypes files without dependencies.")
116 QQmlJS::SourceLocation()
119 for (
const QString &dependency : std::as_const(dependencyStrings)) {
120 const auto blank = dependency.indexOf(u' ');
122 result->dependencies.append(
123 QQmlDirParser::Import(dependency, {}, QQmlDirParser::Import::Default));
127 const QString module = dependency.left(blank);
128 const QString versionString = dependency.mid(blank + 1).trimmed();
129 if (versionString == QStringLiteral(
"auto")) {
130 result->dependencies.append(
131 QQmlDirParser::Import(module, {}, QQmlDirParser::Import::Auto));
135 const auto dot = versionString.indexOf(u'.');
137 const QTypeRevision version = dot < 0
138 ? QTypeRevision::fromMajorVersion(versionString.toUShort())
139 : QTypeRevision::fromVersion(versionString.left(dot).toUShort(),
140 versionString.mid(dot + 1).toUShort());
142 result->dependencies.append(
143 QQmlDirParser::Import(module, version, QQmlDirParser::Import::Default));
149 if (
const auto *factory = scope.factory())
150 return factory->internalName();
151 return scope->internalName();
157 return scope.factory() || scope->isComposite();
162 return isComposite(scope)
168
169
170
171QQmlJSImporter::QQmlJSImporter(
const QStringList &importPaths, QQmlJSResourceFileMapper *mapper,
172 QQmlJSImporterFlags flags)
173 : m_importPaths(importPaths),
176 m_importVisitor([](QQmlJS::AST::Node *rootNode, QQmlJSImporter *self,
177 const ImportVisitorPrerequisites &p) {
178 auto visitor = std::unique_ptr<QQmlJS::AST::BaseVisitor>(
new QQmlJSImportVisitor(
179 self, p.m_logger, p.m_implicitImportDirectory, p.m_qmldirFiles));
180 QQmlJS::AST::Node::accept(rootNode, visitor.get());
186 const QString &qmldirPath,
const QString &prefer, QQmlJSResourceFileMapper *mapper)
188 if (prefer.isEmpty())
191 if (!prefer.endsWith(u'/')) {
192 qWarning() <<
"Ignoring invalid prefer path" << prefer <<
"(has to end with slash)";
196 if (prefer.startsWith(u':')) {
201 Q_ASSERT(prefer.endsWith(u'/'));
202 const auto entry = mapper->entry(
203 QQmlJSResourceFileMapper::resourceFileFilter(prefer.mid(1) + SlashQmldir.mid(1)));
207 return entry.filePath.endsWith(SlashQmldir)
213 const QFileInfo f(prefer + SlashQmldir);
214 const QString canonical = f.canonicalFilePath();
215 if (canonical.isEmpty()) {
216 qWarning() <<
"No qmldir at" << prefer;
222QQmlJSImporter::Import QQmlJSImporter::readQmldir(
const QString &modulePath)
225 const QString moduleQmldirPath = modulePath + SlashQmldir;
226 auto reader = createQmldirParserForFile(moduleQmldirPath, &result);
228 const QString resolvedQmldirPath
229 = resolvePreferredPath(moduleQmldirPath, reader.preferredPath(), m_mapper);
230 if (resolvedQmldirPath != moduleQmldirPath)
231 reader = createQmldirParserForFile(resolvedQmldirPath, &result);
234 Q_ASSERT(resolvedQmldirPath.endsWith(SlashQmldir));
235 QStringView resolvedPath = QStringView(resolvedQmldirPath).chopped(SlashQmldir.size() - 1);
237 result.name = reader.typeNamespace();
239 result.isStaticModule = reader.isStaticModule();
240 result.isSystemModule = reader.isSystemModule();
241 result.imports.append(reader.imports());
242 result.dependencies.append(reader.dependencies());
244 if (result.isSystemModule) {
246 const QString jsrootPath = resolvedPath + JsrootDotQmltypes;
247 if (QFile::exists(jsrootPath)) {
248 readQmltypes(jsrootPath, &result);
250 result.warnings.append({
251 QStringLiteral(
"System module at %1 does not contain jsroot.qmltypes")
254 QQmlJS::SourceLocation()
259 const auto typeInfos = reader.typeInfos();
260 for (
const auto &typeInfo : typeInfos) {
261 const QString typeInfoPath = QFileInfo(typeInfo).isRelative()
262 ? resolvedPath + typeInfo
264 readQmltypes(typeInfoPath, &result);
267 if (typeInfos.isEmpty() && !reader.plugins().isEmpty()) {
268 const QString defaultTypeInfoPath = resolvedPath + PluginsDotQmltypes;
269 if (QFile::exists(defaultTypeInfoPath)) {
270 result.warnings.append({
271 QStringLiteral(
"typeinfo not declared in qmldir file: ")
272 + defaultTypeInfoPath,
274 QQmlJS::SourceLocation()
276 readQmltypes(defaultTypeInfoPath, &result);
280 QHash<QString, QQmlJSExportedScope> qmlComponents;
281 const auto components = reader.components();
282 for (
auto it = components.begin(), end = components.end(); it != end; ++it) {
283 const QString filePath = resolvedPath + it->fileName;
284 if (!QFile::exists(filePath)) {
285 result.warnings.append({
286 it->fileName + QStringLiteral(
" is listed as component in ")
288 + QStringLiteral(
" but does not exist.\n"),
290 QQmlJS::SourceLocation()
295 auto mo = qmlComponents.find(it->fileName);
296 if (mo == qmlComponents.end()) {
297 QQmlJSScope::Ptr imported = localFile2QQmlJSScope(filePath);
298 if (
auto factory = imported.factory())
299 factory->setIsSingleton(it->singleton);
301 imported->setIsSingleton(it->singleton);
302 mo = qmlComponents.insert(it->fileName, {imported, QList<QQmlJSScope::Export>() });
305 mo->exports.append(QQmlJSScope::Export(
306 reader.typeNamespace(), it.key(), it->version, QTypeRevision()));
308 for (
auto it = qmlComponents.begin(), end = qmlComponents.end(); it != end; ++it)
309 result.objects.append(it.value());
311 const auto scripts = reader.scripts();
312 for (
const auto &script : scripts) {
313 const QString filePath = resolvedPath + script.fileName;
314 auto mo = result.scripts.find(script.fileName);
315 if (mo == result.scripts.end())
316 mo = result.scripts.insert(script.fileName, { localFile2QQmlJSScope(filePath), {} });
318 mo->exports.append(QQmlJSScope::Export(
319 reader.typeNamespace(), script.nameSpace,
320 script.version, QTypeRevision()));
325QQmlJSImporter::Import QQmlJSImporter::readDirectory(
const QString &directory)
328 if (directory.startsWith(u':')) {
330 const auto resources = m_mapper->filter(
331 QQmlJSResourceFileMapper::resourceQmlDirectoryFilter(directory.mid(1)));
332 for (
const auto &entry : resources) {
333 const QString name = QFileInfo(entry.resourcePath).baseName();
334 if (name.front().isUpper()) {
335 import.objects.append({
336 localFile2QQmlJSScope(entry.filePath),
337 { QQmlJSScope::Export(QString(), name, QTypeRevision(), QTypeRevision()) }
342 qWarning() <<
"Cannot read files from resource directory" << directory
343 <<
"because no resource file mapper was provided";
350 QDirListing::IteratorFlags listingFlags = QDirListing::IteratorFlag::Default
351 | QDirListing::IteratorFlag::IncludeHidden
352 | QDirListing::IteratorFlag::FilesOnly;
353 QDirListing dirListing(
355 QStringList() << QLatin1String(
"*.qml"),
358 for (
const QDirListing::DirEntry &entry: dirListing) {
359 QString name = entry.completeBaseName();
362 if (!name.front().isUpper())
366 if (name.endsWith(u".ui"))
367 name = name.chopped(3);
370 if (name.contains(u'.'))
373 import.objects.append({
374 localFile2QQmlJSScope(entry.filePath()),
375 { QQmlJSScope::Export(QString(), name, QTypeRevision(), QTypeRevision()) }
381void QQmlJSImporter::importDependencies(
const QQmlJSImporter::Import &import, quint8 precedence,
382 QQmlJSImporter::AvailableTypes *types,
383 const QString &prefix, QTypeRevision version,
388 for (
auto const &dependency : std::as_const(import.dependencies))
389 importHelper(dependency.module, types, precedence + 1, QString(), dependency.version,
true);
391 bool hasOptionalImports =
false;
392 for (
auto const &import : std::as_const(import.imports)) {
393 if (import.flags & QQmlDirParser::Import::Optional) {
394 hasOptionalImports =
true;
395 if (!useOptionalImports()) {
399 if (!(import.flags & QQmlDirParser::Import::OptionalDefault))
403 importHelper(import.module, types, precedence + 1, isDependency ? QString() : prefix,
404 (import.flags & QQmlDirParser::Import::Auto) ? version : import.version,
408 if (hasOptionalImports && !useOptionalImports()) {
409 types->warnings.append({
410 u"%1 uses optional imports which are not supported. Some types might not be found."_s
412 QtCriticalMsg, QQmlJS::SourceLocation()
420 const QTypeRevision importVersion = importDescription.version();
422 if (!importVersion.hasMajorVersion())
424 if (importVersion.majorVersion() != exportVersion.majorVersion())
426 return !importVersion.hasMinorVersion()
427 || exportVersion.minorVersion() <= importVersion.minorVersion();
430void QQmlJSImporter::insertAliases(
const QQmlJS::ContextualType &type,
431 QQmlJSImporter::AvailableTypes *types)
433 const QStringList cppAliases = aliases(type.scope);
434 for (
const QString &alias : cppAliases)
435 types->cppNames.setType(alias, type);
438void QQmlJSImporter::insertExport(
const QQmlJS::ContextualType &type,
439 const QQmlJS::Export &valExport,
const QString &qmlName,
440 QHash<QString, QList<QQmlJSScope::Export>> *seenExports,
441 QQmlJSImporter::AvailableTypes *types)
const
443 if (m_flags.testFlag(TolerateFileSelectors)) {
444 if (
const QString fileSelector = QQmlJSUtils::fileSelectorFor(type.scope);
445 !fileSelector.isEmpty()) {
446 types->qmlNames.setFileSelectedType(fileSelector, qmlName, type);
450 types->qmlNames.setType(qmlName, type);
451 (*seenExports)[qmlName].append(valExport);
455QQmlJSImporter::resolveConflictingExports(
const QQmlJS::Import &importDescription,
456 const QQmlJSExportedScope &val, quint8 precedence,
457 QHash<QString, QList<QQmlJSScope::Export>> *seenExports,
458 QQmlJSImporter::AvailableTypes *types)
460 QQmlJSScope::Export bestExport;
462 for (
const auto &valExport : val.exports) {
463 const QString qmlName = prefixedName(importDescription.prefix(), valExport.type());
464 if (!isVersionAllowed(valExport, importDescription))
469 if (!bestExport.isValid() || valExport.version() > bestExport.version())
470 bestExport = valExport;
472 auto insertExportWithConflict = [&](
const QQmlJSImportedScope &conflicting) {
478 if (conflicting.scope == val.scope && conflicting.revision == valExport.version())
481 const SeenVersion seenVersion = computeSeenVersion(
482 importDescription, seenExports->value(qmlName), valExport.version());
484 insertExportWithConflictingVersion(val, precedence, qmlName, valExport,
485 conflicting.scope, seenExports, types, seenVersion);
488 if (
const auto it = types->qmlNames.types().find(qmlName);
489 it != types->qmlNames.types().end()) {
490 insertExportWithConflict(*it);
494 const auto [it, end] = types->qmlNames.fileSelectionsEqualRange(qmlName);
496 insertExport({ val.scope, valExport.version(), precedence }, valExport, qmlName,
500 insertExportWithConflict(it->type);
505QQmlJSImporter::SeenVersion
506QQmlJSImporter::computeSeenVersion(
const QQmlJS::Import &importDescription,
507 const QList<QQmlJS::Export> &existingExports,
508 QTypeRevision valExportVersion)
const
510 QQmlJSImporter::SeenVersion seenVersion = LowerVersion;
511 for (
const QQmlJSScope::Export &entry : existingExports) {
512 if (!isVersionAllowed(entry, importDescription))
515 if (valExportVersion < entry.version()) {
516 seenVersion = HigherVersion;
520 if (seenVersion == LowerVersion && valExportVersion == entry.version())
521 seenVersion = SameVersion;
526void QQmlJSImporter::insertExportWithConflictingVersion(
527 const QQmlJSExportedScope &val, quint8 precedence,
const QString &qmlName,
528 const QQmlJSScope::Export &valExport,
const QQmlJSScope::ConstPtr &scope,
529 QHash<QString, QList<QQmlJSScope::Export>> *seenExports,
530 QQmlJSImporter::AvailableTypes *types, SeenVersion seenVersion)
const
532 auto onDuplicateImport = [&]() {
533 types->warnings.append({ QStringLiteral(
"Ambiguous type detected. "
534 "%1 %2.%3 is defined multiple times.")
536 .arg(valExport.version().majorVersion())
537 .arg(valExport.version().minorVersion()),
538 QtCriticalMsg, QQmlJS::SourceLocation() });
541 types->qmlNames.clearType(qmlName);
543 switch (seenVersion) {
545 insertExport({ val.scope, valExport.version(), precedence }, valExport, qmlName,
549 if (!m_flags.testAnyFlag(QQmlJSImporterFlag::TolerateFileSelectors) || !scope) {
553 if (
const QString fileSelector = QQmlJSUtils::fileSelectorFor(val.scope);
554 !fileSelector.isEmpty()) {
555 types->qmlNames.setFileSelectedType(fileSelector, qmlName,
556 { val.scope, valExport.version(), precedence });
559 if (!QQmlJSUtils::fileSelectorFor(scope).isEmpty()) {
561 types->qmlNames.setType(qmlName, { val.scope, valExport.version(), precedence });
562 (*seenExports)[qmlName].append(valExport);
573void QQmlJSImporter::insertExports(
const QQmlJS::Import &importDescription,
574 const QQmlJSExportedScope &val,
const QString &cppName,
576 QHash<QString, QList<QQmlJSScope::Export>> *seenExports,
577 QQmlJSImporter::AvailableTypes *types)
579 const QQmlJSScope::Export bestExport =
580 resolveConflictingExports(importDescription, val, precedence, seenExports, types);
581 const QTypeRevision bestRevision =
582 bestExport.isValid() ? bestExport.revision() : QTypeRevision::zero();
583 const QQmlJS::ContextualType contextualType{ val.scope, bestRevision, precedence };
584 types->cppNames.setType(cppName, contextualType);
586 insertAliases(contextualType, types);
588 const QTypeRevision bestVersion =
589 bestExport.isValid() ? bestExport.version() : QTypeRevision::zero();
590 types->qmlNames.setType(prefixedName(internalPrefix, cppName),
591 { val.scope, bestVersion, precedence });
594void QQmlJSImporter::processImport(
const QQmlJS::Import &importDescription,
595 const QQmlJSImporter::Import &import, quint8 precedence,
596 QQmlJSImporter::AvailableTypes *types)
598 QHash<QString, QList<QQmlJSScope::Export>> seenExports;
601 if (!importDescription.prefix().isEmpty())
602 types->qmlNames.setType(importDescription.prefix(), { {}, precedence });
604 if (!importDescription.isDependency()) {
606 types->qmlNames.setType(prefixedName(modulePrefix, importDescription.name()),
609 if (import.isStaticModule)
610 types->staticModules << import.name;
612 if (import.isSystemModule)
613 types->hasSystemModule =
true;
615 types->warnings.append(import.warnings);
618 for (
auto it = import.scripts.begin(); it != import.scripts.end(); ++it) {
620 Q_ASSERT(!it->exports.isEmpty());
621 insertExports(importDescription, *it, prefixedName(anonPrefix, internalName(it->scope)),
622 precedence, &seenExports, types);
626 for (
const auto &val : import.objects) {
627 const QString cppName = isComposite(val.scope)
628 ? prefixedName(anonPrefix, internalName(val.scope))
629 : internalName(val.scope);
631 if (val.exports.isEmpty()) {
632 const QQmlJS::ContextualType unresolvableDummyName{ val.scope, QTypeRevision(),
634 types->qmlNames.setType(prefixedName(internalPrefix, cppName), unresolvableDummyName);
635 types->cppNames.setType(cppName, unresolvableDummyName);
636 insertAliases(unresolvableDummyName, types);
638 insertExports(importDescription, val, cppName, precedence, &seenExports, types);
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
663 QQmlJSImporter::AvailableTypes tempTypes(builtinImportHelper().cppNames);
664 tempTypes.cppNames.addTypes(types->cppNames);
671 const QQmlJSScope::ConstPtr arrayType = tempTypes.cppNames.type(u"Array"_s).scope;
672 for (
auto it = import.objects.begin(); it != import.objects.end(); ++it) {
673 if (!it->scope.factory()) {
674 QQmlJSScope::resolveEnums(it->scope, tempTypes.cppNames);
675 QQmlJSScope::resolveList(it->scope, arrayType);
679 for (
const auto &val : std::as_const(import.objects)) {
681 if (!val.scope.factory() && val.scope->baseType().isNull()) {
685 if (val.scope->baseTypeName() == s_inProcessMarker)
691 if (val.scope->isComposite()) {
692 types->warnings.append({
693 QStringLiteral(
"Found incomplete composite type %1. Do not use qmlplugindump.")
694 .arg(val.scope->internalName()),
696 QQmlJS::SourceLocation()
700 QQmlJSScope::resolveNonEnumTypes(val.scope, tempTypes.cppNames);
706
707
708
709QQmlJSImporter::ImportedTypes QQmlJSImporter::importHardCodedBuiltins()
711 const auto builtins = builtinImportHelper();
713 QQmlJS::ContextualTypes result(
714 QQmlJS::ContextualTypes::QML, {}, {}, builtins.cppNames.arrayType());
715 for (
const QString hardcoded : {
716 "void"_L1,
"int"_L1,
"bool"_L1,
"double"_L1,
"real"_L1,
"string"_L1,
"url"_L1,
717 "date"_L1,
"regexp"_L1,
"rect"_L1,
"point"_L1,
"size"_L1,
"variant"_L1,
"var"_L1,
720 const auto type = builtins.qmlNames.type(hardcoded);
721 Q_ASSERT(type.scope);
722 result.setType(hardcoded, { type, QQmlJS::PrecedenceValues::Default });
725 return ImportedTypes(std::move(result), {});
729QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
734 AvailableTypes builtins(QQmlJS::ContextualTypes(QQmlJS::ContextualTypes::INTERNAL, {}, {}, {}));
736 importHelper(u"QML"_s, &builtins, QQmlJS::PrecedenceValues::Default, QString(),
737 QTypeRevision::fromVersion(1, 0));
739 QQmlJSScope::ConstPtr arrayType = builtins.cppNames.type(u"Array"_s).scope;
742 m_builtins = AvailableTypes(QQmlJS::ContextualTypes(
743 QQmlJS::ContextualTypes::INTERNAL, builtins.cppNames.types(), builtins.cppNames.names(),
745 m_builtins->qmlNames = QQmlJS::ContextualTypes(
746 QQmlJS::ContextualTypes::QML, builtins.qmlNames.types(), builtins.qmlNames.names(),
748 m_builtins->staticModules = std::move(builtins.staticModules);
749 m_builtins->warnings = std::move(builtins.warnings);
750 m_builtins->hasSystemModule = builtins.hasSystemModule;
756
757
758QList<QQmlJS::DiagnosticMessage> QQmlJSImporter::importQmldirs(
const QStringList &qmldirFiles)
760 QList<QQmlJS::DiagnosticMessage> warnings;
761 for (
const auto &file : qmldirFiles) {
764 if (file.endsWith(SlashQmldir)) {
765 result = readQmldir(file.chopped(SlashQmldir.size()));
766 setQualifiedNamesOn(result);
770 QStringLiteral(
"Argument %1 to -i option is not a qmldir file. Assuming qmltypes.")
773 QQmlJS::SourceLocation()
776 readQmltypes(file, &result);
781 qmldirName = file + QStringLiteral(
"_FAKE_QMLDIR");
784 warnings.append(result.warnings);
785 m_seenQmldirFiles.insert(qmldirName, result);
787 for (
const auto &object : std::as_const(result.objects)) {
788 for (
const auto &ex : object.exports) {
789 m_seenImports.insert({ex.package(), ex.version()}, qmldirName);
791 m_seenImports.insert({ex.package(), QTypeRevision()}, qmldirName);
799QQmlJSImporter::ImportedTypes QQmlJSImporter::importModule(
const QString &module, quint8 precedence,
800 const QString &prefix,
801 QTypeRevision version,
802 QStringList *staticModuleList)
804 const AvailableTypes builtins = builtinImportHelper();
805 AvailableTypes result(builtins.cppNames);
806 if (!importHelper(module, &result, precedence, prefix, version)) {
807 result.warnings.append({
808 QStringLiteral(
"Failed to import %1. Are your import paths set up properly?")
811 QQmlJS::SourceLocation()
815 if (staticModuleList)
816 *staticModuleList << result.staticModules;
818 return ImportedTypes(std::move(result.qmlNames), std::move(result.warnings));
821QQmlJSImporter::ImportedTypes QQmlJSImporter::builtinInternalNames()
823 auto builtins = builtinImportHelper();
824 return ImportedTypes(std::move(builtins.cppNames), std::move(builtins.warnings));
827bool QQmlJSImporter::importHelper(
const QString &module, AvailableTypes *types, quint8 precedence,
828 const QString &prefix, QTypeRevision version,
bool isDependency,
832 const QString moduleCacheName = QString(module).replace(u'/', u'.');
835 Q_ASSERT(prefix.isEmpty());
837 const QQmlJS::Import cacheKey(prefix, moduleCacheName, version, isFile, isDependency);
839 auto getTypesFromCache = [&]() ->
bool {
840 if (!m_cachedImportTypes.contains(cacheKey))
843 const auto &cacheEntry = m_cachedImportTypes[cacheKey];
845 types->cppNames.addTypes(cacheEntry->cppNames);
846 types->staticModules << cacheEntry->staticModules;
847 types->hasSystemModule |= cacheEntry->hasSystemModule;
851 types->warnings.append(cacheEntry->warnings);
852 types->qmlNames.addTypes(cacheEntry->qmlNames);
858 if (getTypesFromCache())
861 auto cacheTypes = QSharedPointer<QQmlJSImporter::AvailableTypes>(
862 new QQmlJSImporter::AvailableTypes(QQmlJS::ContextualTypes(
863 QQmlJS::ContextualTypes::INTERNAL, {}, {}, types->cppNames.arrayType())));
864 m_cachedImportTypes[cacheKey] = cacheTypes;
866 const std::pair<QString, QTypeRevision> importId { module, version };
867 const auto it = m_seenImports.constFind(importId);
869 if (it != m_seenImports.constEnd()) {
873 Q_ASSERT(m_seenQmldirFiles.contains(*it));
874 const QQmlJSImporter::Import import = m_seenQmldirFiles.value(*it);
876 importDependencies(import, precedence, cacheTypes.get(), prefix, version, isDependency);
877 processImport(cacheKey, import, precedence, cacheTypes.get());
879 const bool typesFromCache = getTypesFromCache();
880 Q_ASSERT(typesFromCache);
881 return typesFromCache;
884 QStringList modulePaths;
886 const auto import = readDirectory(module);
887 m_seenQmldirFiles.insert(module, import);
888 m_seenImports.insert(importId, module);
889 importDependencies(import, precedence, cacheTypes.get(), prefix, version, isDependency);
890 processImport(cacheKey, import, precedence, cacheTypes.get());
893 modulePaths.append(module);
894 }
else if (module ==
"QML"_L1) {
898 modulePaths = {
":/qt-project.org/imports/QML"_L1 };
900 modulePaths = qQmlResolveImportPaths(module, m_importPaths, version);
903 for (
auto const &modulePath : std::as_const(modulePaths)) {
904 QString qmldirPath = modulePath + SlashQmldir;
905 if (modulePath.startsWith(u':')) {
906 if (module ==
"QML"_L1) {
908 }
else if (m_mapper) {
909 const QString resourcePath = modulePath.mid(
910 1, modulePath.endsWith(u'/') ? modulePath.size() - 2 : -1)
912 const auto entry = m_mapper->entry(
913 QQmlJSResourceFileMapper::resourceFileFilter(resourcePath));
914 qmldirPath = entry.filePath;
917 qWarning() <<
"Cannot read files from resource directory" << modulePath
918 <<
"because no resource file mapper was provided";
922 const auto it = m_seenQmldirFiles.constFind(qmldirPath);
923 if (it != m_seenQmldirFiles.constEnd()) {
924 const QQmlJSImporter::Import import = *it;
925 m_seenImports.insert(importId, qmldirPath);
926 importDependencies(import, precedence, cacheTypes.get(), prefix, version, isDependency);
927 processImport(cacheKey, import, precedence, cacheTypes.get());
929 const bool typesFromCache = getTypesFromCache();
930 Q_ASSERT(typesFromCache);
931 return typesFromCache;
934 const QFileInfo file(qmldirPath);
936 const auto import = readQmldir(file.canonicalPath());
937 setQualifiedNamesOn(import);
938 m_seenQmldirFiles.insert(qmldirPath, import);
939 m_seenImports.insert(importId, qmldirPath);
940 importDependencies(import, precedence, cacheTypes.get(), prefix, version, isDependency);
943 processImport(cacheKey, import, precedence, cacheTypes.get());
945 const bool typesFromCache = getTypesFromCache();
946 Q_ASSERT(typesFromCache);
947 return typesFromCache;
953 const bool typesFromCache = getTypesFromCache();
954 Q_ASSERT(typesFromCache);
955 return typesFromCache;
958 m_seenImports.insert(importId, QString());
962QQmlJSScope::Ptr QQmlJSImporter::localFile2QQmlJSScope(
const QString &filePath)
964 const QString sourceFolderFile = preferQmlFilesFromSourceFolder()
965 ? QQmlJSUtils::qmlSourcePathFromBuildPath(m_mapper, filePath)
968 const auto seen = m_importedFiles.find(sourceFolderFile);
969 if (seen != m_importedFiles.end())
972 return *m_importedFiles.insert(
974 { QQmlJSScope::create(),
975 QSharedPointer<QDeferredFactory<QQmlJSScope>>(
new QDeferredFactory<QQmlJSScope>(
976 this, {}, sourceFolderFile, QString(),
false)) });
979QQmlJSScope::Ptr QQmlJSImporter::importFile(
const QString &file)
981 return localFile2QQmlJSScope(file);
984QQmlJSImporter::ImportedTypes
985QQmlJSImporter::importDirectory(
const QString &directory, quint8 precedence,
const QString &prefix)
987 const AvailableTypes builtins = builtinImportHelper();
988 QQmlJSImporter::AvailableTypes types(QQmlJS::ContextualTypes(
989 QQmlJS::ContextualTypes::INTERNAL, {}, {}, builtins.cppNames.arrayType()));
990 importHelper(directory, &types, precedence, prefix, QTypeRevision(),
false,
true);
991 return ImportedTypes(std::move(types.qmlNames), std::move(types.warnings));
994void QQmlJSImporter::setImportPaths(
const QStringList &importPaths)
996 if (m_importPaths == importPaths)
999 m_importPaths = importPaths;
1003 m_seenImports.clear();
1004 m_cachedImportTypes.clear();
1008void QQmlJSImporter::clearCache()
1010 m_seenImports.clear();
1011 m_cachedImportTypes.clear();
1012 m_seenQmldirFiles.clear();
1013 m_importedFiles.clear();
1017QQmlJSScope::ConstPtr QQmlJSImporter::jsGlobalObject()
1019 return builtinImportHelper().cppNames.type(u"GlobalObject"_s).scope;
1022void QQmlJSImporter::setQualifiedNamesOn(
const Import &import)
1024 for (
auto &object : import.objects) {
1025 if (object.exports.isEmpty())
1027 if (
auto *factory = object.scope.factory()) {
1028 factory->setModuleName(import.name);
1030 object.scope->setOwnModuleName(import.name);
1035void QQmlJSImporter::runImportVisitor(QQmlJS::AST::Node *rootNode,
1036 const ImportVisitorPrerequisites &p)
1038 m_importVisitor(rootNode,
this, p);
Combined button and popup list for selecting options.
static QStringList aliases(const QQmlJSScope::ConstPtr &scope)
static const QLatin1String JsrootDotQmltypes
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 const QLatin1String SlashQmldir
static QString internalName(const QQmlJSScope::ConstPtr &scope)
static const QLatin1String PluginsDotQmltypes