ClangFormat: Improve formatting performance to reformat the whole file

Allows not to cut the file and removes extra logic.

To achieve that do "smart" formatting in one go by adding a trick
with comment to keep the last line break and provide the proper indent
for the current line together with formatting the code above.

Disable adding namespace comments because it causes one extra
formatting pass (not for the manual formatting).

Change-Id: I8f644129606238c5438e636f56e6097ab149aa0c
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Ivan Donchevskii
2019-02-08 12:31:53 +01:00
parent 4b5841292e
commit 4066dee257
2 changed files with 39 additions and 65 deletions

View File

@@ -36,16 +36,27 @@
namespace ClangFormat { namespace ClangFormat {
static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style) static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style,
ReplacementsToKeep replacementsToKeep)
{ {
if (replacementsToKeep == ReplacementsToKeep::All)
return;
style.MaxEmptyLinesToKeep = 2;
style.SortIncludes = false;
style.SortUsingDeclarations = false;
// This is a separate pass, don't do it unless it's the full formatting.
style.FixNamespaceComments = false;
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore)
return;
style.DisableFormat = false; style.DisableFormat = false;
style.ColumnLimit = 0; style.ColumnLimit = 0;
#ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED #ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
style.KeepLineBreaksForNonEmptyLines = true; style.KeepLineBreaksForNonEmptyLines = true;
#endif #endif
style.MaxEmptyLinesToKeep = 2;
style.SortIncludes = false;
style.SortUsingDeclarations = false;
} }
static llvm::StringRef clearExtraNewline(llvm::StringRef text) static llvm::StringRef clearExtraNewline(llvm::StringRef text)
@@ -59,7 +70,6 @@ static clang::tooling::Replacements filteredReplacements(
const clang::tooling::Replacements &replacements, const clang::tooling::Replacements &replacements,
int offset, int offset,
int utf8LineLengthBeforeCursor, int utf8LineLengthBeforeCursor,
int extraOffsetFromStartOfFile,
int extraEmptySpaceOffset, int extraEmptySpaceOffset,
ReplacementsToKeep replacementsToKeep) ReplacementsToKeep replacementsToKeep)
{ {
@@ -69,14 +79,13 @@ static clang::tooling::Replacements filteredReplacements(
const bool replacementDoesNotMatchRestriction const bool replacementDoesNotMatchRestriction
= (replacementsToKeep == ReplacementsToKeep::OnlyIndent = (replacementsToKeep == ReplacementsToKeep::OnlyIndent
&& replacementOffset != offset - 1) && replacementOffset != offset - 1)
|| (replacementsToKeep == ReplacementsToKeep::OnlyBeforeIndent || (replacementsToKeep == ReplacementsToKeep::IndentAndBefore
&& replacementOffset >= offset + utf8LineLengthBeforeCursor - 1); && replacementOffset > offset + utf8LineLengthBeforeCursor - 1);
if (replacementDoesNotMatchRestriction) if (replacementDoesNotMatchRestriction)
continue; continue;
if (replacementOffset >= offset - 1) if (replacementOffset >= offset - 1)
replacementOffset += extraEmptySpaceOffset; replacementOffset += extraEmptySpaceOffset;
replacementOffset += extraOffsetFromStartOfFile;
llvm::StringRef text = replacementsToKeep == ReplacementsToKeep::OnlyIndent llvm::StringRef text = replacementsToKeep == ReplacementsToKeep::OnlyIndent
? clearExtraNewline(replacement.getReplacementText()) ? clearExtraNewline(replacement.getReplacementText())
@@ -128,18 +137,6 @@ static void trimFirstNonEmptyBlock(const QTextBlock &currentBlock)
cursor.endEditBlock(); cursor.endEditBlock();
} }
static void trimCurrentBlock(const QTextBlock &currentBlock)
{
if (currentBlock.text().trimmed().isEmpty()) {
// Clear the block containing only spaces
QTextCursor cursor(currentBlock);
cursor.beginEditBlock();
cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
cursor.removeSelectedText();
cursor.endEditBlock();
}
}
// Returns the total langth of previous lines with pure whitespace. // Returns the total langth of previous lines with pure whitespace.
static int previousEmptyLinesLength(const QTextBlock &currentBlock) static int previousEmptyLinesLength(const QTextBlock &currentBlock)
{ {
@@ -167,7 +164,7 @@ static void modifyToIndentEmptyLines(
if (firstNonWhitespace < 0 || closingParenBlock) { if (firstNonWhitespace < 0 || closingParenBlock) {
//This extra text works for the most cases. //This extra text works for the most cases.
QByteArray dummyText("a;"); QByteArray dummyText("a;a;");
// Search for previous character // Search for previous character
QTextBlock prevBlock = block.previous(); QTextBlock prevBlock = block.previous();
@@ -198,8 +195,6 @@ static void modifyToIndentEmptyLines(
} }
} }
static const int kMaxLinesFromCurrentBlock = 200;
static Utils::LineColumn utf16LineColumn(const QTextBlock &block, static Utils::LineColumn utf16LineColumn(const QTextBlock &block,
int blockOffsetUtf8, int blockOffsetUtf8,
const QByteArray &utf8Buffer, const QByteArray &utf8Buffer,
@@ -388,24 +383,21 @@ TextEditor::Replacements ClangFormatBaseIndenter::format(
return format(cursor, cursorPositionInEditor); return format(cursor, cursorPositionInEditor);
} }
int ClangFormatBaseIndenter::indentBeforeCursor(const QTextBlock &block, void ClangFormatBaseIndenter::indentBeforeCursor(const QTextBlock &block,
const QChar &typedChar, const QChar &typedChar,
int cursorPositionInEditor) int cursorPositionInEditor)
{ {
const QByteArray buffer = m_doc->toPlainText().toUtf8(); const QByteArray buffer = m_doc->toPlainText().toUtf8();
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1); const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return cursorPositionInEditor;); QTC_ASSERT(utf8Offset >= 0, return;);
const TextEditor::Replacements toReplace = replacements(buffer, const TextEditor::Replacements toReplace = replacements(buffer,
utf8Offset, utf8Offset,
0, 0,
block, block,
cursorPositionInEditor, cursorPositionInEditor,
ReplacementsToKeep::OnlyBeforeIndent, ReplacementsToKeep::IndentAndBefore,
typedChar); typedChar);
applyReplacements(block, toReplace); applyReplacements(block, toReplace);
for (const TextEditor::Replacement &replacement : toReplace)
cursorPositionInEditor += replacement.text.length() - replacement.length;
return cursorPositionInEditor;
} }
static bool doNotIndentInContext(QTextDocument *doc, int pos) static bool doNotIndentInContext(QTextDocument *doc, int pos)
@@ -466,11 +458,10 @@ void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
else else
cursorPositionInEditor = currentBlock.position(); cursorPositionInEditor = currentBlock.position();
cursorPositionInEditor = indentBeforeCursor(currentBlock, typedChar, cursorPositionInEditor); indentBeforeCursor(currentBlock, typedChar, cursorPositionInEditor);
currentBlock = m_doc->findBlock(cursorPositionInEditor); return;
} }
trimCurrentBlock(currentBlock);
const QByteArray buffer = m_doc->toPlainText().toUtf8(); const QByteArray buffer = m_doc->toPlainText().toUtf8();
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1); const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return;); QTC_ASSERT(utf8Offset >= 0, return;);
@@ -496,7 +487,6 @@ void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, int cursorPositionInEditor) int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, int cursorPositionInEditor)
{ {
trimFirstNonEmptyBlock(block); trimFirstNonEmptyBlock(block);
trimCurrentBlock(block);
const QByteArray buffer = m_doc->toPlainText().toUtf8(); const QByteArray buffer = m_doc->toPlainText().toUtf8();
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1); const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return 0;); QTC_ASSERT(utf8Offset >= 0, return 0;);
@@ -571,8 +561,7 @@ static int formattingRangeStart(const QTextBlock &currentBlock,
{ {
QTextBlock prevBlock = currentBlock.previous(); QTextBlock prevBlock = currentBlock.previous();
while ((prevBlock.position() > 0 || prevBlock.length() > 0) while ((prevBlock.position() > 0 || prevBlock.length() > 0)
&& prevBlock.revision() != documentRevision && prevBlock.revision() != documentRevision) {
&& (currentBlock.blockNumber() - prevBlock.blockNumber() < kMaxLinesFromCurrentBlock)) {
// Find the first block with not matching revision. // Find the first block with not matching revision.
prevBlock = prevBlock.previous(); prevBlock = prevBlock.previous();
} }
@@ -604,41 +593,27 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
= block.text().left(cursorPositionInEditor - block.position()).toUtf8().size(); = block.text().left(cursorPositionInEditor - block.position()).toUtf8().size();
} }
int extraOffsetFromStartOfFile = 0;
int extraEmptySpaceOffset = 0; int extraEmptySpaceOffset = 0;
int rangeStart = 0; int rangeStart = 0;
if (replacementsToKeep != ReplacementsToKeep::All) { if (replacementsToKeep != ReplacementsToKeep::All) {
if (block.blockNumber() > kMaxLinesFromCurrentBlock) { if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore)
extraOffsetFromStartOfFile
= Utils::Text::utf8NthLineOffset(block.document(),
buffer,
block.blockNumber() - kMaxLinesFromCurrentBlock);
}
int endOffset = Utils::Text::utf8NthLineOffset(block.document(),
buffer,
block.blockNumber()
+ kMaxLinesFromCurrentBlock);
if (endOffset == -1)
endOffset = buffer.size();
if (replacementsToKeep == ReplacementsToKeep::OnlyBeforeIndent)
rangeStart = formattingRangeStart(block, buffer, lastSaveRevision()); rangeStart = formattingRangeStart(block, buffer, lastSaveRevision());
buffer = buffer.mid(extraOffsetFromStartOfFile, endOffset - extraOffsetFromStartOfFile);
utf8Offset -= extraOffsetFromStartOfFile;
rangeStart -= extraOffsetFromStartOfFile;
extraEmptySpaceOffset = previousEmptyLinesLength(block); extraEmptySpaceOffset = previousEmptyLinesLength(block);
utf8Offset -= extraEmptySpaceOffset; utf8Offset -= extraEmptySpaceOffset;
buffer.remove(utf8Offset, extraEmptySpaceOffset); buffer.remove(utf8Offset, extraEmptySpaceOffset);
if (replacementsToKeep == ReplacementsToKeep::OnlyIndent) adjustFormatStyleForLineBreak(style, replacementsToKeep);
adjustFormatStyleForLineBreak(style);
modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, block, secondTry); modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, block, secondTry);
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) {
buffer.insert(utf8Offset - 1, " //");
extraEmptySpaceOffset -= 3;
utf8Offset += 3;
}
} }
if (replacementsToKeep != ReplacementsToKeep::OnlyBeforeIndent || utf8Offset < rangeStart) if (replacementsToKeep != ReplacementsToKeep::IndentAndBefore || utf8Offset < rangeStart)
rangeStart = utf8Offset; rangeStart = utf8Offset;
unsigned int rangeLength = static_cast<unsigned int>(utf8Offset + utf8Length - rangeStart); unsigned int rangeLength = static_cast<unsigned int>(utf8Offset + utf8Length - rangeStart);
@@ -658,7 +633,6 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
filtered = filteredReplacements(clangReplacements, filtered = filteredReplacements(clangReplacements,
utf8Offset, utf8Offset,
utf8LineLengthBeforeCursor, utf8LineLengthBeforeCursor,
extraOffsetFromStartOfFile,
extraEmptySpaceOffset, extraEmptySpaceOffset,
replacementsToKeep); replacementsToKeep);
} }

View File

@@ -31,7 +31,7 @@
namespace ClangFormat { namespace ClangFormat {
enum class ReplacementsToKeep { OnlyIndent, OnlyBeforeIndent, All }; enum class ReplacementsToKeep { OnlyIndent, IndentAndBefore, All };
class ClangFormatBaseIndenter : public TextEditor::Indenter class ClangFormatBaseIndenter : public TextEditor::Indenter
{ {
@@ -79,9 +79,9 @@ private:
void indent(const QTextCursor &cursor, const QChar &typedChar, int cursorPositionInEditor); void indent(const QTextCursor &cursor, const QChar &typedChar, int cursorPositionInEditor);
void indentBlock(const QTextBlock &block, const QChar &typedChar, int cursorPositionInEditor); void indentBlock(const QTextBlock &block, const QChar &typedChar, int cursorPositionInEditor);
int indentFor(const QTextBlock &block, int cursorPositionInEditor); int indentFor(const QTextBlock &block, int cursorPositionInEditor);
int indentBeforeCursor(const QTextBlock &block, void indentBeforeCursor(const QTextBlock &block,
const QChar &typedChar, const QChar &typedChar,
int cursorPositionInEditor); int cursorPositionInEditor);
TextEditor::Replacements replacements(QByteArray buffer, TextEditor::Replacements replacements(QByteArray buffer,
int utf8Offset, int utf8Offset,
int utf8Length, int utf8Length,