From 17693bc41518ee1c15d673dfee3c3818057b1895 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Tue, 5 Jul 2022 16:38:51 +0200 Subject: ClangFormat: Fix list declaration Fixed list declaration indentation. Fixed function declaration with parameters on the new line. Added tests for both cases. Fixes: QTCREATORBUG-25011 Change-Id: Ida4f6ec4f407c5e5b015dc2c0afff110262d9645 Reviewed-by: Christian Kandeler --- .../clangformat/clangformatbaseindenter.cpp | 49 ++++++++++----- src/plugins/clangformat/tests/clangformat-test.cpp | 70 ++++++++++++++++++++++ src/plugins/clangformat/tests/clangformat-test.h | 2 + 3 files changed, 106 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 4ee5daebdb..8724109bad 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -156,6 +156,16 @@ QTextBlock reverseFindLastEmptyBlock(QTextBlock start) return start; } +QTextBlock reverseFindLastBlockWithSymbol(QTextBlock start, QChar ch) +{ + if (start.position() > 0) { + start = start.previous(); + while (start.position() > 0 && !start.text().contains(ch)) + start = start.previous(); + } + return start; +} + enum class CharacterContext { AfterComma, LastAfterComma, @@ -202,18 +212,30 @@ bool comesDirectlyAfterIf(const QTextDocument *doc, int pos) return pos > 0 && doc->characterAt(pos) == 'f' && doc->characterAt(pos - 1) == 'i'; } -CharacterContext characterContext(const QTextBlock ¤tBlock, - const QTextBlock &previousNonEmptyBlock) +CharacterContext characterContext(const QTextBlock ¤tBlock) { + QTextBlock previousNonEmptyBlock = reverseFindLastEmptyBlock(currentBlock); + if (previousNonEmptyBlock.position() > 0) + previousNonEmptyBlock = previousNonEmptyBlock.previous(); + const QString prevLineText = previousNonEmptyBlock.text().trimmed(); if (prevLineText.isEmpty()) return CharacterContext::NewStatementOrContinuation; const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock); if (prevLineText.endsWith(',')) { - // We don't need to add comma in case it's the last argument. - if (firstNonWhitespaceChar == '}' || firstNonWhitespaceChar == ')') + if (firstNonWhitespaceChar == '}') { + if (reverseFindLastBlockWithSymbol(currentBlock, '{').text().trimmed().last(1) == '{') + return CharacterContext::NewStatementOrContinuation; return CharacterContext::LastAfterComma; + } + + if (firstNonWhitespaceChar == ')') { + if (reverseFindLastBlockWithSymbol(currentBlock, '(').text().trimmed().last(1) == '(') + return CharacterContext::NewStatementOrContinuation; + return CharacterContext::LastAfterComma; + } + return CharacterContext::AfterComma; } @@ -267,6 +289,14 @@ int forceIndentWithExtraText(QByteArray &buffer, if (!block.isValid()) return 0; + auto tmpcharContext = characterContext(block); + if (charContext == CharacterContext::LastAfterComma + && tmpcharContext == CharacterContext::LastAfterComma) { + charContext = CharacterContext::AfterComma; + } else { + charContext = tmpcharContext; + } + const QString blockText = block.text(); int firstNonWhitespace = Utils::indexOf(blockText, [](const QChar &ch) { return !ch.isSpace(); }); @@ -290,17 +320,6 @@ int forceIndentWithExtraText(QByteArray &buffer, // If the next line is also empty it's safer to use a comment line. dummyText = "//"; } else if (firstNonWhitespace < 0 || closingParenBlock || closingBraceBlock) { - if (charContext == CharacterContext::LastAfterComma) { - charContext = CharacterContext::AfterComma; - } else if (charContext == CharacterContext::Unknown || firstNonWhitespace >= 0) { - QTextBlock lastBlock = reverseFindLastEmptyBlock(block); - if (lastBlock.position() > 0) - lastBlock = lastBlock.previous(); - - // If we don't know yet the dummy text, let's guess it and use for this line and before. - charContext = characterContext(block, lastBlock); - } - dummyText = dummyTextForContext(charContext, closingBraceBlock); } diff --git a/src/plugins/clangformat/tests/clangformat-test.cpp b/src/plugins/clangformat/tests/clangformat-test.cpp index 0493eeca97..50a5fe426b 100644 --- a/src/plugins/clangformat/tests/clangformat-test.cpp +++ b/src/plugins/clangformat/tests/clangformat-test.cpp @@ -655,4 +655,74 @@ void ClangFormatTest::testClassIndentStructure() (std::vector{"class test {", " Q_OBJECT", "public:", "};"})); } +void ClangFormatTest::testIndentInitializeVector() +{ + insertLines({ + "class Test {", + "public:", + " Test();", + "};", + "", + "Test::Test()", + "{", + " QVector list = {", + " 1,", + " 2,", + " 3,", + " };", + " QVector list_2 = {", + " 1,", + " 2,", + " 3,", + " };", + "}", + "", + "int main()", + "{", + "}" + }); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), + (std::vector{ + "class Test {", + "public:", + " Test();", + "};", + "", + "Test::Test()", + "{", + " QVector list = {", + " 1,", + " 2,", + " 3,", + " };", + " QVector list_2 = {", + " 1,", + " 2,", + " 3,", + " };", + "}", + "", + "int main()", + "{", + "}" + })); +} + +void ClangFormatTest::testIndentFunctionArgumentOnNewLine() +{ + insertLines( + {"Bar foo(", + "a,", + ")" + }); + m_indenter->indentBlock(m_doc->findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), + (std::vector{ + "Bar foo(", + " a,", + ")" + })); +} + } // namespace ClangFormat::Internal diff --git a/src/plugins/clangformat/tests/clangformat-test.h b/src/plugins/clangformat/tests/clangformat-test.h index 094657d1b0..1793a0cffb 100644 --- a/src/plugins/clangformat/tests/clangformat-test.h +++ b/src/plugins/clangformat/tests/clangformat-test.h @@ -110,6 +110,8 @@ private slots: void testChainedMemberFunctionCalls(); void testCommentBlock(); void testClassIndentStructure(); + void testIndentInitializeVector(); + void testIndentFunctionArgumentOnNewLine(); private: void insertLines(const std::vector &lines); -- cgit v1.2.1