aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlcompiler/qqmljsimportvisitor.cpp
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/qmlcompiler/qqmljsimportvisitor.cpp
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/qmlcompiler/qqmljsimportvisitor.cpp')
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp167
1 files changed, 93 insertions, 74 deletions
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)