forked from qt-creator/qt-creator
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:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user