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

@@ -21,21 +21,6 @@
namespace ClangStaticAnalyzer { namespace ClangStaticAnalyzer {
namespace Internal { namespace Internal {
Location::Location()
: line(0), column(0)
{
}
Location::Location(const QString &filePath, int line, int column)
: filePath(filePath), line(line), column(column)
{
}
bool Location::isValid() const
{
return !filePath.isEmpty() && line >= 0 && column >= 0;
}
ExplainingStep::ExplainingStep() ExplainingStep::ExplainingStep()
: depth(0) : depth(0)
{ {

View File

@@ -19,6 +19,8 @@
#ifndef CLANGSTATICANALZYERDIAGNOSTIC_H #ifndef CLANGSTATICANALZYERDIAGNOSTIC_H
#define CLANGSTATICANALZYERDIAGNOSTIC_H #define CLANGSTATICANALZYERDIAGNOSTIC_H
#include <analyzerbase/diagnosticlocation.h>
#include <QList> #include <QList>
#include <QMetaType> #include <QMetaType>
#include <QString> #include <QString>
@@ -26,19 +28,6 @@
namespace ClangStaticAnalyzer { namespace ClangStaticAnalyzer {
namespace Internal { namespace Internal {
class Location
{
public:
Location();
Location(const QString &filePath, int line, int column);
bool isValid() const;
QString filePath;
int line;
int column;
};
class ExplainingStep class ExplainingStep
{ {
public: public:
@@ -48,8 +37,8 @@ public:
QString message; QString message;
QString extendedMessage; QString extendedMessage;
Location location; Analyzer::DiagnosticLocation location;
QList<Location> ranges; QList<Analyzer::DiagnosticLocation> ranges;
int depth; int depth;
}; };
@@ -63,7 +52,7 @@ public:
QString type; QString type;
QString issueContextKind; QString issueContextKind;
QString issueContext; QString issueContext;
Location location; Analyzer::DiagnosticLocation location;
QList<ExplainingStep> explainingSteps; QList<ExplainingStep> explainingSteps;
}; };

View File

@@ -18,6 +18,7 @@
#include "clangstaticanalyzerdiagnosticmodel.h" #include "clangstaticanalyzerdiagnosticmodel.h"
#include "clangstaticanalyzerdiagnosticview.h"
#include "clangstaticanalyzerprojectsettingsmanager.h" #include "clangstaticanalyzerprojectsettingsmanager.h"
#include "clangstaticanalyzerutils.h" #include "clangstaticanalyzerutils.h"
@@ -28,32 +29,53 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QFileInfo> #include <QFileInfo>
#include <cmath>
namespace ClangStaticAnalyzer { namespace ClangStaticAnalyzer {
namespace Internal { namespace Internal {
ClangStaticAnalyzerDiagnosticModel::ClangStaticAnalyzerDiagnosticModel(QObject *parent) class DiagnosticItem : public Utils::TreeItem
: QAbstractListModel(parent)
{ {
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) void ClangStaticAnalyzerDiagnosticModel::addDiagnostics(const QList<Diagnostic> &diagnostics)
{ {
beginInsertRows(QModelIndex(), m_diagnostics.size(), foreach (const Diagnostic &d, diagnostics)
m_diagnostics.size() + diagnostics.size() - 1 ); rootItem()->appendChild(new DiagnosticItem(d));
m_diagnostics += diagnostics;
endInsertRows();
} }
void ClangStaticAnalyzerDiagnosticModel::clear() QList<Diagnostic> ClangStaticAnalyzerDiagnosticModel::diagnostics() const
{ {
beginResetModel(); QList<Diagnostic> diags;
m_diagnostics.clear(); foreach (const Utils::TreeItem * const item, rootItem()->children())
endResetModel(); diags << static_cast<const DiagnosticItem *>(item)->diagnostic();
} return diags;
int ClangStaticAnalyzerDiagnosticModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_diagnostics.count();
} }
static QString createDiagnosticToolTipString(const Diagnostic &diagnostic) static QString createDiagnosticToolTipString(const Diagnostic &diagnostic)
@@ -100,28 +122,162 @@ static QString createDiagnosticToolTipString(const Diagnostic &diagnostic)
return html; 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(); 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(); return QVariant();
}
}
const int row = index.row(); ExplainingStepItem::ExplainingStepItem(const ExplainingStep &step) : m_step(step)
if (row < 0 || row >= m_diagnostics.size()) {
}
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(); 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, bool ClangStaticAnalyzerDiagnosticFilterModel::filterAcceptsRow(int sourceRow,
const QModelIndex &sourceParent) const const QModelIndex &sourceParent) const
{ {
Q_UNUSED(sourceParent); if (sourceParent.isValid())
return true;
const Diagnostic diag = static_cast<ClangStaticAnalyzerDiagnosticModel *>(sourceModel()) const Diagnostic diag = static_cast<ClangStaticAnalyzerDiagnosticModel *>(sourceModel())
->diagnostics().at(sourceRow); ->diagnostics().at(sourceRow);
foreach (const SuppressedDiagnostic &d, m_suppressedDiagnostics) { foreach (const SuppressedDiagnostic &d, m_suppressedDiagnostics) {

View File

@@ -19,12 +19,13 @@
#ifndef CLANGSTATICANALYZERDIAGNOSTICMODEL_H #ifndef CLANGSTATICANALYZERDIAGNOSTICMODEL_H
#define CLANGSTATICANALYZERDIAGNOSTICMODEL_H #define CLANGSTATICANALYZERDIAGNOSTICMODEL_H
#include "clangstaticanalyzerlogfilereader.h" #include "clangstaticanalyzerdiagnostic.h"
#include "clangstaticanalyzerprojectsettings.h" #include "clangstaticanalyzerprojectsettings.h"
#include <analyzerbase/detailederrorview.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/treemodel.h>
#include <QAbstractListModel>
#include <QPointer> #include <QPointer>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
@@ -33,7 +34,7 @@ namespace ProjectExplorer { class Project; }
namespace ClangStaticAnalyzer { namespace ClangStaticAnalyzer {
namespace Internal { namespace Internal {
class ClangStaticAnalyzerDiagnosticModel : public QAbstractListModel class ClangStaticAnalyzerDiagnosticModel : public Utils::TreeModel
{ {
Q_OBJECT Q_OBJECT
@@ -41,15 +42,11 @@ public:
ClangStaticAnalyzerDiagnosticModel(QObject *parent = 0); ClangStaticAnalyzerDiagnosticModel(QObject *parent = 0);
void addDiagnostics(const QList<Diagnostic> &diagnostics); void addDiagnostics(const QList<Diagnostic> &diagnostics);
QList<Diagnostic> diagnostics() const { return m_diagnostics; } QList<Diagnostic> diagnostics() const;
void clear();
// QAbstractListModel interface enum ItemRole {
int rowCount(const QModelIndex &parent = QModelIndex()) const; DiagnosticRole = Analyzer::DetailedErrorView::FullTextRole + 1
QVariant data(const QModelIndex &index, int role) const; };
private:
QList<Diagnostic> m_diagnostics;
}; };
class ClangStaticAnalyzerDiagnosticFilterModel : public QSortFilterProxyModel class ClangStaticAnalyzerDiagnosticFilterModel : public QSortFilterProxyModel

View File

@@ -18,7 +18,6 @@
#include "clangstaticanalyzerdiagnosticview.h" #include "clangstaticanalyzerdiagnosticview.h"
#include "clangstaticanalyzerlogfilereader.h"
#include "clangstaticanalyzerdiagnosticmodel.h" #include "clangstaticanalyzerdiagnosticmodel.h"
#include "clangstaticanalyzerprojectsettings.h" #include "clangstaticanalyzerprojectsettings.h"
#include "clangstaticanalyzerprojectsettingsmanager.h" #include "clangstaticanalyzerprojectsettingsmanager.h"
@@ -28,266 +27,27 @@
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QAction> #include <QAction>
#include <QCoreApplication>
#include <QDebug> #include <QDebug>
#include <QFileInfo>
#include <QLabel>
#include <QVBoxLayout>
using namespace Analyzer; using namespace Analyzer;
namespace {
QLabel *createCommonLabel()
{
QLabel *label = new QLabel;
label->setWordWrap(true);
label->setContentsMargins(0, 0, 0, 0);
label->setMargin(0);
label->setIndent(10);
return label;
}
QString createSummaryText(const ClangStaticAnalyzer::Internal::Diagnostic &diagnostic,
const QPalette &palette)
{
const QColor color = palette.color(QPalette::Text);
const QString linkStyle = QString::fromLatin1("style=\"color:rgba(%1, %2, %3, %4);\"")
.arg(color.red())
.arg(color.green())
.arg(color.blue())
.arg(int(0.7 * 255));
const QString fileName = QFileInfo(diagnostic.location.filePath).fileName();
const QString location = fileName + QLatin1Char(' ')
+ QString::number(diagnostic.location.line);
return QString::fromLatin1("%1&nbsp;&nbsp;<span %3>%2</span>")
.arg(diagnostic.description.toHtmlEscaped(),
location,
linkStyle);
}
QLabel *createSummaryLabel(const ClangStaticAnalyzer::Internal::Diagnostic &diagnostic)
{
QLabel *label = createCommonLabel();
QPalette palette = label->palette();
palette.setBrush(QPalette::Text, palette.highlightedText());
label->setPalette(palette);
label->setText(createSummaryText(diagnostic, palette));
return label;
}
QLabel *createExplainingStepLabel(const QFont &font, bool useAlternateRowPalette)
{
QLabel *label = createCommonLabel();
// Font
QFont fixedPitchFont = font;
fixedPitchFont.setFixedPitch(true);
label->setFont(fixedPitchFont);
// Background
label->setAutoFillBackground(true);
if (useAlternateRowPalette) {
QPalette p = label->palette();
p.setBrush(QPalette::Base, p.alternateBase());
label->setPalette(p);
}
return label;
}
QString createLocationString(const ClangStaticAnalyzer::Internal::Location &location,
bool withMarkup, bool withAbsolutePath)
{
const QString filePath = location.filePath;
const QString lineNumber = QString::number(location.line);
const QString columnNumber = QString::number(location.column - 1);
const QString fileAndLine = (withAbsolutePath ? filePath : QFileInfo(filePath).fileName())
+ QLatin1Char(':') + lineNumber;
if (withMarkup) {
return QLatin1String("in <a href=\"file://")
+ filePath + QLatin1Char(':') + lineNumber + QLatin1Char(':') + columnNumber
+ QLatin1String("\">")
+ fileAndLine
+ QLatin1String("</a>");
} else {
return QLatin1String("in ") + fileAndLine;
}
}
QString createExplainingStepNumberString(int number, bool withMarkup)
{
const int fieldWidth = 2;
const QString result = QString::fromLatin1("%1:").arg(number, fieldWidth);
return withMarkup
? QLatin1String("<code style='white-space:pre'>") + result + QLatin1String("</code>")
: result;
}
QString createExplainingStepToolTipString(const ClangStaticAnalyzer::Internal::ExplainingStep &step)
{
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;
}
QString createExplainingStepString(
const ClangStaticAnalyzer::Internal::ExplainingStep &explainingStep,
int number, bool withMarkup, bool withAbsolutePath)
{
return createExplainingStepNumberString(number, withMarkup)
+ QLatin1Char(' ')
+ (withMarkup
? explainingStep.extendedMessage.toHtmlEscaped()
: explainingStep.extendedMessage)
+ QLatin1Char(' ')
+ createLocationString(explainingStep.location, withMarkup, withAbsolutePath);
}
} // anonymous namespace
namespace ClangStaticAnalyzer { namespace ClangStaticAnalyzer {
namespace Internal { namespace Internal {
ClangStaticAnalyzerDiagnosticDelegate::ClangStaticAnalyzerDiagnosticDelegate(QListView *parent)
: DetailedErrorDelegate(parent)
{
}
DetailedErrorDelegate::SummaryLineInfo ClangStaticAnalyzerDiagnosticDelegate::summaryInfo(
const QModelIndex &index) const
{
const Diagnostic diagnostic = index.data(Qt::UserRole).value<Diagnostic>();
QTC_ASSERT(diagnostic.isValid(), return SummaryLineInfo());
DetailedErrorDelegate::SummaryLineInfo info;
info.errorText = diagnostic.description;
info.errorLocation = createLocationString(diagnostic.location,
/*withMarkup=*/ false,
/*withAbsolutePath=*/ false);
return info;
}
Diagnostic ClangStaticAnalyzerDiagnosticDelegate::getDiagnostic(const QModelIndex &index) const
{
return index.data(Qt::UserRole).value<Diagnostic>();
}
QWidget *ClangStaticAnalyzerDiagnosticDelegate::createDetailsWidget(const QFont &font,
const QModelIndex &index,
QWidget *parent) const
{
QWidget *widget = new QWidget(parent);
const Diagnostic diagnostic = getDiagnostic(index);
if (!diagnostic.isValid())
return widget;
QVBoxLayout *layout = new QVBoxLayout;
// Add summary label
QLabel *summaryLineLabel = createSummaryLabel(diagnostic);
connect(summaryLineLabel, &QLabel::linkActivated,
this, &ClangStaticAnalyzerDiagnosticDelegate::openLinkInEditor);
layout->addWidget(summaryLineLabel);
// Add labels for explaining steps
int explainingStepNumber = 1;
foreach (const ExplainingStep &explainingStep, diagnostic.explainingSteps) {
const QString text = createExplainingStepString(explainingStep,
explainingStepNumber++,
/*withMarkup=*/ true,
/*withAbsolutePath=*/ false);
QLabel *label = createExplainingStepLabel(font, explainingStepNumber % 2 == 0);
label->setParent(widget);
label->setText(text);
label->setToolTip(createExplainingStepToolTipString(explainingStep));
connect(label, &QLabel::linkActivated,
this, &ClangStaticAnalyzerDiagnosticDelegate::openLinkInEditor);
layout->addWidget(label);
}
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
widget->setLayout(layout);
return widget;
}
QString ClangStaticAnalyzerDiagnosticDelegate::textualRepresentation() const
{
QTC_ASSERT(m_detailsIndex.isValid(), return QString());
const Diagnostic diagnostic = getDiagnostic(m_detailsIndex);
QTC_ASSERT(diagnostic.isValid(), return QString());
// Create summary
QString clipboardText = diagnostic.category + QLatin1String(": ") + diagnostic.type;
if (diagnostic.type != diagnostic.description)
clipboardText += QLatin1String(": ") + diagnostic.description;
clipboardText += QLatin1Char('\n');
// Create explaining steps
int explainingStepNumber = 1;
foreach (const ExplainingStep &explainingStep, diagnostic.explainingSteps) {
clipboardText += createExplainingStepString(explainingStep,
explainingStepNumber++,
/*withMarkup=*/ false,
/*withAbsolutePath=*/ true) + QLatin1Char('\n');
}
clipboardText.chop(1); // Remove \n
return clipboardText;
}
ClangStaticAnalyzerDiagnosticView::ClangStaticAnalyzerDiagnosticView(QWidget *parent) ClangStaticAnalyzerDiagnosticView::ClangStaticAnalyzerDiagnosticView(QWidget *parent)
: Analyzer::DetailedErrorView(parent) : Analyzer::DetailedErrorView(parent)
{ {
ClangStaticAnalyzerDiagnosticDelegate *delegate
= new ClangStaticAnalyzerDiagnosticDelegate(this);
setItemDelegate(delegate);
m_suppressAction = new QAction(tr("Suppress this diagnostic"), this); m_suppressAction = new QAction(tr("Suppress this diagnostic"), this);
connect(m_suppressAction, &QAction::triggered, [this](bool) { suppressCurrentDiagnostic(); }); connect(m_suppressAction, &QAction::triggered, [this](bool) { suppressCurrentDiagnostic(); });
} }
void ClangStaticAnalyzerDiagnosticView::suppressCurrentDiagnostic() void ClangStaticAnalyzerDiagnosticView::suppressCurrentDiagnostic()
{ {
const QModelIndexList indexes = selectedIndexes(); const QModelIndexList indexes = selectionModel()->selectedRows();
QTC_ASSERT(indexes.count() == 1, return); QTC_ASSERT(indexes.count() == 1, return);
const Diagnostic diag = static_cast<ClangStaticAnalyzerDiagnosticDelegate *>(itemDelegate()) const Diagnostic diag = model()->data(indexes.first(),
->getDiagnostic(indexes.first()); ClangStaticAnalyzerDiagnosticModel::DiagnosticRole)
.value<Diagnostic>();
QTC_ASSERT(diag.isValid(), return); QTC_ASSERT(diag.isValid(), return);
// If the original project was closed, we work directly on the filter model, otherwise // If the original project was closed, we work directly on the filter model, otherwise

View File

@@ -23,7 +23,6 @@
namespace ClangStaticAnalyzer { namespace ClangStaticAnalyzer {
namespace Internal { namespace Internal {
class Diagnostic;
class ClangStaticAnalyzerDiagnosticView : public Analyzer::DetailedErrorView class ClangStaticAnalyzerDiagnosticView : public Analyzer::DetailedErrorView
{ {
@@ -40,20 +39,6 @@ private:
QAction *m_suppressAction; QAction *m_suppressAction;
}; };
class ClangStaticAnalyzerDiagnosticDelegate : public Analyzer::DetailedErrorDelegate
{
public:
ClangStaticAnalyzerDiagnosticDelegate(QListView *parent);
SummaryLineInfo summaryInfo(const QModelIndex &index) const;
Diagnostic getDiagnostic(const QModelIndex &index) const;
private:
QWidget *createDetailsWidget(const QFont &font, const QModelIndex &index,
QWidget *parent) const;
QString textualRepresentation() const;
};
} // namespace Internal } // namespace Internal
} // namespace ClangStaticAnalyzer } // namespace ClangStaticAnalyzer

View File

@@ -48,8 +48,8 @@ private:
void readDiagnosticsDict(); void readDiagnosticsDict();
QList<ExplainingStep> readPathArray(); QList<ExplainingStep> readPathArray();
ExplainingStep readPathDict(); ExplainingStep readPathDict();
Location readLocationDict(bool elementIsRead = false); Analyzer::DiagnosticLocation readLocationDict(bool elementIsRead = false);
QList<Location> readRangesArray(); QList<Analyzer::DiagnosticLocation> readRangesArray();
QString readString(); QString readString();
QStringList readStringArray(); QStringList readStringArray();
@@ -277,9 +277,9 @@ ExplainingStep ClangStaticAnalyzerLogFileReader::readPathDict()
return explainingStep; return explainingStep;
} }
Location ClangStaticAnalyzerLogFileReader::readLocationDict(bool elementIsRead) Analyzer::DiagnosticLocation ClangStaticAnalyzerLogFileReader::readLocationDict(bool elementIsRead)
{ {
Location location; Analyzer::DiagnosticLocation location;
if (elementIsRead) { if (elementIsRead) {
QTC_ASSERT(m_xml.isStartElement() && m_xml.name() == QLatin1String("dict"), QTC_ASSERT(m_xml.isStartElement() && m_xml.name() == QLatin1String("dict"),
return location); return location);
@@ -310,14 +310,14 @@ Location ClangStaticAnalyzerLogFileReader::readLocationDict(bool elementIsRead)
if (lineOk && columnOk && fileIndexOk) { if (lineOk && columnOk && fileIndexOk) {
QTC_ASSERT(fileIndex < m_referencedFiles.size(), return location); QTC_ASSERT(fileIndex < m_referencedFiles.size(), return location);
location = Location(m_referencedFiles.at(fileIndex), line, column); location = Analyzer::DiagnosticLocation(m_referencedFiles.at(fileIndex), line, column);
} }
return location; return location;
} }
QList<Location> ClangStaticAnalyzerLogFileReader::readRangesArray() QList<Analyzer::DiagnosticLocation> ClangStaticAnalyzerLogFileReader::readRangesArray()
{ {
QList<Location> result; QList<Analyzer::DiagnosticLocation> result;
// It's an array of arrays... // It's an array of arrays...
QTC_ASSERT(m_xml.readNextStartElement() && m_xml.name() == QLatin1String("array"), QTC_ASSERT(m_xml.readNextStartElement() && m_xml.name() == QLatin1String("array"),

View File

@@ -19,6 +19,7 @@
#include "clangstaticanalyzertool.h" #include "clangstaticanalyzertool.h"
#include "clangstaticanalyzerconstants.h" #include "clangstaticanalyzerconstants.h"
#include "clangstaticanalyzerdiagnostic.h"
#include "clangstaticanalyzerdiagnosticmodel.h" #include "clangstaticanalyzerdiagnosticmodel.h"
#include "clangstaticanalyzerdiagnosticview.h" #include "clangstaticanalyzerdiagnosticview.h"
#include "clangstaticanalyzerruncontrol.h" #include "clangstaticanalyzerruncontrol.h"
@@ -88,11 +89,10 @@ QWidget *ClangStaticAnalyzerTool::createWidgets()
// Diagnostic View // Diagnostic View
// //
m_diagnosticView = new ClangStaticAnalyzerDiagnosticView; m_diagnosticView = new ClangStaticAnalyzerDiagnosticView;
m_diagnosticView->setObjectName(QLatin1String("ClangStaticAnalyzerIssuesView"));
m_diagnosticView->setFrameStyle(QFrame::NoFrame); m_diagnosticView->setFrameStyle(QFrame::NoFrame);
m_diagnosticView->setAttribute(Qt::WA_MacShowFocusRect, false); m_diagnosticView->setAttribute(Qt::WA_MacShowFocusRect, false);
m_diagnosticModel = new ClangStaticAnalyzerDiagnosticModel(m_diagnosticView); m_diagnosticModel = new ClangStaticAnalyzerDiagnosticModel(this);
m_diagnosticFilterModel = new ClangStaticAnalyzerDiagnosticFilterModel(m_diagnosticView); m_diagnosticFilterModel = new ClangStaticAnalyzerDiagnosticFilterModel(this);
m_diagnosticFilterModel->setSourceModel(m_diagnosticModel); m_diagnosticFilterModel->setSourceModel(m_diagnosticModel);
m_diagnosticView->setModel(m_diagnosticFilterModel); m_diagnosticView->setModel(m_diagnosticFilterModel);
m_diagnosticView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); m_diagnosticView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
@@ -302,7 +302,7 @@ void ClangStaticAnalyzerTool::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->rowCount(); 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);

View File

@@ -72,7 +72,7 @@ private:
ClangStaticAnalyzerDiagnosticModel *m_diagnosticModel; ClangStaticAnalyzerDiagnosticModel *m_diagnosticModel;
ClangStaticAnalyzerDiagnosticFilterModel *m_diagnosticFilterModel; ClangStaticAnalyzerDiagnosticFilterModel *m_diagnosticFilterModel;
Analyzer::DetailedErrorView *m_diagnosticView; ClangStaticAnalyzerDiagnosticView *m_diagnosticView;
QAction *m_goBack; QAction *m_goBack;
QAction *m_goNext; QAction *m_goNext;

View File

@@ -70,7 +70,7 @@ QString clangExecutable(const QString &fileNameOrPath, bool *isValid)
return executable; return executable;
} }
QString createFullLocationString(const ClangStaticAnalyzer::Internal::Location &location) QString createFullLocationString(const Analyzer::DiagnosticLocation &location)
{ {
const QString filePath = location.filePath; const QString filePath = location.filePath;
const QString lineNumber = QString::number(location.line); const QString lineNumber = QString::number(location.line);

View File

@@ -27,17 +27,17 @@ QT_BEGIN_NAMESPACE
class QString; class QString;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace Analyzer { class DiagnosticLocation; }
namespace ClangStaticAnalyzer { namespace ClangStaticAnalyzer {
namespace Internal { namespace Internal {
class Location;
bool isClangExecutableUsable(const QString &filePath, QString *errorMessage = 0); bool isClangExecutableUsable(const QString &filePath, QString *errorMessage = 0);
QString clangExecutable(const QString &fileNameOrPath, bool *isValid); QString clangExecutable(const QString &fileNameOrPath, bool *isValid);
QString clangExecutableFromSettings(Core::Id toolchainType, bool *isValid); QString clangExecutableFromSettings(Core::Id toolchainType, bool *isValid);
QString createFullLocationString(const ClangStaticAnalyzer::Internal::Location &location); QString createFullLocationString(const Analyzer::DiagnosticLocation &location);
} // namespace Internal } // namespace Internal
} // namespace ClangStaticAnalyzer } // namespace ClangStaticAnalyzer

View File

@@ -2,6 +2,7 @@ import qbs
QtcAutotest { QtcAutotest {
Depends { name: "Qt.widgets" } Depends { name: "Qt.widgets" }
Depends { name: "AnalyzerBase" }
Depends { name: "Utils" } Depends { name: "Utils" }
property path pluginDir: "../../" property path pluginDir: "../../"

View File

@@ -24,38 +24,18 @@
enum { debug = 0 }; enum { debug = 0 };
namespace ClangStaticAnalyzer { using namespace Analyzer;
namespace Internal {
static bool operator==(const Location &first, const Location &second)
{
return first.filePath == second.filePath
&& first.line == second.line
&& first.column == second.column;
}
} // namespace Internal
} // namespace ClangStaticAnalyzer
using namespace ClangStaticAnalyzer::Internal; using namespace ClangStaticAnalyzer::Internal;
namespace { namespace {
QDebug operator<<(QDebug dbg, const Location &location)
{
dbg.nospace() << "Location(" << location.filePath << ", "
<< location.line << ", "
<< location.column << ')';
return dbg.space();
}
QDebug operator<<(QDebug dbg, const ExplainingStep &step) QDebug operator<<(QDebug dbg, const ExplainingStep &step)
{ {
dbg << '\n' dbg << '\n'
<< " ExplainingStep\n" << " ExplainingStep\n"
<< " location:" << step.location << '\n' << " location:" << step.location << '\n'
<< " ranges:\n"; << " ranges:\n";
foreach (const Location &location, step.ranges) foreach (const DiagnosticLocation &location, step.ranges)
dbg << " " << location << '\n'; dbg << " " << location << '\n';
dbg dbg
<< " message:" << step.message << '\n' << " message:" << step.message << '\n'
@@ -148,23 +128,23 @@ void ClangStaticAnalyzerLogFileReaderTest::readFileWithDiagnostics()
QCOMPARE(d1.type, d1.description); QCOMPARE(d1.type, d1.description);
QCOMPARE(d1.issueContextKind, QLatin1String("function")); QCOMPARE(d1.issueContextKind, QLatin1String("function"));
QCOMPARE(d1.issueContext, QLatin1String("test")); QCOMPARE(d1.issueContext, QLatin1String("test"));
QCOMPARE(d1.location, Location(commonPath, 36, 3)); QCOMPARE(d1.location, DiagnosticLocation(commonPath, 36, 3));
QCOMPARE(d1.explainingSteps.size(), 2); QCOMPARE(d1.explainingSteps.size(), 2);
const ExplainingStep step1 = d1.explainingSteps.at(0); const ExplainingStep step1 = d1.explainingSteps.at(0);
QCOMPARE(step1.location, Location(commonPath, 35, 3)); QCOMPARE(step1.location, DiagnosticLocation(commonPath, 35, 3));
QCOMPARE(step1.ranges.size(), 2); QCOMPARE(step1.ranges.size(), 2);
QCOMPARE(step1.ranges.at(0), Location(commonPath, 35, 3)); QCOMPARE(step1.ranges.at(0), DiagnosticLocation(commonPath, 35, 3));
QCOMPARE(step1.ranges.at(1), Location(commonPath, 35, 9)); QCOMPARE(step1.ranges.at(1), DiagnosticLocation(commonPath, 35, 9));
QCOMPARE(step1.depth, 0); QCOMPARE(step1.depth, 0);
QCOMPARE(step1.message, QLatin1String("Null pointer value stored to 'foo'")); QCOMPARE(step1.message, QLatin1String("Null pointer value stored to 'foo'"));
QCOMPARE(step1.extendedMessage, step1.message); QCOMPARE(step1.extendedMessage, step1.message);
const ExplainingStep step2 = d1.explainingSteps.at(1); const ExplainingStep step2 = d1.explainingSteps.at(1);
QCOMPARE(step2.location, Location(commonPath, 36, 3)); QCOMPARE(step2.location, DiagnosticLocation(commonPath, 36, 3));
QCOMPARE(step2.ranges.size(), 2); QCOMPARE(step2.ranges.size(), 2);
QCOMPARE(step2.ranges.at(0), Location(commonPath, 36, 3)); QCOMPARE(step2.ranges.at(0), DiagnosticLocation(commonPath, 36, 3));
QCOMPARE(step2.ranges.at(1), Location(commonPath, 36, 5)); QCOMPARE(step2.ranges.at(1), DiagnosticLocation(commonPath, 36, 5));
QCOMPARE(step2.depth, 0); QCOMPARE(step2.depth, 0);
QCOMPARE(step2.message, QLatin1String("Called function pointer is null (null dereference)")); QCOMPARE(step2.message, QLatin1String("Called function pointer is null (null dereference)"));
QCOMPARE(step2.extendedMessage, step2.message); QCOMPARE(step2.extendedMessage, step2.message);

View File

@@ -1,4 +1,5 @@
QTC_LIB_DEPENDS += utils QTC_LIB_DEPENDS += utils
QTC_PLUGIN_DEPENDS += analyzerbase
isEmpty(IDE_SOURCE_TREE): IDE_SOURCE_TREE=$$(QTC_SOURCE) isEmpty(IDE_SOURCE_TREE): IDE_SOURCE_TREE=$$(QTC_SOURCE)
isEmpty(IDE_BUILD_TREE): IDE_BUILD_TREE=$$(QTC_BUILD) isEmpty(IDE_BUILD_TREE): IDE_BUILD_TREE=$$(QTC_BUILD)