diff options
author | Maximilian Goldstein <max.goldstein@qt.io> | 2021-03-24 20:13:14 +0100 |
---|---|---|
committer | Maximilian Goldstein <max.goldstein@qt.io> | 2021-03-25 11:34:41 +0100 |
commit | eb74d99d02f61007443bcdf83033b05d525326b8 (patch) | |
tree | e7d768e70b154daa9418aad3d3d3df138908c201 /tools | |
parent | 8fe127129b4f31e7e13dbf727687d98b95984763 (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.cpp | 11 | ||||
-rw-r--r-- | tools/qmllint/findwarnings.cpp | 37 |
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 { |