diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/qmlcompiler/qqmljsimporter.cpp | 138 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsimporter_p.h | 91 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor.cpp | 167 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor_p.h | 10 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljslinter.cpp | 2 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsscope.cpp | 6 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljstyperesolver.cpp | 2 |
7 files changed, 246 insertions, 170 deletions
diff --git a/src/qmlcompiler/qqmljsimporter.cpp b/src/qmlcompiler/qqmljsimporter.cpp index b590cc07b7..b37f274622 100644 --- a/src/qmlcompiler/qqmljsimporter.cpp +++ b/src/qmlcompiler/qqmljsimporter.cpp @@ -42,16 +42,16 @@ static const QString prefixedName(const QString &prefix, const QString &name) return prefix.isEmpty() ? name : (prefix + QLatin1Char('.') + name); } -QQmlDirParser QQmlJSImporter::createQmldirParserForFile(const QString &filename) +QQmlDirParser QQmlJSImporter::createQmldirParserForFile(const QString &filename, Import *import) { + Q_ASSERT(import); QFile f(filename); QQmlDirParser parser; if (f.open(QFile::ReadOnly)) { parser.parse(QString::fromUtf8(f.readAll())); } else { - m_warnings.append({ - QStringLiteral("Could not open qmldir file: ") - + filename, + import->warnings.append({ + QStringLiteral("Could not open qmldir file: ") + filename, QtWarningMsg, QQmlJS::SourceLocation() }); @@ -60,13 +60,11 @@ QQmlDirParser QQmlJSImporter::createQmldirParserForFile(const QString &filename) return parser; } -void QQmlJSImporter::readQmltypes( - const QString &filename, QList<QQmlJSExportedScope> *objects, - QList<QQmlDirParser::Import> *dependencies) +void QQmlJSImporter::readQmltypes(const QString &filename, Import *result) { const QFileInfo fileInfo(filename); if (!fileInfo.exists()) { - m_warnings.append({ + result->warnings.append({ QStringLiteral("QML types file does not exist: ") + filename, QtWarningMsg, QQmlJS::SourceLocation() @@ -75,7 +73,7 @@ void QQmlJSImporter::readQmltypes( } if (fileInfo.isDir()) { - m_warnings.append({ + result->warnings.append({ QStringLiteral("QML types file cannot be a directory: ") + filename, QtWarningMsg, QQmlJS::SourceLocation() @@ -85,7 +83,7 @@ void QQmlJSImporter::readQmltypes( QFile file(filename); if (!file.open(QFile::ReadOnly)) { - m_warnings.append({ + result->warnings.append({ QStringLiteral("QML types file cannot be opened: ") + filename, QtWarningMsg, QQmlJS::SourceLocation() @@ -95,18 +93,18 @@ void QQmlJSImporter::readQmltypes( QQmlJSTypeDescriptionReader reader { filename, QString::fromUtf8(file.readAll()) }; QStringList dependencyStrings; - auto succ = reader(objects, &dependencyStrings); + auto succ = reader(&result->objects, &dependencyStrings); if (!succ) - m_warnings.append({ reader.errorMessage(), QtCriticalMsg, QQmlJS::SourceLocation() }); + result->warnings.append({ reader.errorMessage(), QtCriticalMsg, QQmlJS::SourceLocation() }); const QString warningMessage = reader.warningMessage(); if (!warningMessage.isEmpty()) - m_warnings.append({ warningMessage, QtWarningMsg, QQmlJS::SourceLocation() }); + result->warnings.append({ warningMessage, QtWarningMsg, QQmlJS::SourceLocation() }); if (dependencyStrings.isEmpty()) return; - m_warnings.append({ + result->warnings.append({ QStringLiteral("Found deprecated dependency specifications in %1." "Specify dependencies in qmldir and use qmltyperegistrar " "to generate qmltypes files without dependencies.") @@ -118,15 +116,16 @@ void QQmlJSImporter::readQmltypes( for (const QString &dependency : std::as_const(dependencyStrings)) { const auto blank = dependency.indexOf(u' '); if (blank < 0) { - dependencies->append(QQmlDirParser::Import(dependency, {}, - QQmlDirParser::Import::Default)); + result->dependencies.append( + QQmlDirParser::Import(dependency, {}, QQmlDirParser::Import::Default)); continue; } const QString module = dependency.left(blank); const QString versionString = dependency.mid(blank + 1).trimmed(); if (versionString == QStringLiteral("auto")) { - dependencies->append(QQmlDirParser::Import(module, {}, QQmlDirParser::Import::Auto)); + result->dependencies.append( + QQmlDirParser::Import(module, {}, QQmlDirParser::Import::Auto)); continue; } @@ -137,8 +136,8 @@ void QQmlJSImporter::readQmltypes( : QTypeRevision::fromVersion(versionString.left(dot).toUShort(), versionString.mid(dot + 1).toUShort()); - dependencies->append(QQmlDirParser::Import(module, version, - QQmlDirParser::Import::Default)); + result->dependencies.append( + QQmlDirParser::Import(module, version, QQmlDirParser::Import::Default)); } } @@ -215,19 +214,19 @@ static QString resolvePreferredPath( QQmlJSImporter::Import QQmlJSImporter::readQmldir(const QString &modulePath) { + Import result; const QString moduleQmldirPath = modulePath + SlashQmldir; - auto reader = createQmldirParserForFile(moduleQmldirPath); + auto reader = createQmldirParserForFile(moduleQmldirPath, &result); const QString resolvedQmldirPath = resolvePreferredPath(moduleQmldirPath, reader.preferredPath(), m_mapper); if (resolvedQmldirPath != moduleQmldirPath) - reader = createQmldirParserForFile(resolvedQmldirPath); + reader = createQmldirParserForFile(resolvedQmldirPath, &result); // Leave the trailing slash Q_ASSERT(resolvedQmldirPath.endsWith(SlashQmldir)); QStringView resolvedPath = QStringView(resolvedQmldirPath).chopped(SlashQmldir.size() - 1); - Import result; result.name = reader.typeNamespace(); result.isStaticModule = reader.isStaticModule(); @@ -240,19 +239,19 @@ QQmlJSImporter::Import QQmlJSImporter::readQmldir(const QString &modulePath) const QString typeInfoPath = QFileInfo(typeInfo).isRelative() ? resolvedPath + typeInfo : typeInfo; - readQmltypes(typeInfoPath, &result.objects, &result.dependencies); + readQmltypes(typeInfoPath, &result); } if (typeInfos.isEmpty() && !reader.plugins().isEmpty()) { const QString defaultTypeInfoPath = resolvedPath + PluginsDotQmltypes; if (QFile::exists(defaultTypeInfoPath)) { - m_warnings.append({ + result.warnings.append({ QStringLiteral("typeinfo not declared in qmldir file: ") + defaultTypeInfoPath, QtWarningMsg, QQmlJS::SourceLocation() }); - readQmltypes(defaultTypeInfoPath, &result.objects, &result.dependencies); + readQmltypes(defaultTypeInfoPath, &result); } } @@ -261,7 +260,7 @@ QQmlJSImporter::Import QQmlJSImporter::readQmldir(const QString &modulePath) for (auto it = components.begin(), end = components.end(); it != end; ++it) { const QString filePath = resolvedPath + it->fileName; if (!QFile::exists(filePath)) { - m_warnings.append({ + result.warnings.append({ it->fileName + QStringLiteral(" is listed as component in ") + resolvedQmldirPath + QStringLiteral(" but does not exist.\n"), @@ -354,10 +353,9 @@ QQmlJSImporter::Import QQmlJSImporter::readDirectory(const QString &directory) return import; } -void QQmlJSImporter::importDependencies(const QQmlJSImporter::Import &import, - QQmlJSImporter::AvailableTypes *types, - const QString &prefix, QTypeRevision version, - bool isDependency) +void QQmlJSImporter::importDependencies( + const QQmlJSImporter::Import &import, QQmlJSImporter::AvailableTypes *types, + const QString &prefix, QTypeRevision version, bool isDependency) { // Import the dependencies with an invalid prefix. The prefix will never be matched by actual // QML code but the C++ types will be visible. @@ -382,10 +380,11 @@ void QQmlJSImporter::importDependencies(const QQmlJSImporter::Import &import, } if (hasOptionalImports && !useOptionalImports()) { - m_warnings.append( - { u"%1 uses optional imports which are not supported. Some types might not be found."_s - .arg(import.name), - QtCriticalMsg, QQmlJS::SourceLocation() }); + types->warnings.append({ + u"%1 uses optional imports which are not supported. Some types might not be found."_s + .arg(import.name), + QtCriticalMsg, QQmlJS::SourceLocation() + }); } } @@ -402,9 +401,9 @@ static bool isVersionAllowed(const QQmlJSScope::Export &exportEntry, || exportVersion.minorVersion() <= importVersion.minorVersion(); } -void QQmlJSImporter::processImport(const QQmlJS::Import &importDescription, - const QQmlJSImporter::Import &import, - QQmlJSImporter::AvailableTypes *types) +void QQmlJSImporter::processImport( + const QQmlJS::Import &importDescription, const QQmlJSImporter::Import &import, + QQmlJSImporter::AvailableTypes *types) { // In the list of QML types we prefix unresolvable QML names with $anonymous$, and C++ // names with $internal$. This is to avoid clashes between them. @@ -465,7 +464,7 @@ void QQmlJSImporter::processImport(const QQmlJS::Import &importDescription, case LowerVersion: break; case SameVersion: { - m_warnings.append({ + types->warnings.append({ QStringLiteral("Ambiguous type detected. " "%1 %2.%3 is defined multiple times.") .arg(qmlName) @@ -505,16 +504,17 @@ void QQmlJSImporter::processImport(const QQmlJS::Import &importDescription, if (!importDescription.prefix().isEmpty()) types->qmlNames.setType(importDescription.prefix(), {}); - // Add a marker to show that this module has been imported - if (!importDescription.isDependency()) + if (!importDescription.isDependency()) { + // Add a marker to show that this module has been imported types->qmlNames.setType(prefixedName(modulePrefix, importDescription.name()), {}); - if (!importDescription.isDependency()) { if (import.isStaticModule) types->staticModules << import.name; if (import.isSystemModule) types->hasSystemModule = true; + + types->warnings.append(import.warnings); } for (auto it = import.scripts.begin(); it != import.scripts.end(); ++it) { @@ -585,7 +585,7 @@ void QQmlJSImporter::processImport(const QQmlJS::Import &importDescription, // ... except that old qmltypes files might specify composite types with C++ names. // Warn about those. if (val.scope->isComposite()) { - m_warnings.append({ + types->warnings.append({ QStringLiteral("Found incomplete composite type %1. Do not use qmlplugindump.") .arg(val.scope->internalName()), QtWarningMsg, @@ -603,7 +603,8 @@ void QQmlJSImporter::processImport(const QQmlJS::Import &importDescription, */ QQmlJSImporter::ImportedTypes QQmlJSImporter::importBuiltins() { - return builtinImportHelper().qmlNames; + auto builtins = builtinImportHelper(); + return ImportedTypes(std::move(builtins.qmlNames), std::move(builtins.warnings)); } @@ -612,7 +613,7 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper() if (m_builtins) return *m_builtins; - AvailableTypes builtins(ImportedTypes(ImportedTypes::INTERNAL, {}, {})); + AvailableTypes builtins(QQmlJS::ContextualTypes(QQmlJS::ContextualTypes::INTERNAL, {}, {})); Import result; result.name = QStringLiteral("QML"); @@ -623,8 +624,7 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper() if (!importDir.exists(qmltypesFile)) continue; - readQmltypes( - importDir.filePath(qmltypesFile), &result.objects, &result.dependencies); + readQmltypes(importDir.filePath(qmltypesFile), &result); setQualifiedNamesOn(result); importDependencies(result, &builtins); return true; @@ -666,10 +666,10 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper() Q_ASSERT(intType); Q_ASSERT(arrayType); - m_builtins = AvailableTypes( - ImportedTypes(ImportedTypes::INTERNAL, builtins.cppNames.types(), arrayType)); - m_builtins->qmlNames - = ImportedTypes(ImportedTypes::QML, builtins.qmlNames.types(), arrayType); + m_builtins = AvailableTypes(QQmlJS::ContextualTypes( + QQmlJS::ContextualTypes::INTERNAL, builtins.cppNames.types(), arrayType)); + m_builtins->qmlNames = QQmlJS::ContextualTypes( + QQmlJS::ContextualTypes::QML, builtins.qmlNames.types(), arrayType); processImport(builtinImport, result, &(*m_builtins)); @@ -679,8 +679,9 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper() /*! * Imports types from the specified \a qmltypesFiles. */ -void QQmlJSImporter::importQmldirs(const QStringList &qmldirFiles) +QList<QQmlJS::DiagnosticMessage> QQmlJSImporter::importQmldirs(const QStringList &qmldirFiles) { + QList<QQmlJS::DiagnosticMessage> warnings; for (const auto &file : qmldirFiles) { Import result; QString qmldirName; @@ -689,14 +690,14 @@ void QQmlJSImporter::importQmldirs(const QStringList &qmldirFiles) setQualifiedNamesOn(result); qmldirName = file; } else { - m_warnings.append({ + warnings.append({ QStringLiteral("Argument %1 to -i option is not a qmldir file. Assuming qmltypes.") .arg(file), QtWarningMsg, QQmlJS::SourceLocation() }); - readQmltypes(file, &result.objects, &result.dependencies); + readQmltypes(file, &result); // Append _FAKE_QMLDIR to our made up qmldir name so that if it ever gets used somewhere // else except for cache lookups, it will blow up due to a missing file instead of @@ -704,6 +705,7 @@ void QQmlJSImporter::importQmldirs(const QStringList &qmldirFiles) qmldirName = file + QStringLiteral("_FAKE_QMLDIR"); } + warnings.append(result.warnings); m_seenQmldirFiles.insert(qmldirName, result); for (const auto &object : std::as_const(result.objects)) { @@ -714,6 +716,8 @@ void QQmlJSImporter::importQmldirs(const QStringList &qmldirFiles) } } } + + return warnings; } QQmlJSImporter::ImportedTypes QQmlJSImporter::importModule(const QString &module, @@ -724,11 +728,12 @@ QQmlJSImporter::ImportedTypes QQmlJSImporter::importModule(const QString &module const AvailableTypes builtins = builtinImportHelper(); AvailableTypes result(builtins.cppNames); if (!importHelper(module, &result, prefix, version)) { - m_warnings.append({ - QStringLiteral("Failed to import %1. Are your import paths set up properly?").arg(module), - QtWarningMsg, - QQmlJS::SourceLocation() - }); + result.warnings.append({ + QStringLiteral("Failed to import %1. Are your import paths set up properly?") + .arg(module), + QtWarningMsg, + QQmlJS::SourceLocation() + }); } // If we imported a system module add all builtin QML types @@ -742,12 +747,13 @@ QQmlJSImporter::ImportedTypes QQmlJSImporter::importModule(const QString &module if (staticModuleList) *staticModuleList << result.staticModules; - return result.qmlNames; + return ImportedTypes(std::move(result.qmlNames), std::move(result.warnings)); } QQmlJSImporter::ImportedTypes QQmlJSImporter::builtinInternalNames() { - return builtinImportHelper().cppNames; + auto builtins = builtinImportHelper(); + return ImportedTypes(std::move(builtins.cppNames), std::move(builtins.warnings)); } bool QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types, @@ -771,6 +777,7 @@ bool QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types, types->cppNames.addTypes(cacheEntry->cppNames); types->staticModules << cacheEntry->staticModules; types->hasSystemModule |= cacheEntry->hasSystemModule; + types->warnings.append(cacheEntry->warnings); // No need to import qml names for dependencies if (!isDependency) @@ -788,8 +795,8 @@ bool QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types, return true; auto cacheTypes = QSharedPointer<QQmlJSImporter::AvailableTypes>( - new QQmlJSImporter::AvailableTypes( - ImportedTypes(ImportedTypes::INTERNAL, {}, types->cppNames.arrayType()))); + new QQmlJSImporter::AvailableTypes(QQmlJS::ContextualTypes( + QQmlJS::ContextualTypes::INTERNAL, {}, types->cppNames.arrayType()))); m_cachedImportTypes[cacheKey] = cacheTypes; const QPair<QString, QTypeRevision> importId { module, version }; @@ -908,11 +915,10 @@ QQmlJSImporter::ImportedTypes QQmlJSImporter::importDirectory( const QString &directory, const QString &prefix) { const AvailableTypes builtins = builtinImportHelper(); - QQmlJSImporter::AvailableTypes types( - ImportedTypes( - ImportedTypes::INTERNAL, {}, builtins.cppNames.arrayType())); + QQmlJSImporter::AvailableTypes types(QQmlJS::ContextualTypes( + QQmlJS::ContextualTypes::INTERNAL, {}, builtins.cppNames.arrayType())); importHelper(directory, &types, prefix, QTypeRevision(), false, true); - return types.qmlNames; + return ImportedTypes(std::move(types.qmlNames), std::move(types.warnings)); } void QQmlJSImporter::setImportPaths(const QStringList &importPaths) diff --git a/src/qmlcompiler/qqmljsimporter_p.h b/src/qmlcompiler/qqmljsimporter_p.h index 558c1799a2..033d479711 100644 --- a/src/qmlcompiler/qqmljsimporter_p.h +++ b/src/qmlcompiler/qqmljsimporter_p.h @@ -73,7 +73,59 @@ class QQmlJSLogger; class Q_QMLCOMPILER_EXPORT QQmlJSImporter { public: - using ImportedTypes = QQmlJS::ContextualTypes; + struct ImportedTypes { + ImportedTypes(QQmlJS::ContextualTypes &&types, QList<QQmlJS::DiagnosticMessage> &&warnings) + : m_types(std::move(types)), m_warnings(std::move(warnings)) + {} + + ImportedTypes(const ImportedTypes &) = default; + ImportedTypes(ImportedTypes &&) = default; + ImportedTypes &operator=(const ImportedTypes &) = default; + ImportedTypes &operator=(ImportedTypes &&) = default; + ~ImportedTypes() = default; + + void clear() + { + m_types.clearTypes(); + m_warnings.clear(); + } + + const QQmlJS::ContextualTypes &contextualTypes() const { return m_types; } + const QList<QQmlJS::DiagnosticMessage> &warnings() const { return m_warnings; }; + + bool isEmpty() const { return m_types.types().isEmpty(); } + + bool hasType(const QString &name) const { return m_types.hasType(name); } + QQmlJS::ImportedScope<QQmlJSScope::ConstPtr> type(const QString &name) const + { + return m_types.type(name); + } + QString name(const QQmlJSScope::ConstPtr &type) const { return m_types.name(type); } + void setType(const QString &name, const QQmlJS::ImportedScope<QQmlJSScope::ConstPtr> &type) + { + m_types.setType(name, type); + } + bool isNullType(const QString &name) const { return m_types.isNullType(name); } + const QHash<QString, QQmlJS::ImportedScope<QQmlJSScope::ConstPtr>> &types() const + { + return m_types.types(); + } + + void add(ImportedTypes &&other) + { + m_types.addTypes(std::move(other.m_types)); + m_warnings.append(std::move(other.m_warnings)); + } + + void addWarnings(QList<QQmlJS::DiagnosticMessage> &&warnings) + { + m_warnings.append(std::move(warnings)); + } + + private: + QQmlJS::ContextualTypes m_types; + QList<QQmlJS::DiagnosticMessage> m_warnings; + }; QQmlJSImporter(const QStringList &importPaths, QQmlJSResourceFileMapper *mapper, QQmlJSImporterFlags flags = QQmlJSImporterFlags{}); @@ -85,7 +137,7 @@ public: void setMetaDataMapper(QQmlJSResourceFileMapper *mapper) { m_metaDataMapper = mapper; } ImportedTypes importBuiltins(); - void importQmldirs(const QStringList &qmltypesFiles); + QList<QQmlJS::DiagnosticMessage> importQmldirs(const QStringList &qmltypesFiles); QQmlJSScope::Ptr importFile(const QString &file); ImportedTypes importDirectory(const QString &directory, const QString &prefix = QString()); @@ -99,13 +151,6 @@ public: ImportedTypes builtinInternalNames(); - QList<QQmlJS::DiagnosticMessage> takeWarnings() - { - const auto result = std::move(m_warnings); - m_warnings.clear(); - return result; - } - QList<QQmlJS::DiagnosticMessage> takeGlobalWarnings() { const auto result = std::move(m_globalWarnings); @@ -158,21 +203,24 @@ private: struct AvailableTypes { - AvailableTypes(ImportedTypes builtins) + AvailableTypes(QQmlJS::ContextualTypes builtins) : cppNames(std::move(builtins)) , qmlNames(QQmlJS::ContextualTypes::QML, {}, cppNames.arrayType()) { } // C++ names used in qmltypes files for non-composite types - ImportedTypes cppNames; + QQmlJS::ContextualTypes cppNames; // Names the importing component sees, including any prefixes - ImportedTypes qmlNames; + QQmlJS::ContextualTypes qmlNames; // Static modules included here QStringList staticModules; + // Warnings produced when importing + QList<QQmlJS::DiagnosticMessage> warnings; + // Whether a system module has been imported bool hasSystemModule = false; }; @@ -186,20 +234,22 @@ private: QHash<QString, QQmlJSExportedScope> scripts; QList<QQmlDirParser::Import> imports; QList<QQmlDirParser::Import> dependencies; + + // Warnings produced when importing + QList<QQmlJS::DiagnosticMessage> warnings; }; AvailableTypes builtinImportHelper(); bool importHelper(const QString &module, AvailableTypes *types, const QString &prefix = QString(), QTypeRevision version = QTypeRevision(), bool isDependency = false, bool isFile = false); - void processImport(const QQmlJS::Import &importDescription, const Import &import, - AvailableTypes *types); - void importDependencies(const QQmlJSImporter::Import &import, AvailableTypes *types, - const QString &prefix = QString(), - QTypeRevision version = QTypeRevision(), bool isDependency = false); - QQmlDirParser createQmldirParserForFile(const QString &filename); - void readQmltypes(const QString &filename, QList<QQmlJSExportedScope> *objects, - QList<QQmlDirParser::Import> *dependencies); + void processImport( + const QQmlJS::Import &importDescription, const Import &import, AvailableTypes *types); + void importDependencies( + const Import &import, AvailableTypes *types, const QString &prefix = QString(), + QTypeRevision version = QTypeRevision(), bool isDependency = false); + QQmlDirParser createQmldirParserForFile(const QString &filename, Import *import); + void readQmltypes(const QString &filename, Import *result); Import readQmldir(const QString &dirname); Import readDirectory(const QString &directory); @@ -214,7 +264,6 @@ private: QHash<QString, QQmlJSScope::Ptr> m_importedFiles; QList<QQmlJS::DiagnosticMessage> m_globalWarnings; - QList<QQmlJS::DiagnosticMessage> m_warnings; std::optional<AvailableTypes> m_builtins; QQmlJSResourceFileMapper *m_mapper = nullptr; diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp index edc65fc6fe..cb5abd5d7e 100644 --- a/src/qmlcompiler/qqmljsimportvisitor.cpp +++ b/src/qmlcompiler/qqmljsimportvisitor.cpp @@ -131,8 +131,10 @@ QQmlJSImportVisitor::QQmlJSImportVisitor( m_importer(importer), m_logger(logger), m_rootScopeImports( - QQmlJSImporter::ImportedTypes::QML, {}, - importer->builtinInternalNames().arrayType()) + QQmlJS::ContextualTypes( + QQmlJS::ContextualTypes::QML, {}, + importer->builtinInternalNames().contextualTypes().arrayType()), + {}) { m_currentScope->setScopeType(QQmlSA::ScopeType::JSFunctionScope); Q_ASSERT(logger); // must be valid @@ -340,7 +342,8 @@ void QQmlJSImportVisitor::resolveAliasesAndIds() const QQmlJSScope::ConstPtr deferred = m_scopesById.scope(name, childScope); if (!deferred.isNull()) { QQmlJSScope::resolveGeneralizedGroup( - childScope, deferred, m_rootScopeImports, &m_usedTypes); + childScope, deferred, m_rootScopeImports.contextualTypes(), + &m_usedTypes); } } } @@ -387,9 +390,9 @@ QString QQmlJSImportVisitor::implicitImportDirectory( } void QQmlJSImportVisitor::processImportWarnings( - const QString &what, const QQmlJS::SourceLocation &srcLocation) + const QString &what, const QList<QQmlJS::DiagnosticMessage> &warnings, + const QQmlJS::SourceLocation &srcLocation) { - const auto warnings = m_importer->takeWarnings(); if (warnings.isEmpty()) return; @@ -400,24 +403,21 @@ void QQmlJSImportVisitor::processImportWarnings( void QQmlJSImportVisitor::importBaseModules() { - Q_ASSERT(m_rootScopeImports.types().isEmpty()); + Q_ASSERT(m_rootScopeImports.isEmpty()); m_rootScopeImports = m_importer->importBuiltins(); const QQmlJS::SourceLocation invalidLoc; - for (auto it = m_rootScopeImports.types().keyBegin(), end = m_rootScopeImports.types().keyEnd(); - it != end; it++) { + const auto types = m_rootScopeImports.types(); + for (auto it = types.keyBegin(), end = types.keyEnd(); it != end; it++) addImportWithLocation(*it, invalidLoc); - } if (!m_qmldirFiles.isEmpty()) - m_importer->importQmldirs(m_qmldirFiles); + m_rootScopeImports.addWarnings(m_importer->importQmldirs(m_qmldirFiles)); // Pulling in the modules and neighboring qml files of the qmltypes we're trying to lint is not // something we need to do. if (!m_logger->fileName().endsWith(u".qmltypes"_s)) { - QQmlJS::ContextualTypes fromDirectory = - m_importer->importDirectory(m_implicitImportDirectory); - m_rootScopeImports.addTypes(std::move(fromDirectory)); + m_rootScopeImports.add(m_importer->importDirectory(m_implicitImportDirectory)); // Import all possible resource directories the file may belong to. // This is somewhat fuzzy, but if you're mapping the same file to multiple resource @@ -429,12 +429,12 @@ void QQmlJSImportVisitor::importBaseModules() const qsizetype lastSlash = path.lastIndexOf(QLatin1Char('/')); if (lastSlash == -1) continue; - m_rootScopeImports.addTypes(m_importer->importDirectory(path.first(lastSlash))); + m_rootScopeImports.add(m_importer->importDirectory(path.first(lastSlash))); } } } - processImportWarnings(QStringLiteral("base modules")); + processImportWarnings(QStringLiteral("base modules"), m_rootScopeImports.warnings()); } bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiProgram *) @@ -659,8 +659,8 @@ void QQmlJSImportVisitor::processPropertyTypes() auto property = type.scope->ownProperty(type.name); - if (const auto propertyType = - QQmlJSScope::findType(property.typeName(), m_rootScopeImports).scope) { + if (const auto propertyType = QQmlJSScope::findType( + property.typeName(), m_rootScopeImports.contextualTypes()).scope) { property.setType(propertyType); type.scope->addOwnProperty(property); } else { @@ -676,8 +676,8 @@ void QQmlJSImportVisitor::processMethodTypes() for (auto [it, end] = method.scope->mutableOwnMethodsRange(method.methodName); it != end; ++it) { const auto [parameterBegin, parameterEnd] = it->mutableParametersRange(); for (auto parameter = parameterBegin; parameter != parameterEnd; ++parameter) { - if (const auto parameterType = - QQmlJSScope::findType(parameter->typeName(), m_rootScopeImports) .scope) { + if (const auto parameterType = QQmlJSScope::findType( + parameter->typeName(), m_rootScopeImports.contextualTypes()).scope) { parameter->setType({ parameterType }); } else { m_logger->log( @@ -687,8 +687,8 @@ void QQmlJSImportVisitor::processMethodTypes() } } - if (const auto returnType = - QQmlJSScope::findType(it->returnTypeName(), m_rootScopeImports).scope) { + if (const auto returnType = QQmlJSScope::findType( + it->returnTypeName(), m_rootScopeImports.contextualTypes()).scope) { it->setReturnType({ returnType }); } else { m_logger->log(u"\"%1\" was not found for the return type of method \"%2\"."_s.arg( @@ -1488,7 +1488,7 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition) } const QTypeRevision revision = QQmlJSScope::resolveTypes( - m_currentScope, m_rootScopeImports, &m_usedTypes); + m_currentScope, m_rootScopeImports.contextualTypes(), &m_usedTypes); if (auto base = m_currentScope->baseType(); base) { if (isRoot && base->internalName() == u"QQmlComponent") { m_logger->log(u"Qml top level type cannot be 'Component'."_s, qmlTopLevelComponent, @@ -1527,7 +1527,8 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition) definition->firstSourceLocation()); m_bindings.append(createNonUniqueScopeBinding(m_currentScope, superType, definition->firstSourceLocation())); - QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes); + QQmlJSScope::resolveTypes( + m_currentScope, m_rootScopeImports.contextualTypes(), &m_usedTypes); } m_currentScope->setAnnotations(parseAnnotations(definition->annotations)); @@ -1537,7 +1538,7 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition) void QQmlJSImportVisitor::endVisit(UiObjectDefinition *) { - QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes); + QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports.contextualTypes(), &m_usedTypes); leaveEnvironment(); } @@ -2271,14 +2272,14 @@ void QQmlJSImportVisitor::addImportWithLocation(const QString &name, m_importLocations.insert(loc); } -void QQmlJSImportVisitor::importFromHost(const QString &path, const QString &prefix, - const QQmlJS::SourceLocation &location) +QList<QQmlJS::DiagnosticMessage> QQmlJSImportVisitor::importFromHost( + const QString &path, const QString &prefix, const QQmlJS::SourceLocation &location) { QFileInfo fileInfo(path); if (!fileInfo.exists()) { m_logger->log("File or directory you are trying to import does not exist: %1."_L1.arg(path), qmlImport, location); - return; + return {}; } if (fileInfo.isFile()) { @@ -2286,40 +2287,53 @@ void QQmlJSImportVisitor::importFromHost(const QString &path, const QString &pre const QString actualPrefix = prefix.isEmpty() ? scope->internalName() : prefix; m_rootScopeImports.setType(actualPrefix, { scope, QTypeRevision() }); addImportWithLocation(actualPrefix, location); - } else if (fileInfo.isDir()) { - const auto scopes = m_importer->importDirectory(path, prefix); - m_rootScopeImports.addTypes(scopes); - for (auto it = scopes.types().keyBegin(), end = scopes.types().keyEnd(); it != end; it++) + return {}; + } + + if (fileInfo.isDir()) { + auto scopes = m_importer->importDirectory(path, prefix); + const auto types = scopes.types(); + const auto warnings = scopes.warnings(); + m_rootScopeImports.add(std::move(scopes)); + for (auto it = types.keyBegin(), end = types.keyEnd(); it != end; it++) addImportWithLocation(*it, location); - } else { - m_logger->log( - "%1 is neither a file nor a directory. Are sure the import path is correct?"_L1.arg( - path), - qmlImport, location); + return warnings; } + + m_logger->log( + "%1 is neither a file nor a directory. Are sure the import path is correct?"_L1.arg( + path), + qmlImport, location); + return {}; } -void QQmlJSImportVisitor::importFromQrc(const QString &path, const QString &prefix, - const QQmlJS::SourceLocation &location) +QList<QQmlJS::DiagnosticMessage> QQmlJSImportVisitor::importFromQrc( + const QString &path, const QString &prefix, const QQmlJS::SourceLocation &location) { Q_ASSERT(path.startsWith(u':')); - if (const QQmlJSResourceFileMapper *mapper = m_importer->resourceFileMapper()) { - const auto pathNoColon = QStringView(path).mid(1); - if (mapper->isFile(pathNoColon)) { - const auto entry = m_importer->resourceFileMapper()->entry( - QQmlJSResourceFileMapper::resourceFileFilter(pathNoColon.toString())); - const auto scope = m_importer->importFile(entry.filePath); - const QString actualPrefix = - prefix.isEmpty() ? QFileInfo(entry.resourcePath).baseName() : prefix; - m_rootScopeImports.setType(actualPrefix, { scope, QTypeRevision() }); - addImportWithLocation(actualPrefix, location); - } else { - const auto scopes = m_importer->importDirectory(path, prefix); - m_rootScopeImports.addTypes(scopes); - for (auto it = scopes.types().keyBegin(), end = scopes.types().keyEnd(); it != end; it++) - addImportWithLocation(*it, location); - } + const QQmlJSResourceFileMapper *mapper = m_importer->resourceFileMapper(); + if (!mapper) + return {}; + + const auto pathNoColon = QStringView(path).mid(1); + if (mapper->isFile(pathNoColon)) { + const auto entry = m_importer->resourceFileMapper()->entry( + QQmlJSResourceFileMapper::resourceFileFilter(pathNoColon.toString())); + const auto scope = m_importer->importFile(entry.filePath); + const QString actualPrefix = + prefix.isEmpty() ? QFileInfo(entry.resourcePath).baseName() : prefix; + m_rootScopeImports.setType(actualPrefix, { scope, QTypeRevision() }); + addImportWithLocation(actualPrefix, location); + return {}; } + + auto scopes = m_importer->importDirectory(path, prefix); + const auto types = scopes.types(); + const auto warnings = scopes.warnings(); + m_rootScopeImports.add(std::move(scopes)); + for (auto it = types.keyBegin(), end = types.keyEnd(); it != end; it++) + addImportWithLocation(*it, location); + return warnings; } bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import) @@ -2346,20 +2360,18 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import) QString absolute = fileInfo.isRelative() ? QDir::cleanPath(QDir(m_implicitImportDirectory).filePath(filename)) : filename; - if (absolute.startsWith(u':')) { - importFromQrc(absolute, prefix, importLocation); - } else { - importFromHost(absolute, prefix, importLocation); - } - processImportWarnings("path \"%1\""_L1.arg(url.path()), importLocation); + auto warnings = absolute.startsWith(u':') + ? importFromQrc(absolute, prefix, importLocation) + : importFromHost(absolute, prefix, importLocation); + processImportWarnings("path \"%1\""_L1.arg(url.path()), warnings, importLocation); return true; } else if (scheme == "file"_L1) { - importFromHost(url.path(), prefix, importLocation); - processImportWarnings("URL \"%1\""_L1.arg(url.path()), importLocation); + auto warnings = importFromHost(url.path(), prefix, importLocation); + processImportWarnings("URL \"%1\""_L1.arg(url.path()), warnings, importLocation); return true; } else if (scheme == "qrc"_L1) { - importFromQrc(":"_L1 + url.path(), prefix, importLocation); - processImportWarnings("URL \"%1\""_L1.arg(url.path()), importLocation); + auto warnings = importFromQrc(":"_L1 + url.path(), prefix, importLocation); + processImportWarnings("URL \"%1\""_L1.arg(url.path()), warnings, importLocation); return true; } else { m_logger->log("Unknown import syntax. Imports can be paths, qrc urls or file urls"_L1, @@ -2371,11 +2383,13 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import) QStringList staticModulesProvided; - const auto imported = m_importer->importModule( + auto imported = m_importer->importModule( path, prefix, import->version ? import->version->version : QTypeRevision(), &staticModulesProvided); - m_rootScopeImports.addTypes(imported); - for (auto it = imported.types().keyBegin(), end = imported.types().keyEnd(); it != end; it++) + const auto types = imported.types(); + const auto warnings = imported.warnings(); + m_rootScopeImports.add(std::move(imported)); + for (auto it = types.keyBegin(), end = types.keyEnd(); it != end; it++) addImportWithLocation(*it, import->firstSourceLocation()); if (prefix.isEmpty()) { @@ -2388,7 +2402,8 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import) } } - processImportWarnings(QStringLiteral("module \"%1\"").arg(path), import->firstSourceLocation()); + processImportWarnings( + QStringLiteral("module \"%1\"").arg(path), warnings, import->firstSourceLocation()); return true; } @@ -2650,12 +2665,14 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob) } // recursively resolve types for current scope if new scopes are found - if (needsResolution) - QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes); + if (needsResolution) { + QQmlJSScope::resolveTypes( + m_currentScope, m_rootScopeImports.contextualTypes(), &m_usedTypes); + } enterEnvironment(QQmlSA::ScopeType::QMLScope, typeName, uiob->qualifiedTypeNameId->identifierToken); - QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes); + QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports.contextualTypes(), &m_usedTypes); m_qmlTypes.append(m_currentScope); // new QMLScope is created here, so add it m_objectBindingScopes << m_currentScope; @@ -2664,7 +2681,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob) void QQmlJSImportVisitor::endVisit(QQmlJS::AST::UiObjectBinding *uiob) { - QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes); + QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports.contextualTypes(), &m_usedTypes); // must be mutable, as we might mark it as implicitly wrapped in a component const QQmlJSScope::Ptr childScope = m_currentScope; leaveEnvironment(); @@ -2779,7 +2796,8 @@ bool QQmlJSImportVisitor::visit(ESModule *module) void QQmlJSImportVisitor::endVisit(ESModule *) { - QQmlJSScope::resolveTypes(m_exportedRootScope, m_rootScopeImports, &m_usedTypes); + QQmlJSScope::resolveTypes( + m_exportedRootScope, m_rootScopeImports.contextualTypes(), &m_usedTypes); } bool QQmlJSImportVisitor::visit(Program *) @@ -2795,7 +2813,8 @@ bool QQmlJSImportVisitor::visit(Program *) void QQmlJSImportVisitor::endVisit(Program *) { - QQmlJSScope::resolveTypes(m_exportedRootScope, m_rootScopeImports, &m_usedTypes); + QQmlJSScope::resolveTypes( + m_exportedRootScope, m_rootScopeImports.contextualTypes(), &m_usedTypes); } void QQmlJSImportVisitor::endVisit(QQmlJS::AST::FieldMemberExpression *fieldMember) diff --git a/src/qmlcompiler/qqmljsimportvisitor_p.h b/src/qmlcompiler/qqmljsimportvisitor_p.h index d124951347..015f846638 100644 --- a/src/qmlcompiler/qqmljsimportvisitor_p.h +++ b/src/qmlcompiler/qqmljsimportvisitor_p.h @@ -357,7 +357,7 @@ private: void visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr); void processImportWarnings( - const QString &what, + const QString &what, const QList<QQmlJS::DiagnosticMessage> &warnings, const QQmlJS::SourceLocation &srcLocation = QQmlJS::SourceLocation()); void addImportWithLocation(const QString &name, const QQmlJS::SourceLocation &loc); void populateCurrentScope(QQmlJSScope::ScopeType type, const QString &name, @@ -365,10 +365,10 @@ private: void enterRootScope(QQmlJSScope::ScopeType type, const QString &name, const QQmlJS::SourceLocation &location); - void importFromHost(const QString &path, const QString &prefix, - const QQmlJS::SourceLocation &location); - void importFromQrc(const QString &path, const QString &prefix, - const QQmlJS::SourceLocation &location); + QList<QQmlJS::DiagnosticMessage> importFromHost( + const QString &path, const QString &prefix, const QQmlJS::SourceLocation &location); + QList<QQmlJS::DiagnosticMessage> importFromQrc( + const QString &path, const QString &prefix, const QQmlJS::SourceLocation &location); public: friend class QQmlJS::Dom::QQmlDomAstCreatorWithQQmlJSScope; diff --git a/src/qmlcompiler/qqmljslinter.cpp b/src/qmlcompiler/qqmljslinter.cpp index 2047475317..155ce23008 100644 --- a/src/qmlcompiler/qqmljslinter.cpp +++ b/src/qmlcompiler/qqmljslinter.cpp @@ -674,7 +674,7 @@ QQmlJSLinter::LintResult QQmlJSLinter::lintModule( const QQmlJSImporter::ImportedTypes types = m_importer.importModule(module); QList<QQmlJS::DiagnosticMessage> importWarnings = - m_importer.takeGlobalWarnings() + m_importer.takeWarnings(); + m_importer.takeGlobalWarnings() + types.warnings(); if (!importWarnings.isEmpty()) { m_logger->log(QStringLiteral("Warnings occurred while importing module:"), qmlImport, diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp index d54cbeed7a..ca6ba8bc67 100644 --- a/src/qmlcompiler/qqmljsscope.cpp +++ b/src/qmlcompiler/qqmljsscope.cpp @@ -1165,8 +1165,10 @@ void QDeferredFactory<QQmlJSScope>::populate(const QSharedPointer<QQmlJSScope> & m_importer->m_globalWarnings.append(errors); scope->setInternalName(internalName()); - QQmlJSScope::resolveEnums(scope, m_importer->builtinInternalNames()); - QQmlJSScope::resolveList(scope, m_importer->builtinInternalNames().arrayType()); + QQmlJSScope::resolveEnums( + scope, m_importer->builtinInternalNames().contextualTypes()); + QQmlJSScope::resolveList( + scope, m_importer->builtinInternalNames().contextualTypes().arrayType()); if (m_isSingleton && !scope->isSingleton()) { m_importer->m_globalWarnings.append( diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp index 79b2416bea..c40cd377be 100644 --- a/src/qmlcompiler/qqmljstyperesolver.cpp +++ b/src/qmlcompiler/qqmljstyperesolver.cpp @@ -176,7 +176,7 @@ void QQmlJSTypeResolver::init(QQmlJSImportVisitor *visitor, QQmlJS::AST::Node *p m_objectsById.clear(); m_objectsByLocation.clear(); - m_imports.clearTypes(); + m_imports.clear(); m_signalHandlers.clear(); if (program) |
