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 <christian.kandeler@qt.io>
This commit is contained in:
Artem Sokolovskii
2022-07-05 16:38:51 +02:00
parent 5817bdf87d
commit 17693bc415
3 changed files with 106 additions and 15 deletions

View File

@@ -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 &currentBlock,
const QTextBlock &previousNonEmptyBlock)
CharacterContext characterContext(const QTextBlock &currentBlock)
{
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);
}

View File

@@ -655,4 +655,74 @@ void ClangFormatTest::testClassIndentStructure()
(std::vector<QString>{"class test {", " Q_OBJECT", "public:", "};"}));
}
void ClangFormatTest::testIndentInitializeVector()
{
insertLines({
"class Test {",
"public:",
" Test();",
"};",
"",
"Test::Test()",
"{",
" QVector<int> list = {",
" 1,",
" 2,",
" 3,",
" };",
" QVector<int> list_2 = {",
" 1,",
" 2,",
" 3,",
" };",
"}",
"",
"int main()",
"{",
"}"
});
m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings());
QCOMPARE(documentLines(),
(std::vector<QString>{
"class Test {",
"public:",
" Test();",
"};",
"",
"Test::Test()",
"{",
" QVector<int> list = {",
" 1,",
" 2,",
" 3,",
" };",
" QVector<int> 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<QString>{
"Bar foo(",
" a,",
")"
}));
}
} // namespace ClangFormat::Internal

View File

@@ -110,6 +110,8 @@ private slots:
void testChainedMemberFunctionCalls();
void testCommentBlock();
void testClassIndentStructure();
void testIndentInitializeVector();
void testIndentFunctionArgumentOnNewLine();
private:
void insertLines(const std::vector<QString> &lines);