2014-09-25 11:11:58 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-14 10:59:10 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2014-09-25 11:11:58 +02:00
|
|
|
**
|
2016-01-14 10:59:10 +01:00
|
|
|
** This file is part of Qt Creator.
|
2014-09-25 11:11:58 +02:00
|
|
|
**
|
2016-01-14 10:59:10 +01:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
2014-09-25 11:11:58 +02:00
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-14 10:59:10 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2014-09-25 11:11:58 +02:00
|
|
|
**
|
2016-01-14 10:59:10 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2014-09-25 11:11:58 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2018-01-17 15:08:30 +01:00
|
|
|
#include "clangtoolsdiagnosticmodel.h"
|
2014-09-25 11:11:58 +02:00
|
|
|
|
2018-05-08 17:33:29 +02:00
|
|
|
#include "clangtoolsdiagnosticview.h"
|
2018-05-08 16:47:27 +02:00
|
|
|
#include "clangtoolsprojectsettings.h"
|
2018-01-17 15:08:30 +01:00
|
|
|
#include "clangtoolsutils.h"
|
2014-09-25 11:11:58 +02:00
|
|
|
|
2015-02-19 18:08:38 +01:00
|
|
|
#include <projectexplorer/project.h>
|
|
|
|
|
#include <projectexplorer/session.h>
|
|
|
|
|
#include <utils/qtcassert.h>
|
2018-01-17 15:08:30 +01:00
|
|
|
#include <utils/utilsicons.h>
|
2015-02-19 18:08:38 +01:00
|
|
|
|
|
|
|
|
#include <QFileInfo>
|
2014-09-25 11:11:58 +02:00
|
|
|
|
2015-06-19 15:37:16 +02:00
|
|
|
#include <cmath>
|
|
|
|
|
|
2018-03-14 12:58:12 +01:00
|
|
|
namespace ClangTools {
|
2014-09-25 11:11:58 +02:00
|
|
|
namespace Internal {
|
|
|
|
|
|
2015-06-19 15:37:16 +02:00
|
|
|
class ExplainingStepItem : public Utils::TreeItem
|
2014-09-25 11:11:58 +02:00
|
|
|
{
|
2015-06-19 15:37:16 +02:00
|
|
|
public:
|
|
|
|
|
ExplainingStepItem(const ExplainingStep &step);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
QVariant data(int column, int role) const override;
|
|
|
|
|
|
|
|
|
|
const ExplainingStep m_step;
|
|
|
|
|
};
|
|
|
|
|
|
2018-01-17 15:08:30 +01:00
|
|
|
ClangToolsDiagnosticModel::ClangToolsDiagnosticModel(QObject *parent)
|
2016-06-24 09:36:42 +02:00
|
|
|
: Utils::TreeModel<>(parent)
|
2015-06-19 15:37:16 +02:00
|
|
|
{
|
2018-05-16 14:49:12 +02:00
|
|
|
setHeader({tr("Issue"), tr("Location"), tr("Fixit Status")});
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
2018-01-17 15:08:30 +01:00
|
|
|
void ClangToolsDiagnosticModel::addDiagnostics(const QList<Diagnostic> &diagnostics)
|
2014-09-25 11:11:58 +02:00
|
|
|
{
|
2018-05-16 14:49:12 +02:00
|
|
|
const auto onFixitStatusChanged = [this](FixitStatus newStatus) {
|
|
|
|
|
if (newStatus == FixitStatus::Scheduled)
|
|
|
|
|
++m_fixItsToApplyCount;
|
|
|
|
|
else
|
|
|
|
|
--m_fixItsToApplyCount;
|
2018-05-16 13:07:10 +02:00
|
|
|
emit fixItsToApplyCountChanged(m_fixItsToApplyCount);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (const Diagnostic &d : diagnostics)
|
2018-05-16 14:49:12 +02:00
|
|
|
rootItem()->appendChild(new DiagnosticItem(d, onFixitStatusChanged));
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
2018-01-17 15:08:30 +01:00
|
|
|
QList<Diagnostic> ClangToolsDiagnosticModel::diagnostics() const
|
2014-09-25 11:11:58 +02:00
|
|
|
{
|
2015-06-19 15:37:16 +02:00
|
|
|
QList<Diagnostic> diags;
|
2017-02-07 08:53:00 +01:00
|
|
|
for (const Utils::TreeItem * const item : *rootItem())
|
2015-06-19 15:37:16 +02:00
|
|
|
diags << static_cast<const DiagnosticItem *>(item)->diagnostic();
|
|
|
|
|
return diags;
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
2018-05-29 12:30:59 +02:00
|
|
|
int ClangToolsDiagnosticModel::diagnosticsCount() const
|
|
|
|
|
{
|
|
|
|
|
return rootItem()->childCount();
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-25 11:11:58 +02:00
|
|
|
static QString createDiagnosticToolTipString(const Diagnostic &diagnostic)
|
|
|
|
|
{
|
|
|
|
|
typedef QPair<QString, QString> StringPair;
|
|
|
|
|
QList<StringPair> lines;
|
|
|
|
|
|
|
|
|
|
if (!diagnostic.category.isEmpty()) {
|
|
|
|
|
lines << qMakePair(
|
2018-03-14 12:58:12 +01:00
|
|
|
QCoreApplication::translate("ClangTools::Diagnostic", "Category:"),
|
2014-11-14 16:32:36 +01:00
|
|
|
diagnostic.category.toHtmlEscaped());
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!diagnostic.type.isEmpty()) {
|
|
|
|
|
lines << qMakePair(
|
2018-03-14 12:58:12 +01:00
|
|
|
QCoreApplication::translate("ClangTools::Diagnostic", "Type:"),
|
2014-11-14 16:32:36 +01:00
|
|
|
diagnostic.type.toHtmlEscaped());
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
2018-05-22 15:35:12 +02:00
|
|
|
if (!diagnostic.description.isEmpty()) {
|
|
|
|
|
lines << qMakePair(
|
|
|
|
|
QCoreApplication::translate("ClangTools::Diagnostic", "Description:"),
|
|
|
|
|
diagnostic.description.toHtmlEscaped());
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-25 11:11:58 +02:00
|
|
|
if (!diagnostic.issueContext.isEmpty() && !diagnostic.issueContextKind.isEmpty()) {
|
|
|
|
|
lines << qMakePair(
|
2018-03-14 12:58:12 +01:00
|
|
|
QCoreApplication::translate("ClangTools::Diagnostic", "Context:"),
|
2014-11-14 16:32:36 +01:00
|
|
|
diagnostic.issueContextKind.toHtmlEscaped() + QLatin1Char(' ')
|
|
|
|
|
+ diagnostic.issueContext.toHtmlEscaped());
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lines << qMakePair(
|
2018-03-14 12:58:12 +01:00
|
|
|
QCoreApplication::translate("ClangTools::Diagnostic", "Location:"),
|
2014-09-25 11:11:58 +02:00
|
|
|
createFullLocationString(diagnostic.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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-19 15:37:16 +02:00
|
|
|
static QString createExplainingStepToolTipString(const ExplainingStep &step)
|
2014-09-25 11:11:58 +02:00
|
|
|
{
|
2015-06-19 15:37:16 +02:00
|
|
|
if (step.message == step.extendedMessage)
|
|
|
|
|
return createFullLocationString(step.location);
|
|
|
|
|
|
|
|
|
|
typedef QPair<QString, QString> StringPair;
|
|
|
|
|
QList<StringPair> lines;
|
|
|
|
|
|
|
|
|
|
if (!step.message.isEmpty()) {
|
|
|
|
|
lines << qMakePair(
|
2018-03-14 12:58:12 +01:00
|
|
|
QCoreApplication::translate("ClangTools::ExplainingStep", "Message:"),
|
2015-06-19 15:37:16 +02:00
|
|
|
step.message.toHtmlEscaped());
|
|
|
|
|
}
|
|
|
|
|
if (!step.extendedMessage.isEmpty()) {
|
|
|
|
|
lines << qMakePair(
|
2018-03-14 12:58:12 +01:00
|
|
|
QCoreApplication::translate("ClangTools::ExplainingStep", "Extended message:"),
|
2015-06-19 15:37:16 +02:00
|
|
|
step.extendedMessage.toHtmlEscaped());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lines << qMakePair(
|
2018-03-14 12:58:12 +01:00
|
|
|
QCoreApplication::translate("ClangTools::ExplainingStep", "Location:"),
|
2015-06-19 15:37:16 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-02 13:57:37 +01:00
|
|
|
static QString createLocationString(const Debugger::DiagnosticLocation &location)
|
2015-06-19 15:37:16 +02:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-25 11:11:58 +02:00
|
|
|
|
2018-05-16 14:49:12 +02:00
|
|
|
DiagnosticItem::DiagnosticItem(const Diagnostic &diag, const OnFixitStatusChanged &onFixitStatusChanged)
|
2018-05-16 13:07:10 +02:00
|
|
|
: m_diagnostic(diag)
|
2018-05-16 14:49:12 +02:00
|
|
|
, m_onFixitStatusChanged(onFixitStatusChanged)
|
2015-06-19 15:37:16 +02:00
|
|
|
{
|
2018-05-16 14:49:12 +02:00
|
|
|
if (diag.hasFixits)
|
|
|
|
|
m_fixitStatus = FixitStatus::NotScheduled;
|
|
|
|
|
|
2015-06-19 15:37:16 +02:00
|
|
|
// 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));
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-24 09:03:44 +02:00
|
|
|
DiagnosticItem::~DiagnosticItem()
|
|
|
|
|
{
|
|
|
|
|
setFixitOperations(ReplacementOperations());
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-15 14:31:48 +02:00
|
|
|
Qt::ItemFlags DiagnosticItem::flags(int column) const
|
|
|
|
|
{
|
2018-05-16 13:24:40 +02:00
|
|
|
const Qt::ItemFlags itemFlags = TreeItem::flags(column);
|
|
|
|
|
if (column == DiagnosticView::FixItColumn) {
|
2018-05-16 14:49:12 +02:00
|
|
|
switch (m_fixitStatus) {
|
|
|
|
|
case FixitStatus::NotAvailable:
|
|
|
|
|
case FixitStatus::Applied:
|
|
|
|
|
case FixitStatus::FailedToApply:
|
|
|
|
|
case FixitStatus::Invalidated:
|
2018-05-16 13:24:40 +02:00
|
|
|
return itemFlags & ~Qt::ItemIsEnabled;
|
2018-05-16 14:49:12 +02:00
|
|
|
case FixitStatus::Scheduled:
|
|
|
|
|
case FixitStatus::NotScheduled:
|
|
|
|
|
return itemFlags | Qt::ItemIsUserCheckable;
|
|
|
|
|
}
|
2018-05-16 13:24:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return itemFlags;
|
2018-05-15 14:31:48 +02:00
|
|
|
}
|
|
|
|
|
|
2018-01-17 15:08:30 +01:00
|
|
|
static QVariant iconData(const QString &type)
|
|
|
|
|
{
|
|
|
|
|
if (type == "warning")
|
|
|
|
|
return Utils::Icons::CODEMODEL_WARNING.icon();
|
|
|
|
|
if (type == "error")
|
|
|
|
|
return Utils::Icons::CODEMODEL_ERROR.icon();
|
|
|
|
|
if (type == "note")
|
|
|
|
|
return Utils::Icons::BOOKMARK.icon();
|
|
|
|
|
if (type == "fix-it")
|
|
|
|
|
return Utils::Icons::CODEMODEL_FIXIT.icon();
|
|
|
|
|
return QVariant();
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-19 15:37:16 +02:00
|
|
|
QVariant DiagnosticItem::data(int column, int role) const
|
|
|
|
|
{
|
2016-03-02 13:57:37 +01:00
|
|
|
if (column == Debugger::DetailedErrorView::LocationColumn)
|
2018-05-16 10:41:34 +02:00
|
|
|
return Debugger::DetailedErrorView::locationData(role, m_diagnostic.location);
|
2014-09-25 11:11:58 +02:00
|
|
|
|
2018-05-15 14:31:48 +02:00
|
|
|
if (column == DiagnosticView::FixItColumn) {
|
2018-05-16 14:49:12 +02:00
|
|
|
if (role == Qt::CheckStateRole) {
|
|
|
|
|
switch (m_fixitStatus) {
|
|
|
|
|
case FixitStatus::NotAvailable:
|
|
|
|
|
case FixitStatus::NotScheduled:
|
|
|
|
|
case FixitStatus::Invalidated:
|
|
|
|
|
case FixitStatus::Applied:
|
|
|
|
|
case FixitStatus::FailedToApply:
|
|
|
|
|
return Qt::Unchecked;
|
|
|
|
|
case FixitStatus::Scheduled:
|
|
|
|
|
return Qt::Checked;
|
|
|
|
|
}
|
|
|
|
|
} else if (role == Qt::DisplayRole) {
|
|
|
|
|
switch (m_fixitStatus) {
|
|
|
|
|
case FixitStatus::NotAvailable:
|
|
|
|
|
return ClangToolsDiagnosticModel::tr("No Fixits");
|
|
|
|
|
case FixitStatus::NotScheduled:
|
|
|
|
|
return ClangToolsDiagnosticModel::tr("Not Scheduled");
|
|
|
|
|
case FixitStatus::Invalidated:
|
|
|
|
|
return ClangToolsDiagnosticModel::tr("Invalidated");
|
|
|
|
|
case FixitStatus::Scheduled:
|
|
|
|
|
return ClangToolsDiagnosticModel::tr("Scheduled");
|
|
|
|
|
case FixitStatus::FailedToApply:
|
|
|
|
|
return ClangToolsDiagnosticModel::tr("Failed to Apply");
|
|
|
|
|
case FixitStatus::Applied:
|
|
|
|
|
return ClangToolsDiagnosticModel::tr("Applied");
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-15 14:31:48 +02:00
|
|
|
return QVariant();
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-19 15:37:16 +02:00
|
|
|
// DiagnosticColumn
|
|
|
|
|
switch (role) {
|
2016-03-02 13:57:37 +01:00
|
|
|
case Debugger::DetailedErrorView::FullTextRole:
|
2015-06-19 15:37:16 +02:00
|
|
|
return fullText(m_diagnostic);
|
2018-01-17 15:08:30 +01:00
|
|
|
case ClangToolsDiagnosticModel::DiagnosticRole:
|
2015-06-19 15:37:16 +02:00
|
|
|
return QVariant::fromValue(m_diagnostic);
|
|
|
|
|
case Qt::DisplayRole:
|
|
|
|
|
return m_diagnostic.description;
|
|
|
|
|
case Qt::ToolTipRole:
|
|
|
|
|
return createDiagnosticToolTipString(m_diagnostic);
|
2018-01-17 15:08:30 +01:00
|
|
|
case Qt::DecorationRole:
|
|
|
|
|
return iconData(m_diagnostic.type);
|
2015-06-19 15:37:16 +02:00
|
|
|
default:
|
2014-09-25 11:11:58 +02:00
|
|
|
return QVariant();
|
2015-06-19 15:37:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
2014-09-25 11:11:58 +02:00
|
|
|
|
2018-05-15 14:31:48 +02:00
|
|
|
bool DiagnosticItem::setData(int column, const QVariant &data, int role)
|
|
|
|
|
{
|
|
|
|
|
if (column == DiagnosticView::FixItColumn && role == Qt::CheckStateRole) {
|
2018-06-21 13:53:41 +02:00
|
|
|
if (m_fixitStatus != FixitStatus::Scheduled && m_fixitStatus != FixitStatus::NotScheduled)
|
|
|
|
|
return false;
|
|
|
|
|
|
2018-05-16 14:49:12 +02:00
|
|
|
const FixitStatus newStatus = data.value<Qt::CheckState>() == Qt::Checked
|
|
|
|
|
? FixitStatus::Scheduled
|
|
|
|
|
: FixitStatus::NotScheduled;
|
|
|
|
|
|
|
|
|
|
setFixItStatus(newStatus);
|
2018-05-15 14:31:48 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Utils::TreeItem::setData(column, data, role);
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-16 14:49:12 +02:00
|
|
|
void DiagnosticItem::setFixItStatus(const FixitStatus &status)
|
|
|
|
|
{
|
|
|
|
|
const FixitStatus oldStatus = m_fixitStatus;
|
|
|
|
|
m_fixitStatus = status;
|
|
|
|
|
update();
|
|
|
|
|
if (m_onFixitStatusChanged && status != oldStatus)
|
|
|
|
|
m_onFixitStatusChanged(status);
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-24 09:03:44 +02:00
|
|
|
void DiagnosticItem::setFixitOperations(const ReplacementOperations &replacements)
|
2018-05-16 14:49:12 +02:00
|
|
|
{
|
2018-05-24 09:03:44 +02:00
|
|
|
qDeleteAll(m_fixitOperations);
|
|
|
|
|
m_fixitOperations = replacements;
|
2018-05-16 14:49:12 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-19 15:37:16 +02:00
|
|
|
ExplainingStepItem::ExplainingStepItem(const ExplainingStep &step) : m_step(step)
|
|
|
|
|
{
|
|
|
|
|
}
|
2014-09-25 11:11:58 +02:00
|
|
|
|
2015-06-19 15:37:16 +02:00
|
|
|
QVariant ExplainingStepItem::data(int column, int role) const
|
|
|
|
|
{
|
2016-03-02 13:57:37 +01:00
|
|
|
if (column == Debugger::DetailedErrorView::LocationColumn)
|
2018-05-16 10:41:34 +02:00
|
|
|
return Debugger::DetailedErrorView::locationData(role, m_step.location);
|
2014-09-25 11:11:58 +02:00
|
|
|
|
2018-05-15 14:31:48 +02:00
|
|
|
if (column == DiagnosticView::FixItColumn)
|
|
|
|
|
return QVariant();
|
|
|
|
|
|
2015-06-19 15:37:16 +02:00
|
|
|
// DiagnosticColumn
|
|
|
|
|
switch (role) {
|
2016-03-02 13:57:37 +01:00
|
|
|
case Debugger::DetailedErrorView::FullTextRole:
|
2015-06-19 15:37:16 +02:00
|
|
|
return fullText(static_cast<DiagnosticItem *>(parent())->diagnostic());
|
2018-01-17 15:08:30 +01:00
|
|
|
case ClangToolsDiagnosticModel::DiagnosticRole:
|
2015-06-19 15:37:16 +02:00
|
|
|
return QVariant::fromValue(static_cast<DiagnosticItem *>(parent())->diagnostic());
|
|
|
|
|
case Qt::DisplayRole: {
|
2016-07-27 18:08:56 +02:00
|
|
|
const int row = indexInParent() + 1;
|
2016-07-06 13:38:00 +02:00
|
|
|
const int padding = static_cast<int>(std::log10(parent()->childCount()))
|
2015-06-19 15:37:16 +02:00
|
|
|
- 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);
|
2018-01-17 15:08:30 +01:00
|
|
|
case Qt::DecorationRole:
|
|
|
|
|
return (m_step.message.startsWith("fix-it:")) ? iconData("fix-it") : QVariant();
|
2015-06-19 15:37:16 +02:00
|
|
|
default:
|
|
|
|
|
return QVariant();
|
|
|
|
|
}
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-19 18:08:38 +01:00
|
|
|
|
2018-05-08 17:33:29 +02:00
|
|
|
DiagnosticFilterModel::DiagnosticFilterModel(QObject *parent)
|
2015-02-19 18:08:38 +01:00
|
|
|
: QSortFilterProxyModel(parent)
|
|
|
|
|
{
|
|
|
|
|
// So that when a user closes and re-opens a project and *then* clicks "Suppress",
|
|
|
|
|
// we enter that information into the project settings.
|
|
|
|
|
connect(ProjectExplorer::SessionManager::instance(),
|
|
|
|
|
&ProjectExplorer::SessionManager::projectAdded, this,
|
|
|
|
|
[this](ProjectExplorer::Project *project) {
|
|
|
|
|
if (!m_project && project->projectDirectory() == m_lastProjectDirectory)
|
|
|
|
|
setProject(project);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-08 17:33:29 +02:00
|
|
|
void DiagnosticFilterModel::setProject(ProjectExplorer::Project *project)
|
2015-02-19 18:08:38 +01:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(project, return);
|
|
|
|
|
if (m_project) {
|
2018-05-08 16:47:27 +02:00
|
|
|
disconnect(ClangToolsProjectSettingsManager::getSettings(m_project),
|
|
|
|
|
&ClangToolsProjectSettings::suppressedDiagnosticsChanged, this,
|
2018-05-08 17:33:29 +02:00
|
|
|
&DiagnosticFilterModel::handleSuppressedDiagnosticsChanged);
|
2015-02-19 18:08:38 +01:00
|
|
|
}
|
|
|
|
|
m_project = project;
|
|
|
|
|
m_lastProjectDirectory = m_project->projectDirectory();
|
2018-05-08 16:47:27 +02:00
|
|
|
connect(ClangToolsProjectSettingsManager::getSettings(m_project),
|
|
|
|
|
&ClangToolsProjectSettings::suppressedDiagnosticsChanged,
|
2018-05-08 17:33:29 +02:00
|
|
|
this, &DiagnosticFilterModel::handleSuppressedDiagnosticsChanged);
|
2015-02-19 18:08:38 +01:00
|
|
|
handleSuppressedDiagnosticsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-08 17:33:29 +02:00
|
|
|
void DiagnosticFilterModel::addSuppressedDiagnostic(
|
2015-02-19 18:08:38 +01:00
|
|
|
const SuppressedDiagnostic &diag)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(!m_project, return);
|
|
|
|
|
m_suppressedDiagnostics << diag;
|
|
|
|
|
invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-08 17:33:29 +02:00
|
|
|
bool DiagnosticFilterModel::filterAcceptsRow(int sourceRow,
|
2015-02-19 18:08:38 +01:00
|
|
|
const QModelIndex &sourceParent) const
|
|
|
|
|
{
|
2018-05-15 11:27:14 +02:00
|
|
|
// Avoid filtering child diagnostics / explaining steps.
|
2015-06-19 15:37:16 +02:00
|
|
|
if (sourceParent.isValid())
|
|
|
|
|
return true;
|
2018-05-15 11:27:14 +02:00
|
|
|
|
|
|
|
|
// Is the diagnostic suppressed?
|
2018-05-29 12:30:59 +02:00
|
|
|
auto model = static_cast<ClangToolsDiagnosticModel *>(sourceModel());
|
|
|
|
|
auto item = static_cast<DiagnosticItem *>(model->rootItem()->childAt(sourceRow));
|
|
|
|
|
const Diagnostic &diag = item->diagnostic();
|
2015-02-19 18:08:38 +01:00
|
|
|
foreach (const SuppressedDiagnostic &d, m_suppressedDiagnostics) {
|
|
|
|
|
if (d.description != diag.description)
|
|
|
|
|
continue;
|
|
|
|
|
QString filePath = d.filePath.toString();
|
|
|
|
|
QFileInfo fi(filePath);
|
|
|
|
|
if (fi.isRelative())
|
|
|
|
|
filePath = m_lastProjectDirectory.toString() + QLatin1Char('/') + filePath;
|
|
|
|
|
if (filePath == diag.location.filePath)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-05-15 11:27:14 +02:00
|
|
|
|
|
|
|
|
// Does the diagnostic match the filter?
|
|
|
|
|
if (diag.description.contains(filterRegExp()))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
2015-02-19 18:08:38 +01:00
|
|
|
}
|
|
|
|
|
|
2018-05-08 17:33:29 +02:00
|
|
|
void DiagnosticFilterModel::handleSuppressedDiagnosticsChanged()
|
2015-02-19 18:08:38 +01:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_project, return);
|
|
|
|
|
m_suppressedDiagnostics
|
2018-05-08 16:47:27 +02:00
|
|
|
= ClangToolsProjectSettingsManager::getSettings(m_project)->suppressedDiagnostics();
|
2015-02-19 18:08:38 +01:00
|
|
|
invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-25 11:11:58 +02:00
|
|
|
} // namespace Internal
|
2018-03-14 12:58:12 +01:00
|
|
|
} // namespace ClangTools
|