[clang-format] Constructor initializer lists format with pp directives

Currently constructor initializer lists sometimes format incorrectly
when there is a preprocessor directive in the middle of the list.
This patch fixes the issue when parsing the initilizer list by
ignoring the preprocessor directive when checking if a block is
part of an initializer list.

rdar://82554274

Reviewed By: MyDeveloperDay, HazardyKnusperkeks

Differential Revision: https://reviews.llvm.org/D109951
This commit is contained in:
Josh Learn 2021-10-02 13:22:49 +01:00 committed by mydeveloperday
parent dd3caa99bd
commit 3d209c76dd
2 changed files with 83 additions and 0 deletions

View File

@ -489,6 +489,17 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
if (Style.Language == FormatStyle::LK_Proto) {
ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
} else {
// Skip NextTok over preprocessor lines, otherwise we may not
// properly diagnose the block as a braced intializer
// if the comma separator appears after the pp directive.
while (NextTok->is(tok::hash)) {
ScopedMacroState MacroState(*Line, Tokens, NextTok);
do {
NextTok = Tokens->getNextToken();
++ReadTokens;
} while (NextTok->isNot(tok::eof));
}
// Using OriginalColumn to distinguish between ObjC methods and
// binary operators is a bit hacky.
bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&

View File

@ -19298,6 +19298,78 @@ TEST_F(FormatTest, BreakConstructorInitializersBeforeComma) {
Style);
}
TEST_F(FormatTest, ConstructorInitializersWithPreprocessorDirective) {
FormatStyle Style = getLLVMStyle();
Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Style.ConstructorInitializerIndentWidth = 4;
verifyFormat("SomeClass::Constructor()\n"
" : a{a}\n"
" , b{b} {}",
Style);
verifyFormat("SomeClass::Constructor()\n"
" : a{a}\n"
"#if CONDITION\n"
" , b{b}\n"
"#endif\n"
"{\n}",
Style);
Style.ConstructorInitializerIndentWidth = 2;
verifyFormat("SomeClass::Constructor()\n"
"#if CONDITION\n"
" : a{a}\n"
"#endif\n"
" , b{b}\n"
" , c{c} {\n}",
Style);
Style.ConstructorInitializerIndentWidth = 0;
verifyFormat("SomeClass::Constructor()\n"
": a{a}\n"
"#ifdef CONDITION\n"
", b{b}\n"
"#else\n"
", c{c}\n"
"#endif\n"
", d{d} {\n}",
Style);
Style.ConstructorInitializerIndentWidth = 4;
verifyFormat("SomeClass::Constructor()\n"
" : a{a}\n"
"#if WINDOWS\n"
"#if DEBUG\n"
" , b{0}\n"
"#else\n"
" , b{1}\n"
"#endif\n"
"#else\n"
"#if DEBUG\n"
" , b{2}\n"
"#else\n"
" , b{3}\n"
"#endif\n"
"#endif\n"
"{\n}",
Style);
verifyFormat("SomeClass::Constructor()\n"
" : a{a}\n"
"#if WINDOWS\n"
" , b{0}\n"
"#if DEBUG\n"
" , c{0}\n"
"#else\n"
" , c{1}\n"
"#endif\n"
"#else\n"
"#if DEBUG\n"
" , c{2}\n"
"#else\n"
" , c{3}\n"
"#endif\n"
" , b{1}\n"
"#endif\n"
"{\n}",
Style);
}
TEST_F(FormatTest, Destructors) {
verifyFormat("void F(int &i) { i.~int(); }");
verifyFormat("void F(int &i) { i->~int(); }");