aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2021-03-24 20:13:14 +0100
committerMaximilian Goldstein <max.goldstein@qt.io>2021-03-25 11:34:41 +0100
commiteb74d99d02f61007443bcdf83033b05d525326b8 (patch)
treee7d768e70b154daa9418aad3d3d3df138908c201 /tools
parent8fe127129b4f31e7e13dbf727687d98b95984763 (diff)
qmllint: Add support for warning about unused imports
qmllint will now show an information line pointing out import statements that are not needed. It will not warn about imports that are redundant however, since there are legitimate reasons for having these. Fixes: QTBUG-83237 Change-Id: I9588b5fa8a8efd37b48c9b349a448e580efb1452 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'tools')
-rw-r--r--tools/qmllint/checkidentifiers.cpp11
-rw-r--r--tools/qmllint/findwarnings.cpp37
2 files changed, 43 insertions, 5 deletions
diff --git a/tools/qmllint/checkidentifiers.cpp b/tools/qmllint/checkidentifiers.cpp
index 1ade63c1c0..7350a1f76e 100644
--- a/tools/qmllint/checkidentifiers.cpp
+++ b/tools/qmllint/checkidentifiers.cpp
@@ -38,7 +38,10 @@ class IssueLocationWithContext
public:
IssueLocationWithContext(const QString &code, const QQmlJS::SourceLocation &location) {
int before = qMax(0,code.lastIndexOf(QLatin1Char('\n'), location.offset));
- m_beforeText = QStringView{code}.mid(before + 1, int(location.offset - (before + 1)));
+
+ if (before != 0) before++;
+
+ m_beforeText = QStringView{code}.mid(before, int(location.offset - before));
m_issueText = QStringView{code}.mid(location.offset, location.length);
int after = code.indexOf(QLatin1Char('\n'), int(location.offset + location.length));
m_afterText = QStringView{code}.mid(int(location.offset + location.length),
@@ -68,9 +71,11 @@ void CheckIdentifiers::printContext(
const QString &code, ColorOutput *output, const QQmlJS::SourceLocation &location)
{
IssueLocationWithContext issueLocationWithContext { code, location };
- output->write(issueLocationWithContext.beforeText().toString(), Normal);
+ if (const QString beforeText = issueLocationWithContext.beforeText().toString(); !beforeText.isEmpty())
+ output->write(beforeText, Normal);
output->write(issueLocationWithContext.issueText().toString(), Error);
- output->write(issueLocationWithContext.afterText().toString() + QLatin1Char('\n'), Normal);
+ if (const QString afterText = issueLocationWithContext.afterText().toString(); !afterText.isEmpty())
+ output->write(afterText + QLatin1Char('\n'), Normal);
int tabCount = issueLocationWithContext.beforeText().count(QLatin1Char('\t'));
output->write(QString::fromLatin1(" ").repeated(
issueLocationWithContext.beforeText().length() - tabCount)
diff --git a/tools/qmllint/findwarnings.cpp b/tools/qmllint/findwarnings.cpp
index c7f2a557f6..dd87293eb6 100644
--- a/tools/qmllint/findwarnings.cpp
+++ b/tools/qmllint/findwarnings.cpp
@@ -390,8 +390,13 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiScriptBinding *uisb)
bool FindWarningVisitor::visit(QQmlJS::AST::IdentifierExpression *idexp)
{
+ const QString name = idexp->name.toString();
+ if (name.front().isUpper() && m_importTypeLocationMap.contains(name)) {
+ m_usedTypes.insert(name);
+ }
+
m_memberAccessChains[m_currentScope].append(
- {{idexp->name.toString(), QString(), idexp->firstSourceLocation()}});
+ {{name, QString(), idexp->firstSourceLocation()}});
m_fieldMemberBase = idexp;
return true;
}
@@ -489,6 +494,25 @@ bool FindWarningVisitor::check()
outstandingConnection.uiod->initializer->accept(this);
}
+ auto unusedImports = m_importLocations;
+ for (const QString &type : m_usedTypes) {
+ for (const auto &importLocation : m_importTypeLocationMap.values(type))
+ unusedImports.remove(importLocation);
+
+ // If there are no more unused imports left we can abort early
+ if (unusedImports.isEmpty())
+ break;
+ }
+
+ for (const auto &import : unusedImports) {
+ m_colorOut.writePrefixedMessage(
+ QString::fromLatin1("Unused import at %1:%2:%3\n")
+ .arg(m_filePath)
+ .arg(import.startLine).arg(import.startColumn),
+ Info);
+ CheckIdentifiers::printContext(m_code, &m_colorOut, import);
+ }
+
if (!m_warnUnqualified)
return m_errors.isEmpty();
@@ -617,6 +641,7 @@ void FindWarningVisitor::endVisit(QQmlJS::AST::FieldMemberExpression *fieldMembe
{
using namespace QQmlJS::AST;
ExpressionNode *base = fieldMember->base;
+
while (auto *nested = cast<NestedExpression *>(base))
base = nested->expression;
@@ -631,9 +656,17 @@ void FindWarningVisitor::endVisit(QQmlJS::AST::FieldMemberExpression *fieldMembe
auto &chain = m_memberAccessChains[m_currentScope];
+
Q_ASSERT(!chain.last().isEmpty());
+
+ const QString name = fieldMember->name.toString();
+ if (m_importTypeLocationMap.contains(name)) {
+ if (auto it = m_rootScopeImports.find(name); it != m_rootScopeImports.end() && !*(it))
+ m_usedTypes.insert(name);
+ }
+
chain.last().append(FieldMember {
- fieldMember->name.toString(), type, fieldMember->identifierToken
+ name, type, fieldMember->identifierToken
});
m_fieldMemberBase = fieldMember;
} else {