Index: docs/ClangFormatStyleOptions.rst =================================================================== --- docs/ClangFormatStyleOptions.rst +++ docs/ClangFormatStyleOptions.rst @@ -988,6 +988,21 @@ f(MyMap[{composite, key}]); f(MyMap[{ composite, key }]); new int[3]{1, 2, 3}; new int[3]{ 1, 2, 3 }; +**DanglingParenthesis** (``bool``) + If there is a break after the opening parenthesis, also break + before the closing parenthesis + + .. code-block:: c++ + + true: + someLongFunction( + argument1, argument2 + ); + + false: + someLongFunction( + argument1, argument2); + **DerivePointerAlignment** (``bool``) If ``true``, analyze the formatted file for the most common alignment of ``&`` and ``*``. Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -778,6 +778,20 @@ /// \endcode bool ConstructorInitializerAllOnOneLineOrOnePerLine; + /// \brief If there is a break after the opening parenthesis, also break + /// before the closing parenthesis + /// \code + /// true: + /// someLongFunction( + /// argument1, argument2 + /// ); + /// + /// false: + /// someLongFunction( + /// argument1, argument2); + /// \endcode + bool DanglingParenthesis; + /// \brief The number of characters to use for indentation of constructor /// initializer lists. unsigned ConstructorInitializerIndentWidth; Index: lib/Format/ContinuationIndenter.h =================================================================== --- lib/Format/ContinuationIndenter.h +++ lib/Format/ContinuationIndenter.h @@ -149,12 +149,13 @@ ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking, bool NoLineBreak) : Indent(Indent), LastSpace(LastSpace), NestedBlockIndent(Indent), - BreakBeforeClosingBrace(false), AvoidBinPacking(AvoidBinPacking), - BreakBeforeParameter(false), NoLineBreak(NoLineBreak), - NoLineBreakInOperand(false), LastOperatorWrapped(true), - ContainsLineBreak(false), ContainsUnwrappedBuilder(false), - AlignColons(true), ObjCSelectorNameFound(false), - HasMultipleNestedBlocks(false), NestedBlockInlined(false) {} + BreakBeforeClosingBrace(false), BreakBeforeClosingParen(false), + AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), + NoLineBreak(NoLineBreak), NoLineBreakInOperand(false), + LastOperatorWrapped(true), ContainsLineBreak(false), + ContainsUnwrappedBuilder(false), AlignColons(true), + ObjCSelectorNameFound(false), HasMultipleNestedBlocks(false), + NestedBlockInlined(false) {} /// \brief The position to which a specific parenthesis level needs to be /// indented. @@ -210,6 +211,13 @@ /// was a newline after the beginning left brace. bool BreakBeforeClosingBrace : 1; + /// \brief Whether a newline needs to be inserted before the block's closing + /// paren. + /// + /// We only want to insert a newline before the closing paren if there also + /// was a newline after the beginning left paren. + bool BreakBeforeClosingParen : 1; + /// \brief Avoid bin packing, i.e. multiple parameters/elements on multiple /// lines, in this context. bool AvoidBinPacking : 1; @@ -275,6 +283,8 @@ return FirstLessLess < Other.FirstLessLess; if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace) return BreakBeforeClosingBrace; + if (BreakBeforeClosingParen != Other.BreakBeforeClosingParen) + return BreakBeforeClosingParen; if (QuestionColumn != Other.QuestionColumn) return QuestionColumn < Other.QuestionColumn; if (AvoidBinPacking != Other.AvoidBinPacking) Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -143,6 +143,9 @@ State.Stack.back().NoLineBreakInOperand) return false; + if(Current.is(tok::r_paren) && !State.Stack.back().BreakBeforeClosingParen) + return false; + return !State.Stack.back().NoLineBreak; } @@ -154,6 +157,8 @@ if (State.Stack.back().BreakBeforeClosingBrace && Current.closesBlockOrBlockTypeList(Style)) return true; + if(State.Stack.back().BreakBeforeClosingParen && Current.is(tok::r_paren)) + return true; if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection) return true; if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) || @@ -629,6 +634,9 @@ PreviousNonComment->opensScope()))) State.Stack.back().BreakBeforeClosingBrace = true; + if (PreviousNonComment && PreviousNonComment->is(tok::l_paren)) + State.Stack.back().BreakBeforeClosingParen = Style.DanglingParenthesis; + if (State.Stack.back().AvoidBinPacking) { // If we are breaking after '(', '{', '<', this is not bin packing // unless AllowAllParametersOfDeclarationOnNextLine is false or this is a @@ -674,6 +682,8 @@ return State.Stack[State.Stack.size() - 2].LastSpace; return State.FirstIndent; } + if (Style.DanglingParenthesis && Current.is(tok::r_paren) && State.Stack.size() > 1) + return State.Stack[State.Stack.size() - 2].LastSpace; if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope()) return State.Stack[State.Stack.size() - 2].LastSpace; if (Current.is(tok::identifier) && Current.Next && Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -315,6 +315,7 @@ Style.BreakBeforeInheritanceComma); IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine", Style.ConstructorInitializerAllOnOneLineOrOnePerLine); + IO.mapOptional("DanglingParenthesis", Style.DanglingParenthesis); IO.mapOptional("ConstructorInitializerIndentWidth", Style.ConstructorInitializerIndentWidth); IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth); @@ -541,6 +542,7 @@ LLVMStyle.ColumnLimit = 80; LLVMStyle.CommentPragmas = "^ IWYU pragma:"; LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false; + LLVMStyle.DanglingParenthesis = false; LLVMStyle.ConstructorInitializerIndentWidth = 4; LLVMStyle.ContinuationIndentWidth = 4; LLVMStyle.Cpp11BracedListStyle = true; @@ -606,6 +608,7 @@ GoogleStyle.AlwaysBreakBeforeMultilineStrings = true; GoogleStyle.AlwaysBreakTemplateDeclarations = true; GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true; + GoogleStyle.DanglingParenthesis = false; GoogleStyle.DerivePointerAlignment = true; GoogleStyle.IncludeCategories = {{"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}}; GoogleStyle.IncludeIsMainRegex = "([-_](test|unittest))?$"; Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -2652,7 +2652,9 @@ if (Right.is(TT_ImplicitStringLiteral)) return false; - if (Right.is(tok::r_paren) || Right.is(TT_TemplateCloser)) + if (Right.is(tok::r_paren)) + return Style.DanglingParenthesis; + if (Right.is(TT_TemplateCloser)) return false; if (Right.is(tok::r_square) && Right.MatchingParen && Right.MatchingParen->is(TT_LambdaLSquare)) Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -8757,6 +8757,7 @@ CHECK_PARSE_BOOL(BreakStringLiterals); CHECK_PARSE_BOOL(BreakBeforeInheritanceComma) CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine); + CHECK_PARSE_BOOL(DanglingParenthesis); CHECK_PARSE_BOOL(DerivePointerAlignment); CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding"); CHECK_PARSE_BOOL(DisableFormat);