aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--tests/auto/qml/qmllint/data/DuplicateType/T.qml2
-rw-r--r--tests/auto/qml/qmllint/data/DuplicateType/U.qml2
-rw-r--r--tests/auto/qml/qmllint/data/DuplicateType/qmldir4
-rw-r--r--tests/auto/qml/qmllint/data/DuplicateTypeUser.qml2
-rw-r--r--tests/auto/qml/qmllint/data/duplicateTypeUserUser.qml2
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp17
-rw-r--r--tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp2
14 files changed, 276 insertions, 171 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)
diff --git a/tests/auto/qml/qmllint/data/DuplicateType/T.qml b/tests/auto/qml/qmllint/data/DuplicateType/T.qml
new file mode 100644
index 0000000000..54531c4bdc
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/DuplicateType/T.qml
@@ -0,0 +1,2 @@
+import QtQml
+QtObject {}
diff --git a/tests/auto/qml/qmllint/data/DuplicateType/U.qml b/tests/auto/qml/qmllint/data/DuplicateType/U.qml
new file mode 100644
index 0000000000..54531c4bdc
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/DuplicateType/U.qml
@@ -0,0 +1,2 @@
+import QtQml
+QtObject {}
diff --git a/tests/auto/qml/qmllint/data/DuplicateType/qmldir b/tests/auto/qml/qmllint/data/DuplicateType/qmldir
new file mode 100644
index 0000000000..fc0912a4b5
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/DuplicateType/qmldir
@@ -0,0 +1,4 @@
+module DuplicateType
+T 1.0 T.qml
+T 1.0 U.qml
+U 1.0 U.qml
diff --git a/tests/auto/qml/qmllint/data/DuplicateTypeUser.qml b/tests/auto/qml/qmllint/data/DuplicateTypeUser.qml
new file mode 100644
index 0000000000..1c1130fb59
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/DuplicateTypeUser.qml
@@ -0,0 +1,2 @@
+import DuplicateType
+U {}
diff --git a/tests/auto/qml/qmllint/data/duplicateTypeUserUser.qml b/tests/auto/qml/qmllint/data/duplicateTypeUserUser.qml
new file mode 100644
index 0000000000..ccaa2968f7
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/duplicateTypeUserUser.qml
@@ -0,0 +1,2 @@
+import QtQml
+DuplicateTypeUser { property QtObject o }
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index 607a3a354a..0343bb957d 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -122,6 +122,8 @@ private Q_SLOTS:
void importRelScript();
#endif
+ void replayImportWarnings();
+
private:
enum DefaultImportOption { NoDefaultImports, UseDefaultImports };
enum ContainOption { StringNotContained, StringContained };
@@ -2473,5 +2475,20 @@ void TestQmllint::importRelScript()
}
#endif
+void TestQmllint::replayImportWarnings()
+{
+ QJsonArray warnings;
+ callQmllint(testFile(u"duplicateTypeUserUser.qml"_s), true, &warnings);
+
+ // No warning because the offending import is indirect.
+ QVERIFY2(warnings.isEmpty(), qPrintable(QJsonDocument(warnings).toJson()));
+
+ // No cache clearing here. We want the warnings restored.
+ callQmllint(testFile(u"DuplicateTypeUser.qml"_s), false, &warnings);
+
+ // Warning because the offending import is now direct.
+ searchWarnings(warnings, "Ambiguous type detected. T 1.0 is defined multiple times.");
+}
+
QTEST_GUILESS_MAIN(TestQmllint)
#include "tst_qmllint.moc"
diff --git a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
index 3ece7e9330..ac49239781 100644
--- a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
+++ b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
@@ -213,7 +213,7 @@ void tst_qqmljsscope::allTypesAvailable()
QQmlJSImporter importer { importPaths, /* resource file mapper */ nullptr };
const auto imported = importer.importModule(u"QtQml"_s);
- QCOMPARE(imported.context(), QQmlJS::ContextualTypes::QML);
+ QCOMPARE(imported.contextualTypes().context(), QQmlJS::ContextualTypes::QML);
const auto types = imported.types();
QVERIFY(types.contains(u"$internal$.QObject"_s));
QVERIFY(types.contains(u"QtObject"_s));