ClangTools: Allow applying fixits

Add a new column to the view that allows to check diagnostics with
fixits. The checked fixits can then be applied with the also new "Apply
Fixits" button in the toolbar.

Some corner cases are not yet handled:
 * File is open in editor
 * File changed in the mean time

Change-Id: I3d3f353a4150699a0d082f2a4348e331a4213bcf
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Nikolai Kosjar
2018-05-15 14:31:48 +02:00
parent 1773b4d8b5
commit 26b09af277
10 changed files with 126 additions and 25 deletions

View File

@@ -50,10 +50,13 @@
#include <projectexplorer/target.h>
#include <projectexplorer/session.h>
#include <texteditor/refactoringchanges.h>
#include <utils/fancylineedit.h>
#include <utils/utilsicons.h>
#include <QAction>
#include <QToolButton>
using namespace Core;
using namespace CppTools;
@@ -66,6 +69,43 @@ namespace Internal {
static ClangTidyClazyTool *s_instance;
static void applyFixits(const QVector<Diagnostic> &diagnostics)
{
TextEditor::RefactoringChanges changes;
QMap<QString, TextEditor::RefactoringFilePtr> refactoringFiles;
// Create refactoring files and changes
for (const Diagnostic &diagnostic : diagnostics) {
const auto filePath = diagnostic.location.filePath;
QTC_ASSERT(!filePath.isEmpty(), continue);
// Get or create refactoring file
TextEditor::RefactoringFilePtr refactoringFile = refactoringFiles.value(filePath);
if (!refactoringFile) {
refactoringFile = changes.file(filePath);
refactoringFiles.insert(filePath, refactoringFile);
}
// Append changes
ChangeSet cs = refactoringFile->changeSet();
for (const ExplainingStep &step : diagnostic.explainingSteps) {
if (step.isFixIt) {
const Debugger::DiagnosticLocation start = step.ranges.first();
const Debugger::DiagnosticLocation end = step.ranges.last();
cs.replace(refactoringFile->position(start.line, start.column),
refactoringFile->position(end.line, end.column), step.message);
}
}
refactoringFile->setChangeSet(cs);
}
// Apply refactoring file changes
for (TextEditor::RefactoringFilePtr refactoringFile : refactoringFiles.values())
refactoringFile->apply();
}
ClangTidyClazyTool::ClangTidyClazyTool()
: ClangTool("Clang-Tidy and Clazy")
{
@@ -118,6 +158,22 @@ ClangTidyClazyTool::ClangTidyClazyTool()
QRegExp(filter, Qt::CaseSensitive, QRegExp::WildcardUnix));
});
// Apply fixits button
m_applyFixitsButton = new QToolButton;
m_applyFixitsButton->setText(tr("Apply Fixits"));
connect(m_applyFixitsButton, &QToolButton::clicked, [this]() {
QVector<Diagnostic> diagnosticsWithFixits;
const int count = m_diagnosticModel->rootItem()->childCount();
for (int i = 0; i < count; ++i) {
auto *item = static_cast<DiagnosticItem *>(m_diagnosticModel->rootItem()->childAt(i));
if (item->applyFixits())
diagnosticsWithFixits += item->diagnostic();
}
applyFixits(diagnosticsWithFixits);
});
ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER);
const QString toolTip = tr("Clang-Tidy and Clazy use a customized Clang executable from the "
"Clang project to search for errors and warnings.");
@@ -143,6 +199,7 @@ ClangTidyClazyTool::ClangTidyClazyTool()
tidyClazyToolbar.addAction(m_goBack);
tidyClazyToolbar.addAction(m_goNext);
tidyClazyToolbar.addWidget(m_filterLineEdit);
tidyClazyToolbar.addWidget(m_applyFixitsButton);
Debugger::registerToolbar(ClangTidyClazyPerspectiveId, tidyClazyToolbar);
updateRunActions();