ClangFormat: Add whitespace unit-tests and fix bugs

Check that extra whitespace does not prevent the indentation
and that indentation is the same for the consecutive empty lines.

Change-Id: I04aa12c4cd31aaf07daf9320c98d2eea7afcc9a8
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Ivan Donchevskii
2019-03-06 14:05:31 +01:00
parent 35b0b44b21
commit 7e5e99d551
3 changed files with 59 additions and 22 deletions

View File

@@ -129,7 +129,10 @@ void trimRHSWhitespace(const QTextBlock &block)
// Add extra text in case of the empty line or the line starting with ')'. // Add extra text in case of the empty line or the line starting with ')'.
// Track such extra pieces of text in isInsideModifiedLine(). // Track such extra pieces of text in isInsideModifiedLine().
int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool secondTry) int forceIndentWithExtraText(QByteArray &buffer,
QByteArray &dummyText,
const QTextBlock &block,
bool secondTry)
{ {
const QString blockText = block.text(); const QString blockText = block.text();
int firstNonWhitespace = Utils::indexOf(blockText, int firstNonWhitespace = Utils::indexOf(blockText,
@@ -144,21 +147,26 @@ int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool s
const bool closingParenBlock = firstNonWhitespace >= 0 const bool closingParenBlock = firstNonWhitespace >= 0
&& blockText.at(firstNonWhitespace) == ')'; && blockText.at(firstNonWhitespace) == ')';
int extraLength = 0; int extraLength = 0;
if (firstNonWhitespace < 0 || closingParenBlock) { if (firstNonWhitespace < 0 || closingParenBlock) {
if (dummyText.isEmpty()) {
// If we don't know yet the dummy text, let's guess it and use for this line and before.
// This extra text works for the most cases. // This extra text works for the most cases.
QByteArray dummyText("a;a;"); dummyText = "a;a;";
// Search for previous character // Search for previous character
QTextBlock prevBlock = block.previous(); QTextBlock prevBlock = block.previous();
bool prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); bool prevBlockIsEmpty = prevBlock.position() > 0
&& prevBlock.text().trimmed().isEmpty();
while (prevBlockIsEmpty) { while (prevBlockIsEmpty) {
prevBlock = prevBlock.previous(); prevBlock = prevBlock.previous();
prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty();
} }
if (closingParenBlock || prevBlock.text().endsWith(',')) if (prevBlock.text().endsWith(','))
dummyText = "&& a,"; dummyText = "&& a,";
else if (closingParenBlock)
dummyText = "&& a";
}
buffer.insert(utf8Offset, dummyText); buffer.insert(utf8Offset, dummyText);
extraLength += dummyText.length(); extraLength += dummyText.length();
@@ -357,8 +365,11 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
adjustFormatStyleForLineBreak(style, replacementsToKeep); adjustFormatStyleForLineBreak(style, replacementsToKeep);
if (replacementsToKeep == ReplacementsToKeep::OnlyIndent) { if (replacementsToKeep == ReplacementsToKeep::OnlyIndent) {
for (int index = startBlock.blockNumber(); index <= endBlock.blockNumber(); ++index) { QByteArray dummyText;
// Iterate backwards to reuse the same dummy text for all empty lines.
for (int index = endBlock.blockNumber(); index >= startBlock.blockNumber(); --index) {
utf8Length += forceIndentWithExtraText(buffer, utf8Length += forceIndentWithExtraText(buffer,
dummyText,
m_doc->findBlockByNumber(index), m_doc->findBlockByNumber(index),
secondTry); secondTry);
} }
@@ -447,7 +458,6 @@ TextEditor::Replacements ClangFormatBaseIndenter::format(
TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock, TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock,
const QTextBlock &endBlock, const QTextBlock &endBlock,
const QByteArray &buffer,
const QChar &typedChar, const QChar &typedChar,
int cursorPositionInEditor) int cursorPositionInEditor)
{ {
@@ -465,6 +475,8 @@ TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlo
cursorPositionInEditor += startBlock.position() - startBlockPosition; cursorPositionInEditor += startBlock.position() - startBlockPosition;
} }
const QByteArray buffer = m_doc->toPlainText().toUtf8();
ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent; ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent;
if (formatWhileTyping() if (formatWhileTyping()
&& (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition) && (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition)
@@ -491,9 +503,7 @@ void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock,
const QChar &typedChar, const QChar &typedChar,
int cursorPositionInEditor) int cursorPositionInEditor)
{ {
const QByteArray buffer = m_doc->toPlainText().toUtf8(); applyReplacements(m_doc, indentsFor(startBlock, endBlock, typedChar, cursorPositionInEditor));
applyReplacements(m_doc,
indentsFor(startBlock, endBlock, buffer, typedChar, cursorPositionInEditor));
} }
void ClangFormatBaseIndenter::indent(const QTextCursor &cursor, void ClangFormatBaseIndenter::indent(const QTextCursor &cursor,
@@ -537,15 +547,14 @@ int ClangFormatBaseIndenter::indentFor(const QTextBlock &block,
const TextEditor::TabSettings & /*tabSettings*/, const TextEditor::TabSettings & /*tabSettings*/,
int cursorPositionInEditor) int cursorPositionInEditor)
{ {
const QByteArray buffer = m_doc->toPlainText().toUtf8();
TextEditor::Replacements toReplace = indentsFor(block, TextEditor::Replacements toReplace = indentsFor(block,
block, block,
buffer,
QChar::Null, QChar::Null,
cursorPositionInEditor); cursorPositionInEditor);
if (toReplace.empty()) if (toReplace.empty())
return -1; return -1;
const QByteArray buffer = m_doc->toPlainText().toUtf8();
return indentationForBlock(toReplace, buffer, block); return indentationForBlock(toReplace, buffer, block);
} }
@@ -557,13 +566,12 @@ TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks(
TextEditor::IndentationForBlock ret; TextEditor::IndentationForBlock ret;
if (blocks.isEmpty()) if (blocks.isEmpty())
return ret; return ret;
const QByteArray buffer = m_doc->toPlainText().toUtf8();
TextEditor::Replacements toReplace = indentsFor(blocks.front(), TextEditor::Replacements toReplace = indentsFor(blocks.front(),
blocks.back(), blocks.back(),
buffer,
QChar::Null, QChar::Null,
cursorPositionInEditor); cursorPositionInEditor);
const QByteArray buffer = m_doc->toPlainText().toUtf8();
for (const QTextBlock &block : blocks) for (const QTextBlock &block : blocks)
ret.insert(block.blockNumber(), indentationForBlock(toReplace, buffer, block)); ret.insert(block.blockNumber(), indentationForBlock(toReplace, buffer, block));
return ret; return ret;

View File

@@ -81,7 +81,6 @@ private:
int cursorPositionInEditor); int cursorPositionInEditor);
TextEditor::Replacements indentsFor(QTextBlock startBlock, TextEditor::Replacements indentsFor(QTextBlock startBlock,
const QTextBlock &endBlock, const QTextBlock &endBlock,
const QByteArray &buffer,
const QChar &typedChar, const QChar &typedChar,
int cursorPositionInEditor); int cursorPositionInEditor);
TextEditor::Replacements replacements(QByteArray buffer, TextEditor::Replacements replacements(QByteArray buffer,

View File

@@ -72,6 +72,7 @@ protected:
void insertLines(const std::vector<QString> &lines) void insertLines(const std::vector<QString> &lines)
{ {
doc.clear();
cursor.setPosition(0); cursor.setPosition(0);
for (size_t lineNumber = 1; lineNumber <= lines.size(); ++lineNumber) { for (size_t lineNumber = 1; lineNumber <= lines.size(); ++lineNumber) {
if (lineNumber > 1) if (lineNumber > 1)
@@ -379,6 +380,17 @@ TEST_F(ClangFormat, IndentOnElectricCharacterButNotRemoveEmptyLinesBefore)
"}")); "}"));
} }
TEST_F(ClangFormat, IndentAfterExtraSpaceInpreviousLine)
{
insertLines({"if (a ",
"&& b)"});
indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings());
ASSERT_THAT(documentLines(), ElementsAre("if (a",
" && b)"));
}
TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt) TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt)
{ {
insertLines({"int foo(int a, int b,", insertLines({"int foo(int a, int b,",
@@ -520,6 +532,24 @@ TEST_F(ClangFormat, OnlyIndentClosingParenthesis)
" )")); " )"));
} }
TEST_F(ClangFormat, EquallyIndentInsideParenthesis)
{
insertLines({"if (a",
")"});
extendedIndenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings());
auto linesAfterFirstLineBreak = documentLines();
insertLines({"if (a",
" ",
")"});
extendedIndenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings());
ASSERT_THAT(linesAfterFirstLineBreak, ElementsAre("if (a",
" )"));
ASSERT_THAT(documentLines(), ElementsAre("if (a",
" ",
" )"));
}
TEST_F(ClangFormat, FormatBasicFile) TEST_F(ClangFormat, FormatBasicFile)
{ {
insertLines({"int main()", insertLines({"int main()",