diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -361,7 +361,10 @@ return true; } if (CurrentState.BreakBeforeClosingBrace && - Current.closesBlockOrBlockTypeList(Style)) { + (Current.closesBlockOrBlockTypeList(Style) || + (Current.is(tok::r_brace) && Style.Cpp11BracedListStyle && + Current.MatchingParen->isOneOf(BK_BracedInit, BK_ListInit) && + Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent))) { return true; } if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren)) @@ -1167,7 +1170,10 @@ return State.Stack[State.Stack.size() - 2].LastSpace; } if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent && - Current.is(tok::r_paren) && State.Stack.size() > 1) { + (Current.is(tok::r_paren) || + (Current.is(tok::r_brace) && + Current.MatchingParen->isOneOf(BK_BracedInit, BK_ListInit))) && + State.Stack.size() > 1) { return State.Stack[State.Stack.size() - 2].LastSpace; } if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope()) diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -182,7 +182,7 @@ const char *getTokenTypeName(TokenType Type); // Represents what type of block a set of braces open. -enum BraceBlockKind { BK_Unknown, BK_Block, BK_BracedInit }; +enum BraceBlockKind { BK_Unknown, BK_Block, BK_BracedInit, BK_ListInit }; // The packing kind of a function's parameters. enum ParameterPackingKind { PPK_BinPacked, PPK_OnePerLine, PPK_Inconclusive }; diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp --- a/clang/lib/Format/FormatToken.cpp +++ b/clang/lib/Format/FormatToken.cpp @@ -81,6 +81,12 @@ return true; if (is(TT_TemplateString) && opensScope()) return true; + // Indent C/C++ initializer lists as continuations. + if (is(tok::l_brace) && + (getBlockKind() == BK_BracedInit || getBlockKind() == BK_ListInit) && + Style.Cpp11BracedListStyle && Style.Language == FormatStyle::LK_Cpp) { + return false; + } return is(TT_ArrayInitializerLSquare) || is(TT_ProtoExtensionLSquare) || (is(tok::l_brace) && (getBlockKind() == BK_Block || is(TT_DictLiteral) || diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -856,7 +856,7 @@ ScopedContextCreator ContextCreator(*this, tok::l_brace, 1); Contexts.back().ColonIsDictLiteral = true; - if (OpeningBrace.is(BK_BracedInit)) + if (OpeningBrace.isOneOf(BK_BracedInit, BK_ListInit)) Contexts.back().IsExpression = true; if (Style.isJavaScript() && OpeningBrace.Previous && OpeningBrace.Previous->is(TT_JsTypeColon)) { @@ -4203,7 +4203,7 @@ if (Left.is(tok::kw_operator)) return Right.is(tok::coloncolon); - if (Right.is(tok::l_brace) && Right.is(BK_BracedInit) && + if (Right.is(tok::l_brace) && Right.isOneOf(BK_BracedInit, BK_ListInit) && !Left.opensScope() && Style.SpaceBeforeCpp11BracedList) { return true; } @@ -5444,7 +5444,10 @@ // We only break before r_brace if there was a corresponding break before // the l_brace, which is tracked by BreakBeforeClosingBrace. if (Right.is(tok::r_brace)) - return Right.MatchingParen && Right.MatchingParen->is(BK_Block); + return Right.MatchingParen && (Right.MatchingParen->is(BK_Block) || + (Right.MatchingParen->isOneOf(BK_BracedInit, BK_ListInit) && + Style.Cpp11BracedListStyle && + Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent)); // We only break before r_paren if we're in a block indented context. if (Right.is(tok::r_paren)) { diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1977,6 +1977,8 @@ // initialisers are indented the same way. if (Style.isCSharp()) FormatTok->setBlockKind(BK_BracedInit); + else if (Style.isCpp()) + FormatTok->setBlockKind(BK_ListInit); nextToken(); parseBracedList(); } else if (Style.Language == FormatStyle::LK_Proto && diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -4929,7 +4929,7 @@ " \"zzzzzzzzzzzzzzzz\"};\n", Style); // Designated initializers. - verifyFormat("int LooooooooooooooooooooooooongVariable[1] = {\n" + verifyFormat("int LooooooooooooooooooooooooongVariable[2] = {\n" " [0] = 10000000, [1] = 20000000};", Style); verifyFormat("SomeStruct s{\n" @@ -5039,7 +5039,7 @@ " bar,\n" " },\n" " SomeArrayT{},\n" - "}\n", + "};\n", Style); verifyFormat("SomeArrayT a[3] = {\n" " {foo},\n" @@ -5056,7 +5056,7 @@ " },\n" " },\n" " {baz},\n" - "}\n", + "};\n", Style); // Aligning after open braces unaffected by BracedInitializerIndentWidth. @@ -25494,6 +25494,155 @@ Style); } +TEST_F(FormatTest, AlignAfterOpenBracketBlockIndentInitializers) { + auto Style = getLLVMStyleWithColumns(60); + Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent; + // Aggregate initialization. + verifyFormat("int LooooooooooooooooooooooooongVariable[2] = {\n" + " 10000000, 20000000\n" + "};", + Style); + verifyFormat("SomeStruct s{\n" + " \"xxxxxxxxxxxxxxxx\", \"yyyyyyyyyyyyyyyy\",\n" + " \"zzzzzzzzzzzzzzzz\"\n" + "};", + Style); + // Designated initializers. + verifyFormat("int LooooooooooooooooooooooooongVariable[2] = {\n" + " [0] = 10000000, [1] = 20000000\n" + "};", + Style); + verifyFormat("SomeStruct s{\n" + " .foo = \"xxxxxxxxxxxxx\",\n" + " .bar = \"yyyyyyyyyyyyy\",\n" + " .baz = \"zzzzzzzzzzzzz\"\n" + "};\n", + Style); + // List initialization. + verifyFormat("SomeStruct s{\n" + " \"xxxxxxxxxxxxx\",\n" + " \"yyyyyyyyyyyyy\",\n" + " \"zzzzzzzzzzzzz\",\n" + "};\n", + Style); + verifyFormat("SomeStruct{\n" + " \"xxxxxxxxxxxxx\",\n" + " \"yyyyyyyyyyyyy\",\n" + " \"zzzzzzzzzzzzz\",\n" + "};\n", + Style); + verifyFormat("new SomeStruct{\n" + " \"xxxxxxxxxxxxx\",\n" + " \"yyyyyyyyyyyyy\",\n" + " \"zzzzzzzzzzzzz\",\n" + "};\n", + Style); + // Member initializer. + verifyFormat("class SomeClass {\n" + " SomeStruct s{\n" + " \"xxxxxxxxxxxxx\",\n" + " \"yyyyyyyyyyyyy\",\n" + " \"zzzzzzzzzzzzz\",\n" + " };\n" + "};\n", + Style); + // Constructor member initializer. + verifyFormat("SomeClass::SomeClass : strct{\n" + " \"xxxxxxxxxxxxx\",\n" + " \"yyyyyyyyyyyyy\",\n" + " \"zzzzzzzzzzzzz\",\n" + " } {}\n", + Style); + // Copy initialization. + verifyFormat("SomeStruct s = SomeStruct{\n" + " \"xxxxxxxxxxxxx\",\n" + " \"yyyyyyyyyyyyy\",\n" + " \"zzzzzzzzzzzzz\",\n" + "};\n", + Style); + // Copy list initialization. + verifyFormat("SomeStruct s = {\n" + " \"xxxxxxxxxxxxx\",\n" + " \"yyyyyyyyyyyyy\",\n" + " \"zzzzzzzzzzzzz\",\n" + "};\n", + Style); + // Assignment operand initialization. + verifyFormat("s = {\n" + " \"xxxxxxxxxxxxx\",\n" + " \"yyyyyyyyyyyyy\",\n" + " \"zzzzzzzzzzzzz\",\n" + "};\n", + Style); + // Returned object initialization. + verifyFormat("return {\n" + " \"xxxxxxxxxxxxx\",\n" + " \"yyyyyyyyyyyyy\",\n" + " \"zzzzzzzzzzzzz\",\n" + "};\n", + Style); + // Initializer list. + verifyFormat("auto initializerList = {\n" + " \"xxxxxxxxxxxxx\",\n" + " \"yyyyyyyyyyyyy\",\n" + " \"zzzzzzzzzzzzz\",\n" + "};\n", + Style); + // Function parameter initialization. + verifyFormat("func({\n" + " \"xxxxxxxxxxxxx\",\n" + " \"yyyyyyyyyyyyy\",\n" + " \"zzzzzzzzzzzzz\",\n" + "});\n", + Style); + // Nested init lists. + verifyFormat("SomeStruct s = {\n" + " {{init1, init2, init3, init4, init5},\n" + " {init1, init2, init3, init4, init5}}\n" + "};\n", + Style); + verifyFormat("SomeStruct s = {\n" + " {{\n" + " .init1 = 1,\n" + " .init2 = 2,\n" + " .init3 = 3,\n" + " .init4 = 4,\n" + " .init5 = 5,\n" + " },\n" + " {init1, init2, init3, init4, init5}}\n" + "};\n", + Style); + verifyFormat("SomeArrayT a[3] = {\n" + " {\n" + " foo,\n" + " bar,\n" + " },\n" + " {\n" + " foo,\n" + " bar,\n" + " },\n" + " SomeArrayT{},\n" + "};\n", + Style); + verifyFormat("SomeArrayT a[3] = {\n" + " {foo},\n" + " {\n" + " {\n" + " init1,\n" + " init2,\n" + " init3,\n" + " },\n" + " {\n" + " init1,\n" + " init2,\n" + " init3,\n" + " },\n" + " },\n" + " {baz},\n" + "};\n", + Style); +} + TEST_F(FormatTest, UnderstandsDigraphs) { verifyFormat("int arr<:5:> = {};"); verifyFormat("int arr[5] = <%%>;");