Adapt to new diagnostics presentation API in AnalyzerBase.

Task-number: QCE-34
Change-Id: Ia86fa082b3798ba42ec209b0e417e8a8ca0f8fa7
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
Christian Kandeler
2015-06-19 15:37:16 +02:00
parent 501aad8d2c
commit d9affc16c4
14 changed files with 233 additions and 378 deletions

View File

@@ -18,6 +18,7 @@
#include "clangstaticanalyzerdiagnosticmodel.h"
#include "clangstaticanalyzerdiagnosticview.h"
#include "clangstaticanalyzerprojectsettingsmanager.h"
#include "clangstaticanalyzerutils.h"
@@ -28,32 +29,53 @@
#include <QCoreApplication>
#include <QFileInfo>
#include <cmath>
namespace ClangStaticAnalyzer {
namespace Internal {
ClangStaticAnalyzerDiagnosticModel::ClangStaticAnalyzerDiagnosticModel(QObject *parent)
: QAbstractListModel(parent)
class DiagnosticItem : public Utils::TreeItem
{
public:
DiagnosticItem(const Diagnostic &diag);
Diagnostic diagnostic() const { return m_diagnostic; }
private:
QVariant data(int column, int role) const override;
const Diagnostic m_diagnostic;
};
class ExplainingStepItem : public Utils::TreeItem
{
public:
ExplainingStepItem(const ExplainingStep &step);
private:
QVariant data(int column, int role) const override;
const ExplainingStep m_step;
};
ClangStaticAnalyzerDiagnosticModel::ClangStaticAnalyzerDiagnosticModel(QObject *parent)
: Utils::TreeModel(parent)
{
setHeader(QStringList() << tr("Issue") << tr("Location"));
}
void ClangStaticAnalyzerDiagnosticModel::addDiagnostics(const QList<Diagnostic> &diagnostics)
{
beginInsertRows(QModelIndex(), m_diagnostics.size(),
m_diagnostics.size() + diagnostics.size() - 1 );
m_diagnostics += diagnostics;
endInsertRows();
foreach (const Diagnostic &d, diagnostics)
rootItem()->appendChild(new DiagnosticItem(d));
}
void ClangStaticAnalyzerDiagnosticModel::clear()
QList<Diagnostic> ClangStaticAnalyzerDiagnosticModel::diagnostics() const
{
beginResetModel();
m_diagnostics.clear();
endResetModel();
}
int ClangStaticAnalyzerDiagnosticModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_diagnostics.count();
QList<Diagnostic> diags;
foreach (const Utils::TreeItem * const item, rootItem()->children())
diags << static_cast<const DiagnosticItem *>(item)->diagnostic();
return diags;
}
static QString createDiagnosticToolTipString(const Diagnostic &diagnostic)
@@ -100,28 +122,162 @@ static QString createDiagnosticToolTipString(const Diagnostic &diagnostic)
return html;
}
QVariant ClangStaticAnalyzerDiagnosticModel::data(const QModelIndex &index, int role) const
static QString createExplainingStepToolTipString(const ExplainingStep &step)
{
if (!index.isValid())
if (step.message == step.extendedMessage)
return createFullLocationString(step.location);
typedef QPair<QString, QString> StringPair;
QList<StringPair> lines;
if (!step.message.isEmpty()) {
lines << qMakePair(
QCoreApplication::translate("ClangStaticAnalyzer::ExplainingStep", "Message:"),
step.message.toHtmlEscaped());
}
if (!step.extendedMessage.isEmpty()) {
lines << qMakePair(
QCoreApplication::translate("ClangStaticAnalyzer::ExplainingStep", "Extended Message:"),
step.extendedMessage.toHtmlEscaped());
}
lines << qMakePair(
QCoreApplication::translate("ClangStaticAnalyzer::ExplainingStep", "Location:"),
createFullLocationString(step.location));
QString html = QLatin1String("<html>"
"<head>"
"<style>dt { font-weight:bold; } dd { font-family: monospace; }</style>\n"
"<body><dl>");
foreach (const StringPair &pair, lines) {
html += QLatin1String("<dt>");
html += pair.first;
html += QLatin1String("</dt><dd>");
html += pair.second;
html += QLatin1String("</dd>\n");
}
html += QLatin1String("</dl></body></html>");
return html;
}
static QString createLocationString(const Analyzer::DiagnosticLocation &location)
{
const QString filePath = location.filePath;
const QString lineNumber = QString::number(location.line);
const QString fileAndLine = filePath + QLatin1Char(':') + lineNumber;
return QLatin1String("in ") + fileAndLine;
}
static QString createExplainingStepNumberString(int number)
{
const int fieldWidth = 2;
return QString::fromLatin1("%1:").arg(number, fieldWidth);
}
static QString createExplainingStepString(const ExplainingStep &explainingStep, int number)
{
return createExplainingStepNumberString(number)
+ QLatin1Char(' ')
+ explainingStep.extendedMessage
+ QLatin1Char(' ')
+ createLocationString(explainingStep.location);
}
static QString fullText(const Diagnostic &diagnostic)
{
// Summary.
QString text = diagnostic.category + QLatin1String(": ") + diagnostic.type;
if (diagnostic.type != diagnostic.description)
text += QLatin1String(": ") + diagnostic.description;
text += QLatin1Char('\n');
// Explaining steps.
int explainingStepNumber = 1;
foreach (const ExplainingStep &explainingStep, diagnostic.explainingSteps) {
text += createExplainingStepString(explainingStep, explainingStepNumber++)
+ QLatin1Char('\n');
}
text.chop(1); // Trailing newline.
return text;
}
DiagnosticItem::DiagnosticItem(const Diagnostic &diag) : m_diagnostic(diag)
{
// Don't show explaining steps if they add no information.
if (diag.explainingSteps.count() == 1) {
const ExplainingStep &step = diag.explainingSteps.first();
if (step.message == diag.description && step.location == diag.location)
return;
}
foreach (const ExplainingStep &s, diag.explainingSteps)
appendChild(new ExplainingStepItem(s));
}
QVariant locationData(int role, const Analyzer::DiagnosticLocation &location)
{
switch (role) {
case Analyzer::DetailedErrorView::LocationRole:
return QVariant::fromValue(location);
case Qt::ToolTipRole:
return location.filePath.isEmpty() ? QVariant() : QVariant(location.filePath);
default:
return QVariant();
}
}
if (index.parent().isValid())
QVariant DiagnosticItem::data(int column, int role) const
{
if (column == Analyzer::DetailedErrorView::LocationColumn)
return locationData(role, m_diagnostic.location);
// DiagnosticColumn
switch (role) {
case Analyzer::DetailedErrorView::FullTextRole:
return fullText(m_diagnostic);
case ClangStaticAnalyzerDiagnosticModel::DiagnosticRole:
return QVariant::fromValue(m_diagnostic);
case Qt::DisplayRole:
return m_diagnostic.description;
case Qt::ToolTipRole:
return createDiagnosticToolTipString(m_diagnostic);
default:
return QVariant();
}
}
const int row = index.row();
if (row < 0 || row >= m_diagnostics.size())
ExplainingStepItem::ExplainingStepItem(const ExplainingStep &step) : m_step(step)
{
}
QVariant ExplainingStepItem::data(int column, int role) const
{
if (column == Analyzer::DetailedErrorView::LocationColumn)
return locationData(role, m_step.location);
// DiagnosticColumn
switch (role) {
case Analyzer::DetailedErrorView::FullTextRole:
return fullText(static_cast<DiagnosticItem *>(parent())->diagnostic());
case ClangStaticAnalyzerDiagnosticModel::DiagnosticRole:
return QVariant::fromValue(static_cast<DiagnosticItem *>(parent())->diagnostic());
case Qt::DisplayRole: {
const int row = parent()->children().indexOf(const_cast<ExplainingStepItem *>(this)) + 1;
const int padding = static_cast<int>(std::log10(parent()->rowCount()))
- static_cast<int>(std::log10(row));
return QString::fromLatin1("%1%2: %3")
.arg(QString(padding, QLatin1Char(' ')))
.arg(row)
.arg(m_step.message);
}
case Qt::ToolTipRole:
return createExplainingStepToolTipString(m_step);
default:
return QVariant();
const Diagnostic diagnostic = m_diagnostics.at(row);
if (role == Qt::DisplayRole)
return QString(QLatin1String("Some specific diagnostic")); // TODO: Remove?
else if (role == Qt::ToolTipRole)
return createDiagnosticToolTipString(diagnostic);
else if (role == Qt::UserRole)
return QVariant::fromValue<Diagnostic>(diagnostic);
return QVariant();
}
}
@@ -165,7 +321,8 @@ void ClangStaticAnalyzerDiagnosticFilterModel::addSuppressedDiagnostic(
bool ClangStaticAnalyzerDiagnosticFilterModel::filterAcceptsRow(int sourceRow,
const QModelIndex &sourceParent) const
{
Q_UNUSED(sourceParent);
if (sourceParent.isValid())
return true;
const Diagnostic diag = static_cast<ClangStaticAnalyzerDiagnosticModel *>(sourceModel())
->diagnostics().at(sourceRow);
foreach (const SuppressedDiagnostic &d, m_suppressedDiagnostics) {