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

@@ -384,14 +384,10 @@ void ClangFormatIndenter::indent(QTextDocument *doc,
}
QtReplacements ClangFormatIndenter::format(QTextDocument *doc,
const Utils::FileName &fileName,
const QTextCursor &cursor,
const TextEditor::TabSettings & /*tabSettings*/)
{
TextEditorWidget *editor = TextEditorWidget::currentTextEditorWidget();
if (!editor)
return QtReplacements();
const Utils::FileName fileName = editor->textDocument()->filePath();
int utf8Offset;
int utf8Length;
const QByteArray buffer = doc->toPlainText().toUtf8();

View File

@@ -41,6 +41,7 @@ public:
const QTextCursor &cursor,
const TextEditor::TabSettings &tabSettings) override;
TextEditor::Replacements format(QTextDocument *doc,
const Utils::FileName &fileName,
const QTextCursor &cursor,
const TextEditor::TabSettings &tabSettings) override;
void indentBlock(QTextDocument *doc,

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

View File

@@ -32,6 +32,13 @@
#include <QTextDocument>
#include <QVector>
namespace TextEditor {
class Indenter;
class Replacement;
using Replacements = std::vector<Replacement>;
class TabSettings;
}
namespace ClangTools {
namespace Internal {
@@ -65,6 +72,18 @@ private:
QTextDocument *document(const QString &filePath) const;
void shiftAffectedReplacements(const ReplacementOperation &op, int startIndex);
void tryToFormat(TextEditor::Indenter &indenter,
const TextEditor::TabSettings &tabSettings,
QTextDocument *doc,
const ReplacementOperation &op,
int currentIndex);
void shiftAffectedReplacements(const QString &fileName,
const TextEditor::Replacements &replacements,
int startIndex);
bool hasIntersection(const QString &fileName,
const TextEditor::Replacements &replacements,
int startIndex) const;
QString m_filePath;
mutable Utils::TextFileFormat m_textFileFormat;
mutable QHash<QString, QTextDocument *> m_documents;

View File

@@ -179,7 +179,6 @@ public:
QVector<DiagnosticItem *> itemsInvalidated;
fileInfo.file.setReplacements(ops);
model->removeWatchedPath(ops.first()->fileName);
if (fileInfo.file.apply()) {
itemsApplied = itemsScheduled;

View File

@@ -103,6 +103,7 @@ void Indenter::reindent(QTextDocument *doc, const QTextCursor &cursor, const Tab
}
Replacements Indenter::format(QTextDocument *doc,
const Utils::FileName & /*fileName*/,
const QTextCursor &cursor,
const TabSettings &tabSettings)
{

View File

@@ -39,6 +39,8 @@ class QTextBlock;
class QChar;
QT_END_NAMESPACE
namespace Utils { class FileName; }
namespace TextEditor {
class ICodeStylePreferences;
@@ -85,6 +87,7 @@ public:
// By default just calls indent with default settings.
virtual Replacements format(QTextDocument *doc,
const Utils::FileName &fileName,
const QTextCursor &cursor,
const TabSettings &tabSettings);

View File

@@ -428,7 +428,7 @@ void TextDocument::autoReindent(const QTextCursor &cursor)
void TextDocument::autoFormat(const QTextCursor &cursor)
{
d->m_indenter->format(&d->m_document, cursor, tabSettings());
d->m_indenter->format(&d->m_document, filePath(), cursor, tabSettings());
}
QTextCursor TextDocument::indent(const QTextCursor &cursor, bool blockSelection, int column,