forked from qt-creator/qt-creator
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:
@@ -156,6 +156,16 @@ QTextBlock reverseFindLastEmptyBlock(QTextBlock start)
|
|||||||
return 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 {
|
enum class CharacterContext {
|
||||||
AfterComma,
|
AfterComma,
|
||||||
LastAfterComma,
|
LastAfterComma,
|
||||||
@@ -202,18 +212,30 @@ bool comesDirectlyAfterIf(const QTextDocument *doc, int pos)
|
|||||||
return pos > 0 && doc->characterAt(pos) == 'f' && doc->characterAt(pos - 1) == 'i';
|
return pos > 0 && doc->characterAt(pos) == 'f' && doc->characterAt(pos - 1) == 'i';
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterContext characterContext(const QTextBlock ¤tBlock,
|
CharacterContext characterContext(const QTextBlock ¤tBlock)
|
||||||
const QTextBlock &previousNonEmptyBlock)
|
|
||||||
{
|
{
|
||||||
|
QTextBlock previousNonEmptyBlock = reverseFindLastEmptyBlock(currentBlock);
|
||||||
|
if (previousNonEmptyBlock.position() > 0)
|
||||||
|
previousNonEmptyBlock = previousNonEmptyBlock.previous();
|
||||||
|
|
||||||
const QString prevLineText = previousNonEmptyBlock.text().trimmed();
|
const QString prevLineText = previousNonEmptyBlock.text().trimmed();
|
||||||
if (prevLineText.isEmpty())
|
if (prevLineText.isEmpty())
|
||||||
return CharacterContext::NewStatementOrContinuation;
|
return CharacterContext::NewStatementOrContinuation;
|
||||||
|
|
||||||
const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock);
|
const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock);
|
||||||
if (prevLineText.endsWith(',')) {
|
if (prevLineText.endsWith(',')) {
|
||||||
// We don't need to add comma in case it's the last argument.
|
if (firstNonWhitespaceChar == '}') {
|
||||||
if (firstNonWhitespaceChar == '}' || firstNonWhitespaceChar == ')')
|
if (reverseFindLastBlockWithSymbol(currentBlock, '{').text().trimmed().last(1) == '{')
|
||||||
|
return CharacterContext::NewStatementOrContinuation;
|
||||||
return CharacterContext::LastAfterComma;
|
return CharacterContext::LastAfterComma;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstNonWhitespaceChar == ')') {
|
||||||
|
if (reverseFindLastBlockWithSymbol(currentBlock, '(').text().trimmed().last(1) == '(')
|
||||||
|
return CharacterContext::NewStatementOrContinuation;
|
||||||
|
return CharacterContext::LastAfterComma;
|
||||||
|
}
|
||||||
|
|
||||||
return CharacterContext::AfterComma;
|
return CharacterContext::AfterComma;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,6 +289,14 @@ int forceIndentWithExtraText(QByteArray &buffer,
|
|||||||
if (!block.isValid())
|
if (!block.isValid())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
auto tmpcharContext = characterContext(block);
|
||||||
|
if (charContext == CharacterContext::LastAfterComma
|
||||||
|
&& tmpcharContext == CharacterContext::LastAfterComma) {
|
||||||
|
charContext = CharacterContext::AfterComma;
|
||||||
|
} else {
|
||||||
|
charContext = tmpcharContext;
|
||||||
|
}
|
||||||
|
|
||||||
const QString blockText = block.text();
|
const QString blockText = block.text();
|
||||||
int firstNonWhitespace = Utils::indexOf(blockText,
|
int firstNonWhitespace = Utils::indexOf(blockText,
|
||||||
[](const QChar &ch) { return !ch.isSpace(); });
|
[](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.
|
// If the next line is also empty it's safer to use a comment line.
|
||||||
dummyText = "//";
|
dummyText = "//";
|
||||||
} else if (firstNonWhitespace < 0 || closingParenBlock || closingBraceBlock) {
|
} 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);
|
dummyText = dummyTextForContext(charContext, closingBraceBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -655,4 +655,74 @@ void ClangFormatTest::testClassIndentStructure()
|
|||||||
(std::vector<QString>{"class test {", " Q_OBJECT", "public:", "};"}));
|
(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
|
} // namespace ClangFormat::Internal
|
||||||
|
@@ -110,6 +110,8 @@ private slots:
|
|||||||
void testChainedMemberFunctionCalls();
|
void testChainedMemberFunctionCalls();
|
||||||
void testCommentBlock();
|
void testCommentBlock();
|
||||||
void testClassIndentStructure();
|
void testClassIndentStructure();
|
||||||
|
void testIndentInitializeVector();
|
||||||
|
void testIndentFunctionArgumentOnNewLine();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void insertLines(const std::vector<QString> &lines);
|
void insertLines(const std::vector<QString> &lines);
|
||||||
|
Reference in New Issue
Block a user