12#include <QtQml/private/qqmlimportresolver_p.h>
14#include <QtCore/qfileinfo.h>
15#include <QtCore/qdiriterator.h>
19using namespace Qt::StringLiterals;
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)
167QQmlJSImporter::QQmlJSImporter(
const QStringList &importPaths, QQmlJSResourceFileMapper *mapper,
168 QQmlJSImporterFlags flags)
169 : m_importPaths(importPaths),
172 m_importVisitor([](QQmlJS::AST::Node *rootNode, QQmlJSImporter *self,
173 const ImportVisitorPrerequisites &p) {
174 auto visitor = std::unique_ptr<QQmlJS::AST::BaseVisitor>(
new QQmlJSImportVisitor(
175 p.m_target, self, p.m_logger, p.m_implicitImportDirectory, p.m_qmldirFiles));
176 QQmlJS::AST::Node::accept(rootNode, visitor.get());
182 const QString &qmldirPath,
const QString &prefer, QQmlJSResourceFileMapper *mapper)
184 if (prefer.isEmpty())
187 if (!prefer.endsWith(u'/')) {
188 qWarning() <<
"Ignoring invalid prefer path" << prefer <<
"(has to end with slash)";
192 if (prefer.startsWith(u':')) {
197 Q_ASSERT(prefer.endsWith(u'/'));
198 const auto entry = mapper->entry(
199 QQmlJSResourceFileMapper::resourceFileFilter(prefer.mid(1) + SlashQmldir.mid(1)));
203 return entry.filePath.endsWith(SlashQmldir)
209 const QFileInfo f(prefer + SlashQmldir);
210 const QString canonical = f.canonicalFilePath();
211 if (canonical.isEmpty()) {
212 qWarning() <<
"No qmldir at" << prefer;
218QQmlJSImporter::Import QQmlJSImporter::readQmldir(
const QString &modulePath)
221 const QString moduleQmldirPath = modulePath + SlashQmldir;
222 auto reader = createQmldirParserForFile(moduleQmldirPath, &result);
224 const QString resolvedQmldirPath
225 = resolvePreferredPath(moduleQmldirPath, reader.preferredPath(), m_mapper);
226 if (resolvedQmldirPath != moduleQmldirPath)
227 reader = createQmldirParserForFile(resolvedQmldirPath, &result);
230 Q_ASSERT(resolvedQmldirPath.endsWith(SlashQmldir));
231 QStringView resolvedPath = QStringView(resolvedQmldirPath).chopped(SlashQmldir.size() - 1);
233 result.name = reader.typeNamespace();
235 result.isStaticModule = reader.isStaticModule();
236 result.isSystemModule = reader.isSystemModule();
237 result.imports.append(reader.imports());
238 result.dependencies.append(reader.dependencies());
240 if (result.isSystemModule) {
242 const QString jsrootPath = resolvedPath + JsrootDotQmltypes;
243 if (QFile::exists(jsrootPath)) {
244 readQmltypes(jsrootPath, &result);
246 result.warnings.append({
247 QStringLiteral(
"System module at %1 does not contain jsroot.qmltypes")
250 QQmlJS::SourceLocation()
255 const auto typeInfos = reader.typeInfos();
256 for (
const auto &typeInfo : typeInfos) {
257 const QString typeInfoPath = QFileInfo(typeInfo).isRelative()
258 ? resolvedPath + typeInfo
260 readQmltypes(typeInfoPath, &result);
263 if (typeInfos.isEmpty() && !reader.plugins().isEmpty()) {
264 const QString defaultTypeInfoPath = resolvedPath + PluginsDotQmltypes;
265 if (QFile::exists(defaultTypeInfoPath)) {
266 result.warnings.append({
267 QStringLiteral(
"typeinfo not declared in qmldir file: ")
268 + defaultTypeInfoPath,
270 QQmlJS::SourceLocation()
272 readQmltypes(defaultTypeInfoPath, &result);
276 QHash<QString, QQmlJSExportedScope> qmlComponents;
277 const auto components = reader.components();
278 for (
auto it = components.begin(), end = components.end(); it != end; ++it) {
279 const QString filePath = resolvedPath + it->fileName;
280 if (!QFile::exists(filePath)) {
281 result.warnings.append({
282 it->fileName + QStringLiteral(
" is listed as component in ")
284 + QStringLiteral(
" but does not exist.\n"),
286 QQmlJS::SourceLocation()
291 auto mo = qmlComponents.find(it->fileName);
292 if (mo == qmlComponents.end()) {
293 QQmlJSScope::Ptr imported = localFile2QQmlJSScope(filePath);
294 if (
auto *factory = imported.factory()) {
296 factory->setIsSingleton(
true);
299 mo = qmlComponents.insert(it->fileName, {imported, QList<QQmlJSScope::Export>() });
302 mo->exports.append(QQmlJSScope::Export(
303 reader.typeNamespace(), it.key(), it->version, QTypeRevision()));
305 for (
auto it = qmlComponents.begin(), end = qmlComponents.end(); it != end; ++it)
306 result.objects.append(it.value());
308 const auto scripts = reader.scripts();
309 for (
const auto &script : scripts) {
310 const QString filePath = resolvedPath + script.fileName;
311 auto mo = result.scripts.find(script.fileName);
312 if (mo == result.scripts.end())
313 mo = result.scripts.insert(script.fileName, { localFile2QQmlJSScope(filePath), {} });
315 mo->exports.append(QQmlJSScope::Export(
316 reader.typeNamespace(), script.nameSpace,
317 script.version, QTypeRevision()));
322QQmlJSImporter::Import QQmlJSImporter::readDirectory(
const QString &directory)
325 if (directory.startsWith(u':')) {
327 const auto resources = m_mapper->filter(
328 QQmlJSResourceFileMapper::resourceQmlDirectoryFilter(directory.mid(1)));
329 for (
const auto &entry : resources) {
330 const QString name = QFileInfo(entry.resourcePath).baseName();
331 if (name.front().isUpper()) {
332 import.objects.append({
333 localFile2QQmlJSScope(entry.filePath),
334 { QQmlJSScope::Export(QString(), name, QTypeRevision(), QTypeRevision()) }
339 qWarning() <<
"Cannot read files from resource directory" << directory
340 <<
"because no resource file mapper was provided";
347 QDirListing::IteratorFlags listingFlags = QDirListing::IteratorFlag::Default
348 | QDirListing::IteratorFlag::IncludeHidden
349 | QDirListing::IteratorFlag::FilesOnly;
350 QDirListing dirListing(
352 QStringList() << QLatin1String(
"*.qml"),
355 for (
const QDirListing::DirEntry &entry: dirListing) {
356 QString name = entry.completeBaseName();
359 if (!name.front().isUpper())
363 if (name.endsWith(u".ui"))
364 name = name.chopped(3);
367 if (name.contains(u'.'))
370 import.objects.append({
371 localFile2QQmlJSScope(entry.filePath()),
372 { QQmlJSScope::Export(QString(), name, QTypeRevision(), QTypeRevision()) }
378void QQmlJSImporter::importDependencies(
379 const QQmlJSImporter::Import &import, QQmlJSImporter::AvailableTypes *types,
380 const QString &prefix, QTypeRevision version,
bool isDependency)
384 for (
auto const &dependency : std::as_const(import.dependencies))
385 importHelper(dependency.module, types, QString(), dependency.version,
true);
387 bool hasOptionalImports =
false;
388 for (
auto const &import : std::as_const(import.imports)) {
389 if (import.flags & QQmlDirParser::Import::Optional) {
390 hasOptionalImports =
true;
391 if (!useOptionalImports()) {
395 if (!(import.flags & QQmlDirParser::Import::OptionalDefault))
399 importHelper(import.module, types, isDependency ? QString() : prefix,
400 (import.flags & QQmlDirParser::Import::Auto) ? version : import.version,
404 if (hasOptionalImports && !useOptionalImports()) {
405 types->warnings.append({
406 u"%1 uses optional imports which are not supported. Some types might not be found."_s
408 QtCriticalMsg, QQmlJS::SourceLocation()
416 const QTypeRevision importVersion = importDescription.version();
417 const QTypeRevision exportVersion = exportEntry.version();
418 if (!importVersion.hasMajorVersion())
420 if (importVersion.majorVersion() != exportVersion.majorVersion())
422 return !importVersion.hasMinorVersion()
423 || exportVersion.minorVersion() <= importVersion.minorVersion();
427
428
430 for (
const auto &[propertyName, prop]: scope1->properties().asKeyValueRange())
431 if (!scope2->hasProperty(propertyName))
433 for (
const auto &[methodName, method]: scope1->methods().asKeyValueRange())
434 if (!scope2->hasMethod(methodName))
439void QQmlJSImporter::processImport(
440 const QQmlJS::Import &importDescription,
const QQmlJSImporter::Import &import,
441 QQmlJSImporter::AvailableTypes *types)
447 const QString anonPrefix = QStringLiteral(
"$anonymous$");
448 const QString internalPrefix = QStringLiteral(
"$internal$");
449 const QString modulePrefix = QStringLiteral(
"$module$");
450 QHash<QString, QList<QQmlJSScope::Export>> seenExports;
452 const auto insertAliases = [&](
const QQmlJSScope::ConstPtr &scope, QTypeRevision revision) {
453 const QStringList cppAliases = aliases(scope);
454 for (
const QString &alias : cppAliases)
455 types->cppNames.setType(alias, { scope, revision });
458 const auto insertExports = [&](
const QQmlJSExportedScope &val,
const QString &cppName) {
459 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 const auto it = types->qmlNames.types().find(qmlName);
473 if (it != types->qmlNames.types().end()) {
480 if (it->scope == val.scope && it->revision == valExport.version())
483 const auto existingExports = seenExports.value(qmlName);
484 enum { LowerVersion, SameVersion, HigherVersion } seenVersion = LowerVersion;
485 for (
const QQmlJSScope::Export &entry : existingExports) {
486 if (!isVersionAllowed(entry, importDescription))
489 if (valExport.version() < entry.version()) {
490 seenVersion = HigherVersion;
494 if (seenVersion == LowerVersion && valExport.version() == entry.version())
495 seenVersion = SameVersion;
498 switch (seenVersion) {
502 if (m_flags & QQmlJSImporterFlag::TolerateFileSelectors) {
503 auto isFileSelected = [](
const QQmlJSScope::ConstPtr &scope) ->
bool
505 return scope->filePath().contains(u"+");
507 auto warnAboutFileSelector = [&](
const QString &path) {
508 types->warnings.append({
509 QStringLiteral(
"Type %1 is ambiguous due to file selector usage, ignoring %2.")
512 QQmlJS::SourceLocation()
516 if (isFileSelected(val.scope)) {
518 if (fileSelectedScopesAreCompatibleHeuristic(it->scope, val.scope)) {
519 warnAboutFileSelector(val.scope->filePath());
522 }
else if (isFileSelected(it->scope)) {
525 if (fileSelectedScopesAreCompatibleHeuristic(it->scope, val.scope)) {
526 warnAboutFileSelector(it->scope->filePath());
532 types->warnings.append({
533 QStringLiteral(
"Ambiguous type detected. "
534 "%1 %2.%3 is defined multiple times.")
536 .arg(valExport.version().majorVersion())
537 .arg(valExport.version().minorVersion()),
539 QQmlJS::SourceLocation()
543 types->qmlNames.clearType(qmlName);
551 types->qmlNames.setType(qmlName, { val.scope, valExport.version() });
552 seenExports[qmlName].append(valExport);
555 const QTypeRevision bestRevision = bestExport.isValid()
556 ? bestExport.revision()
557 : QTypeRevision::zero();
558 types->cppNames.setType(cppName, { val.scope, bestRevision });
560 insertAliases(val.scope, bestRevision);
562 const QTypeRevision bestVersion = bestExport.isValid()
563 ? bestExport.version()
564 : QTypeRevision::zero();
565 types->qmlNames.setType(prefixedName(internalPrefix, cppName), { val.scope, bestVersion });
569 if (!importDescription.prefix().isEmpty())
570 types->qmlNames.setType(importDescription.prefix(), {});
572 if (!importDescription.isDependency()) {
574 types->qmlNames.setType(prefixedName(modulePrefix, importDescription.name()), {});
576 if (import.isStaticModule)
577 types->staticModules << import.name;
579 if (import.isSystemModule)
580 types->hasSystemModule =
true;
582 types->warnings.append(import.warnings);
585 for (
auto it = import.scripts.begin(); it != import.scripts.end(); ++it) {
587 Q_ASSERT(!it->exports.isEmpty());
588 insertExports(*it, prefixedName(anonPrefix, internalName(it->scope)));
592 for (
const auto &val : import.objects) {
593 const QString cppName = isComposite(val.scope)
594 ? prefixedName(anonPrefix, internalName(val.scope))
595 : internalName(val.scope);
597 if (val.exports.isEmpty()) {
599 types->qmlNames.setType(
600 prefixedName(internalPrefix, cppName), { val.scope, QTypeRevision() });
601 types->cppNames.setType(cppName, { val.scope, QTypeRevision() });
602 insertAliases(val.scope, QTypeRevision());
604 insertExports(val, cppName);
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
629 QQmlJSImporter::AvailableTypes tempTypes(builtinImportHelper().cppNames);
630 tempTypes.cppNames.addTypes(types->cppNames);
637 const QQmlJSScope::ConstPtr arrayType = tempTypes.cppNames.type(u"Array"_s).scope;
638 for (
auto it = import.objects.begin(); it != import.objects.end(); ++it) {
639 if (!it->scope.factory()) {
640 QQmlJSScope::resolveEnums(it->scope, tempTypes.cppNames);
641 QQmlJSScope::resolveList(it->scope, arrayType);
645 for (
const auto &val : std::as_const(import.objects)) {
647 if (!val.scope.factory() && val.scope->baseType().isNull()) {
651 if (val.scope->baseTypeName() ==
"$InProcess$"_L1)
657 if (val.scope->isComposite()) {
658 types->warnings.append({
659 QStringLiteral(
"Found incomplete composite type %1. Do not use qmlplugindump.")
660 .arg(val.scope->internalName()),
662 QQmlJS::SourceLocation()
666 QQmlJSScope::resolveNonEnumTypes(val.scope, tempTypes.cppNames);
672
673
674
675QQmlJSImporter::ImportedTypes QQmlJSImporter::importHardCodedBuiltins()
677 const auto builtins = builtinImportHelper();
679 QQmlJS::ContextualTypes result(
680 QQmlJS::ContextualTypes::QML, {}, {}, builtins.cppNames.arrayType());
681 for (
const QString hardcoded : {
682 "void"_L1,
"int"_L1,
"bool"_L1,
"double"_L1,
"real"_L1,
"string"_L1,
"url"_L1,
683 "date"_L1,
"regexp"_L1,
"rect"_L1,
"point"_L1,
"size"_L1,
"variant"_L1,
"var"_L1,
686 const auto type = builtins.qmlNames.type(hardcoded);
687 Q_ASSERT(type.scope);
688 result.setType(hardcoded, type);
691 return ImportedTypes(std::move(result), {});
695QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
700 AvailableTypes builtins(QQmlJS::ContextualTypes(QQmlJS::ContextualTypes::INTERNAL, {}, {}, {}));
702 importHelper(u"QML"_s, &builtins, QString(), QTypeRevision::fromVersion(1, 0));
704 QQmlJSScope::ConstPtr arrayType = builtins.cppNames.type(u"Array"_s).scope;
707 m_builtins = AvailableTypes(QQmlJS::ContextualTypes(
708 QQmlJS::ContextualTypes::INTERNAL, builtins.cppNames.types(), builtins.cppNames.names(),
710 m_builtins->qmlNames = QQmlJS::ContextualTypes(
711 QQmlJS::ContextualTypes::QML, builtins.qmlNames.types(), builtins.qmlNames.names(),
713 m_builtins->staticModules = std::move(builtins.staticModules);
714 m_builtins->warnings = std::move(builtins.warnings);
715 m_builtins->hasSystemModule = builtins.hasSystemModule;
721
722
723QList<QQmlJS::DiagnosticMessage> QQmlJSImporter::importQmldirs(
const QStringList &qmldirFiles)
725 QList<QQmlJS::DiagnosticMessage> warnings;
726 for (
const auto &file : qmldirFiles) {
729 if (file.endsWith(SlashQmldir)) {
730 result = readQmldir(file.chopped(SlashQmldir.size()));
731 setQualifiedNamesOn(result);
735 QStringLiteral(
"Argument %1 to -i option is not a qmldir file. Assuming qmltypes.")
738 QQmlJS::SourceLocation()
741 readQmltypes(file, &result);
746 qmldirName = file + QStringLiteral(
"_FAKE_QMLDIR");
749 warnings.append(result.warnings);
750 m_seenQmldirFiles.insert(qmldirName, result);
752 for (
const auto &object : std::as_const(result.objects)) {
753 for (
const auto &ex : object.exports) {
754 m_seenImports.insert({ex.package(), ex.version()}, qmldirName);
756 m_seenImports.insert({ex.package(), QTypeRevision()}, qmldirName);
764QQmlJSImporter::ImportedTypes QQmlJSImporter::importModule(
const QString &module,
765 const QString &prefix,
766 QTypeRevision version,
767 QStringList *staticModuleList)
769 const AvailableTypes builtins = builtinImportHelper();
770 AvailableTypes result(builtins.cppNames);
771 if (!importHelper(module, &result, prefix, version)) {
772 result.warnings.append({
773 QStringLiteral(
"Failed to import %1. Are your import paths set up properly?")
776 QQmlJS::SourceLocation()
780 if (staticModuleList)
781 *staticModuleList << result.staticModules;
783 return ImportedTypes(std::move(result.qmlNames), std::move(result.warnings));
786QQmlJSImporter::ImportedTypes QQmlJSImporter::builtinInternalNames()
788 auto builtins = builtinImportHelper();
789 return ImportedTypes(std::move(builtins.cppNames), std::move(builtins.warnings));
792bool QQmlJSImporter::importHelper(
const QString &module, AvailableTypes *types,
793 const QString &prefix, QTypeRevision version,
bool isDependency,
797 const QString moduleCacheName = QString(module).replace(u'/', u'.');
800 Q_ASSERT(prefix.isEmpty());
802 const QQmlJS::Import cacheKey(prefix, moduleCacheName, version, isFile, isDependency);
804 auto getTypesFromCache = [&]() ->
bool {
805 if (!m_cachedImportTypes.contains(cacheKey))
808 const auto &cacheEntry = m_cachedImportTypes[cacheKey];
810 types->cppNames.addTypes(cacheEntry->cppNames);
811 types->staticModules << cacheEntry->staticModules;
812 types->hasSystemModule |= cacheEntry->hasSystemModule;
816 types->warnings.append(cacheEntry->warnings);
817 types->qmlNames.addTypes(cacheEntry->qmlNames);
823 if (getTypesFromCache())
826 auto cacheTypes = QSharedPointer<QQmlJSImporter::AvailableTypes>(
827 new QQmlJSImporter::AvailableTypes(QQmlJS::ContextualTypes(
828 QQmlJS::ContextualTypes::INTERNAL, {}, {}, types->cppNames.arrayType())));
829 m_cachedImportTypes[cacheKey] = cacheTypes;
831 const std::pair<QString, QTypeRevision> importId { module, version };
832 const auto it = m_seenImports.constFind(importId);
834 if (it != m_seenImports.constEnd()) {
838 Q_ASSERT(m_seenQmldirFiles.contains(*it));
839 const QQmlJSImporter::Import import = m_seenQmldirFiles.value(*it);
841 importDependencies(import, cacheTypes.get(), prefix, version, isDependency);
842 processImport(cacheKey, import, cacheTypes.get());
844 const bool typesFromCache = getTypesFromCache();
845 Q_ASSERT(typesFromCache);
846 return typesFromCache;
849 QStringList modulePaths;
851 const auto import = readDirectory(module);
852 m_seenQmldirFiles.insert(module, import);
853 m_seenImports.insert(importId, module);
854 importDependencies(import, cacheTypes.get(), prefix, version, isDependency);
855 processImport(cacheKey, import, cacheTypes.get());
858 modulePaths.append(module);
859 }
else if (module ==
"QML"_L1) {
863 modulePaths = {
":/qt-project.org/imports/QML"_L1 };
865 modulePaths = qQmlResolveImportPaths(module, m_importPaths, version);
868 for (
auto const &modulePath : std::as_const(modulePaths)) {
869 QString qmldirPath = modulePath + SlashQmldir;
870 if (modulePath.startsWith(u':')) {
871 if (module ==
"QML"_L1) {
873 }
else if (m_mapper) {
874 const QString resourcePath = modulePath.mid(
875 1, modulePath.endsWith(u'/') ? modulePath.size() - 2 : -1)
877 const auto entry = m_mapper->entry(
878 QQmlJSResourceFileMapper::resourceFileFilter(resourcePath));
879 qmldirPath = entry.filePath;
882 qWarning() <<
"Cannot read files from resource directory" << modulePath
883 <<
"because no resource file mapper was provided";
887 const auto it = m_seenQmldirFiles.constFind(qmldirPath);
888 if (it != m_seenQmldirFiles.constEnd()) {
889 const QQmlJSImporter::Import import = *it;
890 m_seenImports.insert(importId, qmldirPath);
891 importDependencies(import, cacheTypes.get(), prefix, version, isDependency);
892 processImport(cacheKey, import, cacheTypes.get());
894 const bool typesFromCache = getTypesFromCache();
895 Q_ASSERT(typesFromCache);
896 return typesFromCache;
899 const QFileInfo file(qmldirPath);
901 const auto import = readQmldir(file.canonicalPath());
902 setQualifiedNamesOn(import);
903 m_seenQmldirFiles.insert(qmldirPath, import);
904 m_seenImports.insert(importId, qmldirPath);
905 importDependencies(import, cacheTypes.get(), prefix, version, isDependency);
908 processImport(cacheKey, import, cacheTypes.get());
910 const bool typesFromCache = getTypesFromCache();
911 Q_ASSERT(typesFromCache);
912 return typesFromCache;
918 const bool typesFromCache = getTypesFromCache();
919 Q_ASSERT(typesFromCache);
920 return typesFromCache;
923 m_seenImports.insert(importId, QString());
927QQmlJSScope::Ptr QQmlJSImporter::localFile2QQmlJSScope(
const QString &filePath)
929 const QString sourceFolderFile = preferQmlFilesFromSourceFolder()
930 ? QQmlJSUtils::qmlSourcePathFromBuildPath(m_mapper, filePath)
933 const auto seen = m_importedFiles.find(sourceFolderFile);
934 if (seen != m_importedFiles.end())
937 return *m_importedFiles.insert(
939 { QQmlJSScope::create(),
940 QSharedPointer<QDeferredFactory<QQmlJSScope>>(
new QDeferredFactory<QQmlJSScope>(
941 this, sourceFolderFile)) });
945
946
947
948
949
950
951
952bool QQmlJSImporter::registerScope(
const QQmlJSScope::Ptr &scope)
954 Q_ASSERT(!scope.factory());
956 QQmlJSScope::Ptr &existing = m_importedFiles[scope->filePath()];
958 return existing == scope;
963QQmlJSScope::Ptr QQmlJSImporter::importFile(
const QString &file)
965 return localFile2QQmlJSScope(file);
968QQmlJSImporter::ImportedTypes QQmlJSImporter::importDirectory(
969 const QString &directory,
const QString &prefix)
971 const AvailableTypes builtins = builtinImportHelper();
972 QQmlJSImporter::AvailableTypes types(QQmlJS::ContextualTypes(
973 QQmlJS::ContextualTypes::INTERNAL, {}, {}, builtins.cppNames.arrayType()));
974 importHelper(directory, &types, prefix, QTypeRevision(),
false,
true);
975 return ImportedTypes(std::move(types.qmlNames), std::move(types.warnings));
978void QQmlJSImporter::setImportPaths(
const QStringList &importPaths)
980 m_importPaths = importPaths;
984 m_seenImports.clear();
985 m_cachedImportTypes.clear();
989void QQmlJSImporter::clearCache()
991 m_seenImports.clear();
992 m_cachedImportTypes.clear();
993 m_seenQmldirFiles.clear();
994 m_importedFiles.clear();
998QQmlJSScope::ConstPtr QQmlJSImporter::jsGlobalObject()
1000 return builtinImportHelper().cppNames.type(u"GlobalObject"_s).scope;
1003void QQmlJSImporter::setQualifiedNamesOn(
const Import &import)
1005 for (
auto &object : import.objects) {
1006 if (object.exports.isEmpty())
1008 if (
auto *factory = object.scope.factory()) {
1009 factory->setModuleName(import.name);
1011 object.scope->setOwnModuleName(import.name);
1016void QQmlJSImporter::runImportVisitor(QQmlJS::AST::Node *rootNode,
1017 const ImportVisitorPrerequisites &p)
1019 m_importVisitor(rootNode,
this, p);
Import(QString prefix, QString name, QTypeRevision version, bool isFile, bool isDependency)
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 bool fileSelectedScopesAreCompatibleHeuristic(const QQmlJSScope::ConstPtr &scope1, const QQmlJSScope::ConstPtr &scope2)
static const QLatin1String PluginsDotQmltypes