diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -241,7 +241,7 @@ .. warning:: - Note: This currently only applies to parentheses. + Note: This currently only applies to parentheses and braced list initializers when ``Cpp11BracedListStyle`` is ``True``. 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,8 @@ return true; } if (CurrentState.BreakBeforeClosingBrace && - Current.closesBlockOrBlockTypeList(Style)) { + (Current.closesBlockOrBlockTypeList(Style) || + Current.isBlockIndentedInitRBrace(Style))) { return true; } if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren)) @@ -1167,7 +1168,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->is(BK_BracedInit))) && + 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 @@ -774,6 +774,9 @@ return Tok; } + /// Returns \c true if this token ends a block indented initializer list. + [[nodiscard]] bool isBlockIndentedInitRBrace(const FormatStyle &Style) const; + /// Returns \c true if this tokens starts a block-type list, i.e. a /// list that should be indented with a block indent. [[nodiscard]] bool opensBlockOrBlockTypeList(const FormatStyle &Style) const; 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 @@ -75,6 +75,22 @@ return isSimpleTypeSpecifier() || Tok.isOneOf(tok::kw_auto, tok::identifier); } +bool FormatToken::isBlockIndentedInitRBrace(const FormatStyle &Style) const { + if (isNot(tok::r_brace)) + return false; + if (Style.Cpp11BracedListStyle != true || + Style.AlignAfterOpenBracket != FormatStyle::BAS_BlockIndent) { + return false; + } + auto LBrace = MatchingParen; + assert(LBrace); + if (LBrace->is(BK_BracedInit)) + return true; + if (LBrace->Previous && LBrace->Previous->is(tok::equal)) + return true; + return false; +} + bool FormatToken::opensBlockOrBlockTypeList(const FormatStyle &Style) const { // C# Does not indent object initialisers as continuations. if (is(tok::l_brace) && getBlockKind() == BK_BracedInit && Style.isCSharp()) 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 @@ -5443,8 +5443,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); + if (Right.is(tok::r_brace)) { + return Right.MatchingParen && (Right.MatchingParen->is(BK_Block) || + (Right.isBlockIndentedInitRBrace(Style))); + } // We only break before r_paren if we're in a block indented context. if (Right.is(tok::r_paren)) { 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", + "};", Style); verifyFormat("SomeArrayT a[3] = {\n" " {foo},\n" @@ -5056,7 +5056,7 @@ " },\n" " },\n" " {baz},\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] = <%%>;");