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:
@@ -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)
|
||||||
{
|
{
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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) {
|
||||||
|
@@ -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
|
||||||
|
@@ -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 <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
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
@@ -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"),
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
@@ -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);
|
||||||
|
@@ -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
|
||||||
|
@@ -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: "../../"
|
||||||
|
@@ -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);
|
||||||
|
@@ -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)
|
||||||
|
Reference in New Issue
Block a user