From df23fbdc8931055d43b9665682e4562a81ead4f7 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Thu, 7 Mar 2019 12:29:10 +0100 Subject: [PATCH] ClangFormat: Improve dummy text guessing for empty lines Improve detection of the cases when the empty line is inside the parenthesis to get more proper indentation. Change-Id: I4aa37c29b17bedcd0e4a781d12c7066e818a07f3 Reviewed-by: Marco Bubke --- .../clangformat/clangformatbaseindenter.cpp | 70 +++++++++++++++---- tests/unit/unittest/clangformat-test.cpp | 13 ++++ 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 7f47b418a77..83e877259c9 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -127,6 +127,44 @@ void trimRHSWhitespace(const QTextBlock &block) cursor.endEditBlock(); } +// We don't need other types so far. +enum class CharacterType { OpeningParen, OpeningBrace, Invalid }; + +CharacterType firstOpeningParenOrBraceBeforeBlock(const QTextBlock &block) +{ + if (block.text().trimmed().startsWith(')')) + return CharacterType::OpeningParen; + + QTextCursor cursor(block); + const QTextDocument *doc = block.document(); + + cursor.movePosition(QTextCursor::PreviousCharacter); + QChar currentChar = doc->characterAt(cursor.position()); + + int parenCount = 0; + int braceCount = 0; + + while (cursor.position() > 0 && parenCount <= 0 && braceCount <= 0) { + cursor.movePosition(QTextCursor::PreviousCharacter); + currentChar = doc->characterAt(cursor.position()); + if (currentChar == '(') + ++parenCount; + else if (currentChar == ')') + --parenCount; + else if (currentChar == '{') + ++braceCount; + else if (currentChar == '}') + --braceCount; + } + + if (braceCount > 0) + return CharacterType::OpeningBrace; + if (parenCount > 0) + return CharacterType::OpeningParen; + + return CharacterType::Invalid; +} + // Add extra text in case of the empty line or the line starting with ')'. // Track such extra pieces of text in isInsideModifiedLine(). int forceIndentWithExtraText(QByteArray &buffer, @@ -147,25 +185,27 @@ int forceIndentWithExtraText(QByteArray &buffer, const bool closingParenBlock = firstNonWhitespace >= 0 && blockText.at(firstNonWhitespace) == ')'; + int extraLength = 0; if (firstNonWhitespace < 0 || closingParenBlock) { if (dummyText.isEmpty()) { + const CharacterType charType = firstOpeningParenOrBraceBeforeBlock(block); // 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 - QTextBlock prevBlock = block.previous(); - bool prevBlockIsEmpty = prevBlock.position() > 0 - && prevBlock.text().trimmed().isEmpty(); - while (prevBlockIsEmpty) { - prevBlock = prevBlock.previous(); - prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); + if (charType != CharacterType::OpeningParen) { + // Use the complete statement if we are not inside parenthesis. + dummyText = "a;a;"; + } else { + // Search for previous character + QTextBlock prevBlock = block.previous(); + bool prevBlockIsEmpty = prevBlock.position() > 0 + && prevBlock.text().trimmed().isEmpty(); + while (prevBlockIsEmpty) { + prevBlock = prevBlock.previous(); + prevBlockIsEmpty = prevBlock.position() > 0 + && prevBlock.text().trimmed().isEmpty(); + } + dummyText = prevBlock.text().endsWith(',') ? "&& a," : "&& a"; } - if (prevBlock.text().endsWith(',')) - dummyText = "&& a,"; - else if (closingParenBlock) - dummyText = "&& a"; } buffer.insert(utf8Offset, dummyText); @@ -179,7 +219,7 @@ int forceIndentWithExtraText(QByteArray &buffer, if (nextLinePos > 0) { // If first try was not successful try to put ')' in the end of the line to close possibly - // unclosed parentheses. + // unclosed parenthesis. // TODO: Does it help to add different endings depending on the context? buffer.insert(nextLinePos, ')'); extraLength += 1; diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index 43380c85028..f87bb1dc747 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -391,6 +391,19 @@ TEST_F(ClangFormat, IndentAfterExtraSpaceInpreviousLine) " && b)")); } +TEST_F(ClangFormat, IndentEmptyLineInsideParantheses) +{ + insertLines({"if (a ", + "", + " && b)"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (a", + " ", + " && b)")); +} + TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt) { insertLines({"int foo(int a, int b,",