qmllint: Warn about failing imports
Warn when an import fails instead of silently ignoring them. Without these it was impossible to tell whether a type was not resolved due to an unresolvable import or due to other reasons. It also fixes the previous behavior of just dumping the types of qmltypes into the rootScope if manually imported. Now they are only are present when actually importing one of the modules mentioned in the type's export statement. Change-Id: I62bdd99828702ed02512eaac30f7f99b98d1df28 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
b07d653c09
commit
6ddb78735b
|
@ -269,25 +269,40 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
|
|||
/*!
|
||||
* Imports types from the specified \a qmltypesFiles.
|
||||
*/
|
||||
QQmlJSImporter::ImportedTypes QQmlJSImporter::importQmltypes(const QStringList &qmltypesFiles)
|
||||
void QQmlJSImporter::importQmltypes(const QStringList &qmltypesFiles)
|
||||
{
|
||||
AvailableTypes types(builtinImportHelper().cppNames);
|
||||
Import result;
|
||||
|
||||
for (const auto &qmltypeFile : qmltypesFiles)
|
||||
for (const auto &qmltypeFile : qmltypesFiles) {
|
||||
Import result;
|
||||
readQmltypes(qmltypeFile, &result.objects, &result.dependencies);
|
||||
|
||||
importDependencies(result, &types);
|
||||
processImport(result, &types);
|
||||
// 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 producing weird results.
|
||||
const QString qmldirName = qmltypeFile + QStringLiteral("_FAKE_QMLDIR");
|
||||
m_seenQmldirFiles.insert(qmldirName, result);
|
||||
|
||||
return types.qmlNames;
|
||||
for (const auto &object : result.objects.values()) {
|
||||
for (const auto &ex : object->exports()) {
|
||||
m_seenImports.insert({ex.package(), ex.version()}, qmldirName);
|
||||
// We also have to handle the case that no version is provided
|
||||
m_seenImports.insert({ex.package(), QTypeRevision()}, qmldirName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QQmlJSImporter::ImportedTypes QQmlJSImporter::importModule(
|
||||
const QString &module, const QString &prefix, QTypeRevision version)
|
||||
const QString &module, const QString &prefix, QTypeRevision version, QQmlJS::SourceLocation location)
|
||||
{
|
||||
AvailableTypes result(builtinImportHelper().cppNames);
|
||||
importHelper(module, &result, prefix, version);
|
||||
if (!importHelper(module, &result, prefix, version)) {
|
||||
m_warnings.append({
|
||||
QStringLiteral("Failed to import %1. Are your include paths set up properly?").arg(module),
|
||||
QtWarningMsg,
|
||||
location
|
||||
});
|
||||
}
|
||||
return result.qmlNames;
|
||||
}
|
||||
|
||||
|
@ -296,20 +311,22 @@ QQmlJSImporter::ImportedTypes QQmlJSImporter::builtinInternalNames()
|
|||
return builtinImportHelper().cppNames;
|
||||
}
|
||||
|
||||
void QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types,
|
||||
bool QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types,
|
||||
const QString &prefix, QTypeRevision version)
|
||||
{
|
||||
|
||||
const QPair<QString, QTypeRevision> importId { module, version };
|
||||
const auto it = m_seenImports.constFind(importId);
|
||||
|
||||
if (it != m_seenImports.constEnd()) {
|
||||
if (it->isEmpty())
|
||||
return; // TODO: warn here in the future
|
||||
return false;
|
||||
|
||||
const auto import = m_seenQmldirFiles.constFind(*it);
|
||||
Q_ASSERT(import != m_seenQmldirFiles.constEnd());
|
||||
importDependencies(*import, types, prefix, version);
|
||||
processImport(*import, types, prefix);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto modulePaths = qQmlResolveImportPaths(module, m_importPaths, version);
|
||||
|
@ -321,7 +338,7 @@ void QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types,
|
|||
m_seenImports.insert(importId, qmldirPath);
|
||||
importDependencies(*it, types, prefix, version);
|
||||
processImport(*it, types, prefix);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
const QFileInfo file(qmldirPath);
|
||||
|
@ -331,12 +348,13 @@ void QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types,
|
|||
m_seenImports.insert(importId, qmldirPath);
|
||||
importDependencies(import, types, prefix, version);
|
||||
processImport(import, types, prefix);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: warn here in the future
|
||||
m_seenImports.insert(importId, QString());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QQmlJSScope::Ptr QQmlJSImporter::localFile2ScopeTree(const QString &filePath)
|
||||
|
|
|
@ -59,14 +59,15 @@ public:
|
|||
QQmlJSResourceFileMapper *resourceFileMapper() { return m_mapper; }
|
||||
|
||||
ImportedTypes importBuiltins();
|
||||
ImportedTypes importQmltypes(const QStringList &qmltypesFiles);
|
||||
void importQmltypes(const QStringList &qmltypesFiles);
|
||||
|
||||
QQmlJSScope::Ptr importFile(const QString &file);
|
||||
ImportedTypes importDirectory(const QString &directory, const QString &prefix = QString());
|
||||
|
||||
ImportedTypes importModule(
|
||||
const QString &module, const QString &prefix = QString(),
|
||||
QTypeRevision version = QTypeRevision());
|
||||
QTypeRevision version = QTypeRevision(),
|
||||
QQmlJS::SourceLocation location = QQmlJS::SourceLocation());
|
||||
|
||||
ImportedTypes builtinInternalNames();
|
||||
|
||||
|
@ -101,7 +102,7 @@ private:
|
|||
};
|
||||
|
||||
AvailableTypes builtinImportHelper();
|
||||
void importHelper(const QString &module, AvailableTypes *types,
|
||||
bool importHelper(const QString &module, AvailableTypes *types,
|
||||
const QString &prefix = QString(),
|
||||
QTypeRevision version = QTypeRevision());
|
||||
void processImport(const Import &import, AvailableTypes *types,
|
||||
|
|
|
@ -176,7 +176,7 @@ void QQmlJSImportVisitor::importBaseModules()
|
|||
m_rootScopeImports = m_importer->importBuiltins();
|
||||
|
||||
if (!m_qmltypesFiles.isEmpty())
|
||||
m_rootScopeImports.insert(m_importer->importQmltypes(m_qmltypesFiles));
|
||||
m_importer->importQmltypes(m_qmltypesFiles);
|
||||
|
||||
m_rootScopeImports.insert(m_importer->importDirectory(m_implicitImportDirectory));
|
||||
m_errors.append(m_importer->takeWarnings());
|
||||
|
@ -538,7 +538,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import)
|
|||
path.chop(1);
|
||||
|
||||
const auto imported = m_importer->importModule(
|
||||
path, prefix, import->version ? import->version->version : QTypeRevision());
|
||||
path, prefix, import->version ? import->version->version : QTypeRevision(), import->firstSourceLocation());
|
||||
|
||||
m_rootScopeImports.insert(imported);
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
import QtQml
|
||||
import FooBar
|
||||
|
||||
QtObject {}
|
|
@ -379,6 +379,10 @@ void TestQmllint::dirtyQmlCode_data()
|
|||
<< QStringLiteral("defaultPropertyWithWrongType2.qml")
|
||||
<< QStringLiteral("Cannot assign to default property of incompatible type")
|
||||
<< QStringLiteral("Cannot assign to non-existent default property");
|
||||
QTest::newRow("InvalidImport")
|
||||
<< QStringLiteral("invalidImport.qml")
|
||||
<< QStringLiteral("Failed to import FooBar. Are your include paths set up properly?")
|
||||
<< QString();
|
||||
}
|
||||
|
||||
void TestQmllint::dirtyQmlCode()
|
||||
|
|
Loading…
Reference in New Issue