ClangTools: Apply indention/formatting after fix-its

Fix-its do not follow the current formatting style therefore
apply indention/formatting by using indenter.

This change will work best when ClangFormat plugin is
enabled to not only reindent line but also format it.

Task-number: QTCREATORBUG-21448
Change-Id: I8bcafcf49f3118aff7840326547e7a24052469b2
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-11-09 11:07:54 +01:00
parent 781dadc94a
commit 97d3858720
8 changed files with 115 additions and 10 deletions

View File

@@ -26,6 +26,13 @@
#include "clangfixitsrefactoringchanges.h"
#include <coreplugin/editormanager/editormanager.h>
#include <cpptools/cppcodestylesettings.h>
#include <cpptools/cppmodelmanager.h>
#include <cpptools/cpptoolsconstants.h>
#include <texteditor/icodestylepreferencesfactory.h>
#include <texteditor/indenter.h>
#include <texteditor/texteditorsettings.h>
#include <QDebug>
#include <QFileInfo>
@@ -35,8 +42,11 @@
#include <utils/qtcassert.h>
#include <algorithm>
Q_LOGGING_CATEGORY(fixitsLog, "qtc.clangtools.fixits", QtWarningMsg);
using namespace TextEditor;
using namespace Utils;
namespace ClangTools {
@@ -71,6 +81,13 @@ bool FixitsRefactoringFile::apply()
QTC_ASSERT(!m_filePath.isEmpty(), return false);
ICodeStylePreferencesFactory *factory = TextEditorSettings::codeStyleFactory(
CppTools::Constants::CPP_SETTINGS_ID);
std::unique_ptr<TextEditor::Indenter> indenter(factory->createIndenter());
const TextEditor::TabSettings tabSettings
= CppTools::CppCodeStyleSettings::currentProjectTabSettings();
// Apply changes
for (int i=0; i < m_replacementOperations.size(); ++i) {
ReplacementOperation &op = *m_replacementOperations[i];
@@ -90,6 +107,8 @@ bool FixitsRefactoringFile::apply()
cursor.setPosition(op.pos);
cursor.setPosition(op.pos + op.length, QTextCursor::KeepAnchor);
cursor.insertText(op.text);
tryToFormat(*indenter, tabSettings, doc, op, i);
}
}
@@ -108,6 +127,33 @@ bool FixitsRefactoringFile::apply()
return true;
}
void FixitsRefactoringFile::tryToFormat(TextEditor::Indenter &indenter,
const TextEditor::TabSettings &tabSettings,
QTextDocument *doc,
const ReplacementOperation &op,
int currentIndex)
{
QTextCursor cursor(doc);
cursor.beginEditBlock();
cursor.setPosition(op.pos);
cursor.movePosition(QTextCursor::Right,
QTextCursor::KeepAnchor,
op.text.length());
const Replacements replacements = indenter.format(doc,
Utils::FileName::fromString(op.fileName),
cursor,
tabSettings);
cursor.endEditBlock();
if (replacements.empty())
return;
if (hasIntersection(op.fileName, replacements, currentIndex + 1))
doc->undo(&cursor);
else
shiftAffectedReplacements(op.fileName, replacements, currentIndex + 1);
}
QTextDocument *FixitsRefactoringFile::document(const QString &filePath) const
{
if (m_documents.find(filePath) == m_documents.end()) {
@@ -148,5 +194,45 @@ void FixitsRefactoringFile::shiftAffectedReplacements(const ReplacementOperation
}
}
bool FixitsRefactoringFile::hasIntersection(const QString &fileName,
const Replacements &replacements,
int startIndex) const
{
for (int i = startIndex; i < m_replacementOperations.size(); ++i) {
const ReplacementOperation &current = *m_replacementOperations[i];
if (fileName != current.fileName)
continue;
// Usually the number of replacements is from 1 to 3.
if (std::any_of(replacements.begin(),
replacements.end(),
[&current](const const Replacement &replacement) {
return replacement.offset + replacement.length > current.pos
&& replacement.offset < current.pos + current.length;
})) {
return true;
}
}
return false;
}
void FixitsRefactoringFile::shiftAffectedReplacements(const QString &fileName,
const Replacements &replacements,
int startIndex)
{
for (int i = startIndex; i < m_replacementOperations.size(); ++i) {
ReplacementOperation &current = *m_replacementOperations[i];
if (fileName != current.fileName)
continue;
for (const auto &replacement : replacements) {
if (replacement.offset > current.pos)
break;
current.pos += replacement.text.size() - replacement.length;
}
}
}
} // namespace Internal
} // namespace ClangTools