ClangTools: Show also diagnostics from project's header files

Fixes: QTCREATORBUG-21452
Change-Id: I73c85224e142f4f1d08c9ada75fe8359ebf0f984
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Nikolai Kosjar
2019-01-22 12:04:51 +01:00
parent 171f3aec26
commit 46fc8c4144
11 changed files with 79 additions and 27 deletions

View File

@@ -407,7 +407,7 @@ void ClangTidyClazyTool::updateRunActions()
m_startAction->setToolTip(toolTip); m_startAction->setToolTip(toolTip);
m_startAction->setEnabled(canRun); m_startAction->setEnabled(canRun);
m_stopAction->setEnabled(false); m_stopAction->setEnabled(false);
m_clear->setEnabled(m_diagnosticModel->diagnosticsCount()); m_clear->setEnabled(m_diagnosticModel->diagnostics().count());
} }
} }
@@ -418,7 +418,7 @@ void ClangTidyClazyTool::handleStateUpdate()
QTC_ASSERT(m_diagnosticModel, return); QTC_ASSERT(m_diagnosticModel, return);
QTC_ASSERT(m_diagnosticFilterModel, return); QTC_ASSERT(m_diagnosticFilterModel, return);
const int issuesFound = m_diagnosticModel->diagnosticsCount(); const int issuesFound = m_diagnosticModel->diagnostics().count();
const int issuesVisible = m_diagnosticFilterModel->rowCount(); const int issuesVisible = m_diagnosticFilterModel->rowCount();
m_goBack->setEnabled(issuesVisible > 1); m_goBack->setEnabled(issuesVisible > 1);
m_goNext->setEnabled(issuesVisible > 1); m_goNext->setEnabled(issuesVisible > 1);
@@ -439,10 +439,11 @@ void ClangTidyClazyTool::handleStateUpdate()
} }
QList<Diagnostic> ClangTidyClazyTool::read(const QString &filePath, QList<Diagnostic> ClangTidyClazyTool::read(const QString &filePath,
const Utils::FileName &projectRootDir,
const QString &logFilePath, const QString &logFilePath,
QString *errorMessage) const QString *errorMessage) const
{ {
return readSerializedDiagnostics(filePath, logFilePath, errorMessage); return readSerializedDiagnostics(filePath, projectRootDir, logFilePath, errorMessage);
} }
} // namespace Internal } // namespace Internal

View File

@@ -54,6 +54,7 @@ public:
void startTool(bool askUserForFileSelection) final; void startTool(bool askUserForFileSelection) final;
QList<Diagnostic> read(const QString &filePath, QList<Diagnostic> read(const QString &filePath,
const Utils::FileName &projectRootDir,
const QString &logFilePath, const QString &logFilePath,
QString *errorMessage) const final; QString *errorMessage) const final;

View File

@@ -135,7 +135,7 @@ void ClangTool::initDiagnosticView()
m_diagnosticView->setAutoScroll(false); m_diagnosticView->setAutoScroll(false);
} }
QList<Diagnostic> ClangTool::diagnostics() const QSet<Diagnostic> ClangTool::diagnostics() const
{ {
return m_diagnosticModel->diagnostics(); return m_diagnosticModel->diagnostics();
} }

View File

@@ -31,6 +31,7 @@
#include <cpptools/projectinfo.h> #include <cpptools/projectinfo.h>
namespace Debugger { class DetailedErrorView; } namespace Debugger { class DetailedErrorView; }
namespace Utils { class FileName; }
namespace ClangTools { namespace ClangTools {
namespace Internal { namespace Internal {
@@ -49,6 +50,7 @@ public:
virtual void startTool(bool askUserForFileSelection) = 0; virtual void startTool(bool askUserForFileSelection) = 0;
virtual QList<Diagnostic> read(const QString &filePath, virtual QList<Diagnostic> read(const QString &filePath,
const Utils::FileName &projectRootDir,
const QString &logFilePath, const QString &logFilePath,
QString *errorMessage) const = 0; QString *errorMessage) const = 0;
@@ -56,7 +58,7 @@ public:
bool askUserForFileSelection) const; bool askUserForFileSelection) const;
// For testing. // For testing.
QList<Diagnostic> diagnostics() const; QSet<Diagnostic> diagnostics() const;
const QString &name() const; const QString &name() const;

View File

@@ -387,13 +387,24 @@ void ClangToolRunControl::analyzeNextFile()
Utils::StdOutFormat); Utils::StdOutFormat);
} }
static Utils::FileName cleanPath(const Utils::FileName &filePath)
{
return Utils::FileName::fromString(QDir::cleanPath(filePath.toString()));
}
void ClangToolRunControl::onRunnerFinishedWithSuccess(const QString &filePath) void ClangToolRunControl::onRunnerFinishedWithSuccess(const QString &filePath)
{ {
const QString logFilePath = qobject_cast<ClangToolRunner *>(sender())->logFilePath(); const QString logFilePath = qobject_cast<ClangToolRunner *>(sender())->logFilePath();
qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << logFilePath; qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << logFilePath;
QTC_ASSERT(m_projectInfo.project(), return);
const Utils::FileName projectRootDir = cleanPath(m_projectInfo.project()->projectDirectory());
QString errorMessage; QString errorMessage;
const QList<Diagnostic> diagnostics = tool()->read(filePath, logFilePath, &errorMessage); const QList<Diagnostic> diagnostics = tool()->read(filePath,
projectRootDir,
logFilePath,
&errorMessage);
QFile::remove(logFilePath); // Clean-up. QFile::remove(logFilePath); // Clean-up.
if (!errorMessage.isEmpty()) { if (!errorMessage.isEmpty()) {

View File

@@ -38,5 +38,13 @@ bool Diagnostic::isValid() const
return !description.isEmpty(); return !description.isEmpty();
} }
quint32 qHash(const Diagnostic &diagnostic)
{
return qHash(diagnostic.description)
^ qHash(diagnostic.location.filePath)
^ diagnostic.location.line
^ diagnostic.location.column;
}
} // namespace Internal } // namespace Internal
} // namespace ClangTools } // namespace ClangTools

View File

@@ -66,6 +66,8 @@ public:
bool hasFixits = false; bool hasFixits = false;
}; };
quint32 qHash(const Diagnostic &diagnostic);
} // namespace Internal } // namespace Internal
} // namespace ClangTools } // namespace ClangTools

View File

@@ -35,9 +35,12 @@
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <QFileInfo> #include <QFileInfo>
#include <QLoggingCategory>
#include <cmath> #include <cmath>
static Q_LOGGING_CATEGORY(LOG, "qtc.clangtools.model", QtWarningMsg)
namespace ClangTools { namespace ClangTools {
namespace Internal { namespace Internal {
@@ -60,6 +63,19 @@ ClangToolsDiagnosticModel::ClangToolsDiagnosticModel(QObject *parent)
connectFileWatcher(); connectFileWatcher();
} }
QDebug operator<<(QDebug debug, const Diagnostic &d)
{
return debug << "category:" << d.category
<< "type:" << d.type
<< "context:" << d.issueContext
<< "contextKind:" << d.issueContextKind
<< "hasFixits:" << d.hasFixits
<< "explainingSteps:" << d.explainingSteps.size()
<< "location:" << d.location
<< "description:" << d.description
;
}
void ClangToolsDiagnosticModel::addDiagnostics(const QList<Diagnostic> &diagnostics) void ClangToolsDiagnosticModel::addDiagnostics(const QList<Diagnostic> &diagnostics)
{ {
const auto onFixitStatusChanged = [this](FixitStatus newStatus) { const auto onFixitStatusChanged = [this](FixitStatus newStatus) {
@@ -70,28 +86,28 @@ void ClangToolsDiagnosticModel::addDiagnostics(const QList<Diagnostic> &diagnost
emit fixItsToApplyCountChanged(m_fixItsToApplyCount); emit fixItsToApplyCountChanged(m_fixItsToApplyCount);
}; };
if (!diagnostics.empty()) for (const Diagnostic &d : diagnostics) {
addWatchedPath(diagnostics.front().location.filePath); const int previousItemCount = m_diagnostics.count();
m_diagnostics.insert(d);
if (m_diagnostics.count() == previousItemCount) {
qCDebug(LOG) << "Not adding duplicate diagnostic:" << d;
continue;
}
for (const Diagnostic &d : diagnostics) qCDebug(LOG) << "Adding diagnostic:" << d;
addWatchedPath(d.location.filePath);
rootItem()->appendChild(new DiagnosticItem(d, onFixitStatusChanged, this)); rootItem()->appendChild(new DiagnosticItem(d, onFixitStatusChanged, this));
}
} }
QList<Diagnostic> ClangToolsDiagnosticModel::diagnostics() const QSet<Diagnostic> ClangToolsDiagnosticModel::diagnostics() const
{ {
QList<Diagnostic> diags; return m_diagnostics;
for (const Utils::TreeItem * const item : *rootItem())
diags << static_cast<const DiagnosticItem *>(item)->diagnostic();
return diags;
}
int ClangToolsDiagnosticModel::diagnosticsCount() const
{
return rootItem()->childCount();
} }
void ClangToolsDiagnosticModel::clear() void ClangToolsDiagnosticModel::clear()
{ {
m_diagnostics.clear();
clearAndSetupCache(); clearAndSetupCache();
Utils::TreeModel<>::clear(); Utils::TreeModel<>::clear();
} }

View File

@@ -98,10 +98,8 @@ class ClangToolsDiagnosticModel : public Utils::TreeModel<>
public: public:
ClangToolsDiagnosticModel(QObject *parent = nullptr); ClangToolsDiagnosticModel(QObject *parent = nullptr);
virtual void addDiagnostics(const QList<Diagnostic> &diagnostics); void addDiagnostics(const QList<Diagnostic> &diagnostics);
virtual QList<Diagnostic> diagnostics() const; QSet<Diagnostic> diagnostics() const;
int diagnosticsCount() const;
enum ItemRole { enum ItemRole {
DiagnosticRole = Debugger::DetailedErrorView::FullTextRole + 1 DiagnosticRole = Debugger::DetailedErrorView::FullTextRole + 1
@@ -121,6 +119,7 @@ private:
void clearAndSetupCache(); void clearAndSetupCache();
private: private:
QSet<Diagnostic> m_diagnostics;
std::map<QVector<ExplainingStep>, QVector<DiagnosticItem *>> stepsToItemsCache; std::map<QVector<ExplainingStep>, QVector<DiagnosticItem *>> stepsToItemsCache;
std::unique_ptr<QFileSystemWatcher> m_filesWatcher; std::unique_ptr<QFileSystemWatcher> m_filesWatcher;
int m_fixItsToApplyCount = 0; int m_fixItsToApplyCount = 0;

View File

@@ -59,6 +59,7 @@ static Debugger::DiagnosticLocation diagLocationFromSourceLocation(CXSourceLocat
Debugger::DiagnosticLocation location; Debugger::DiagnosticLocation location;
location.filePath = fromCXString(clang_getFileName(file)); location.filePath = fromCXString(clang_getFileName(file));
location.filePath = QDir::cleanPath(location.filePath); // Normalize to find duplicates later
location.line = line; location.line = line;
location.column = column; location.column = column;
return location; return location;
@@ -118,7 +119,9 @@ static ExplainingStep buildFixIt(const CXDiagnostic cxDiagnostic, unsigned index
return fixItStep; return fixItStep;
} }
static Diagnostic buildDiagnostic(const CXDiagnostic cxDiagnostic, const QString &nativeFilePath) static Diagnostic buildDiagnostic(const CXDiagnostic cxDiagnostic,
const Utils::FileName &projectRootDir,
const QString &nativeFilePath)
{ {
Diagnostic diagnostic; Diagnostic diagnostic;
diagnostic.type = cxDiagnosticType(cxDiagnostic); diagnostic.type = cxDiagnosticType(cxDiagnostic);
@@ -130,7 +133,13 @@ static Diagnostic buildDiagnostic(const CXDiagnostic cxDiagnostic, const QString
return diagnostic; return diagnostic;
diagnostic.location = diagLocationFromSourceLocation(cxLocation); diagnostic.location = diagLocationFromSourceLocation(cxLocation);
if (diagnostic.location.filePath != nativeFilePath) const auto diagnosticFilePath = Utils::FileName::fromString(diagnostic.location.filePath);
if (!diagnosticFilePath.isChildOf(projectRootDir))
return diagnostic;
// TODO: Introduce CppTools::ProjectFile::isGenerated to filter these out properly
const QString fileName = diagnosticFilePath.fileName();
if ((fileName.startsWith("ui_") && fileName.endsWith(".h")) || fileName.endsWith(".moc"))
return diagnostic; return diagnostic;
CXDiagnosticSet cxChildDiagnostics = clang_getChildDiagnostics(cxDiagnostic); CXDiagnosticSet cxChildDiagnostics = clang_getChildDiagnostics(cxDiagnostic);
@@ -165,6 +174,7 @@ static Diagnostic buildDiagnostic(const CXDiagnostic cxDiagnostic, const QString
} }
static QList<Diagnostic> readSerializedDiagnostics_helper(const QString &filePath, static QList<Diagnostic> readSerializedDiagnostics_helper(const QString &filePath,
const Utils::FileName &projectRootDir,
const QString &logFilePath) const QString &logFilePath)
{ {
QList<Diagnostic> list; QList<Diagnostic> list;
@@ -187,7 +197,7 @@ static QList<Diagnostic> readSerializedDiagnostics_helper(const QString &filePat
Utils::ExecuteOnDestruction cleanUpDiagnostic([&]() { Utils::ExecuteOnDestruction cleanUpDiagnostic([&]() {
clang_disposeDiagnostic(cxDiagnostic); clang_disposeDiagnostic(cxDiagnostic);
}); });
const Diagnostic diagnostic = buildDiagnostic(cxDiagnostic, nativeFilePath); const Diagnostic diagnostic = buildDiagnostic(cxDiagnostic, projectRootDir, nativeFilePath);
if (!diagnostic.isValid()) if (!diagnostic.isValid())
continue; continue;
@@ -213,13 +223,14 @@ static bool checkFilePath(const QString &filePath, QString *errorMessage)
} }
QList<Diagnostic> readSerializedDiagnostics(const QString &filePath, QList<Diagnostic> readSerializedDiagnostics(const QString &filePath,
const Utils::FileName &projectRootDir,
const QString &logFilePath, const QString &logFilePath,
QString *errorMessage) QString *errorMessage)
{ {
if (!checkFilePath(logFilePath, errorMessage)) if (!checkFilePath(logFilePath, errorMessage))
return QList<Diagnostic>(); return QList<Diagnostic>();
return readSerializedDiagnostics_helper(filePath, logFilePath); return readSerializedDiagnostics_helper(filePath, projectRootDir, logFilePath);
} }
} // namespace Internal } // namespace Internal

View File

@@ -35,6 +35,7 @@ namespace ClangTools {
namespace Internal { namespace Internal {
QList<Diagnostic> readSerializedDiagnostics(const QString &filePath, QList<Diagnostic> readSerializedDiagnostics(const QString &filePath,
const Utils::FileName &projectRootDir,
const QString &logFilePath, const QString &logFilePath,
QString *errorMessage); QString *errorMessage);