forked from qt-creator/qt-creator
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:
@@ -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) {
|
||||||
//This extra text works for the most cases.
|
if (dummyText.isEmpty()) {
|
||||||
QByteArray dummyText("a;a;");
|
// 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.
|
||||||
|
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
|
||||||
while (prevBlockIsEmpty) {
|
&& prevBlock.text().trimmed().isEmpty();
|
||||||
prevBlock = prevBlock.previous();
|
while (prevBlockIsEmpty) {
|
||||||
prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty();
|
prevBlock = prevBlock.previous();
|
||||||
|
prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty();
|
||||||
|
}
|
||||||
|
if (prevBlock.text().endsWith(','))
|
||||||
|
dummyText = "&& a,";
|
||||||
|
else if (closingParenBlock)
|
||||||
|
dummyText = "&& a";
|
||||||
}
|
}
|
||||||
if (closingParenBlock || prevBlock.text().endsWith(','))
|
|
||||||
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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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()",
|
||||||
|
|||||||
Reference in New Issue
Block a user