aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-09-12 11:45:53 +0200
committerUlf Hermann <ulf.hermann@qt.io>2024-09-19 21:25:25 +0200
commitbc125ff647f5fd6d124e7f74581411b74bca0b13 (patch)
tree42a60c1ea81f0244d1c2ac780f1e2ad686fc3581 /src
parente3ed72d7e3fe9867fc49ba37ea4173480076b87d (diff)
QmlCompiler: Refactor handling of warnings in import visitor
We want to replay the warnings when we import the same module again. This happens if we lint multiple files with different imports, some direct and some indirect. Pick-to: 6.8 Fixes: QTBUG-118588 Change-Id: I75da4e62acea675342ce8f86f9609f1786ffbdd0 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qmlcompiler/qqmljsimporter.cpp138
-rw-r--r--src/qmlcompiler/qqmljsimporter_p.h91
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp167
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor_p.h10
-rw-r--r--src/qmlcompiler/qqmljslinter.cpp2
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp6
-rw-r--r--src/qmlcompiler/qqmljstyperesolver.cpp2
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)