diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 83716cc049ee3..a8a2c1453f649 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2736,6 +2736,42 @@ the configuration (without a prefix: ``Auto``). @Mock DataLoad loader; +.. _BreakAfterOpenBracketIf: + +**BreakAfterOpenBracketIf** (``Boolean``) :versionbadge:`clang-format 21` :ref:`¶ ` + Force break after the left parenthesis of an if control statement + when the expression exceeds the column limit. + + .. code-block:: c++ + + true: false: + if constexpr ( vs. if constexpr (a || + a || b) b) + +.. _BreakAfterOpenBracketLoop: + +**BreakAfterOpenBracketLoop** (``Boolean``) :versionbadge:`clang-format 21` :ref:`¶ ` + Force break after the left parenthesis of a loop control statement + when the expression exceeds the column limit. + + .. code-block:: c++ + + true: false: + while ( vs. while (a && + a && b) { b) { + +.. _BreakAfterOpenBracketSwitch: + +**BreakAfterOpenBracketSwitch** (``Boolean``) :versionbadge:`clang-format 21` :ref:`¶ ` + Force break after the left parenthesis of a switch control statement + when the expression exceeds the column limit. + + .. code-block:: c++ + + true: false: + switch ( vs. switch (a && + a && b) { b) { + .. _BreakAfterReturnType: **BreakAfterReturnType** (``ReturnTypeBreakingStyle``) :versionbadge:`clang-format 19` :ref:`¶ ` @@ -3373,6 +3409,51 @@ the configuration (without a prefix: ``Auto``). +.. _BreakBeforeCloseBracketIf: + +**BreakBeforeCloseBracketIf** (``Boolean``) :versionbadge:`clang-format 21` :ref:`¶ ` + Force break before the right parenthesis of an if control statement + when the expression exceeds the column limit. The break before the + closing parenthesis is only made if there is a break after the opening + parenthesis. + + .. code-block:: c++ + + true: false: + if constexpr ( vs. if constexpr ( + a || b a || b ) + ) + +.. _BreakBeforeCloseBracketLoop: + +**BreakBeforeCloseBracketLoop** (``Boolean``) :versionbadge:`clang-format 21` :ref:`¶ ` + Force break before the right parenthesis of a loop control statement + when the expression exceeds the column limit. The break before the + closing parenthesis is only made if there is a break after the opening + parenthesis. + + .. code-block:: c++ + + true: false: + while ( vs. while ( + a && b a && b) { + ) { + +.. _BreakBeforeCloseBracketSwitch: + +**BreakBeforeCloseBracketSwitch** (``Boolean``) :versionbadge:`clang-format 21` :ref:`¶ ` + Force break before the right parenthesis of a switch control statement + when the expression exceeds the column limit. The break before the + closing parenthesis is only made if there is a break after the opening + parenthesis. + + .. code-block:: c++ + + true: false: + switch ( vs. switch ( + a && b a && b) { + ) { + .. _BreakBeforeConceptDeclarations: **BreakBeforeConceptDeclarations** (``BreakBeforeConceptDeclarationsStyle``) :versionbadge:`clang-format 12` :ref:`¶ ` diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 648b32c659b4f..0ca0f13332951 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -911,6 +911,9 @@ clang-format ``enum`` enumerator lists. - Add ``OneLineFormatOffRegex`` option for turning formatting off for one line. - Add ``SpaceAfterOperatorKeyword`` option. +- Add ``BreakAfterOpenBracketIf``, ``BreakAfterOpenBracketLoop``, + ``BreakAfterOpenBracketSwitch``, ``BreakBeforeCloseBracketIf``, + ``BreakBeforeCloseBracketLoop``, ``BreakBeforeCloseBracketSwitch`` options. clang-refactor -------------- diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 3ac4318824ac0..38b15d1e54c45 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -62,6 +62,36 @@ struct FormatStyle { /// \version 3.3 int AccessModifierOffset; + /// Force break after the left parenthesis of an if control statement + /// when the expression exceeds the column limit. + /// \code + /// true: false: + /// if constexpr ( vs. if constexpr (a || + /// a || b) b) + /// \endcode + /// \version 21 + bool BreakAfterOpenBracketIf; + + /// Force break after the left parenthesis of a loop control statement + /// when the expression exceeds the column limit. + /// \code + /// true: false: + /// while ( vs. while (a && + /// a && b) { b) { + /// \endcode + /// \version 21 + bool BreakAfterOpenBracketLoop; + + /// Force break after the left parenthesis of a switch control statement + /// when the expression exceeds the column limit. + /// \code + /// true: false: + /// switch ( vs. switch (a && + /// a && b) { b) { + /// \endcode + /// \version 21 + bool BreakAfterOpenBracketSwitch; + /// Different styles for aligning after open brackets. enum BracketAlignmentStyle : int8_t { /// Align parameters on the open bracket, e.g.: @@ -2215,6 +2245,45 @@ struct FormatStyle { /// \version 3.7 BraceBreakingStyle BreakBeforeBraces; + /// Force break before the right parenthesis of an if control statement + /// when the expression exceeds the column limit. The break before the + /// closing parenthesis is only made if there is a break after the opening + /// parenthesis. + /// \code + /// true: false: + /// if constexpr ( vs. if constexpr ( + /// a || b a || b ) + /// ) + /// \endcode + /// \version 21 + bool BreakBeforeCloseBracketIf; + + /// Force break before the right parenthesis of a loop control statement + /// when the expression exceeds the column limit. The break before the + /// closing parenthesis is only made if there is a break after the opening + /// parenthesis. + /// \code + /// true: false: + /// while ( vs. while ( + /// a && b a && b) { + /// ) { + /// \endcode + /// \version 21 + bool BreakBeforeCloseBracketLoop; + + /// Force break before the right parenthesis of a switch control statement + /// when the expression exceeds the column limit. The break before the + /// closing parenthesis is only made if there is a break after the opening + /// parenthesis. + /// \code + /// true: false: + /// switch ( vs. switch ( + /// a && b a && b) { + /// ) { + /// \endcode + /// \version 21 + bool BreakBeforeCloseBracketSwitch; + /// Different ways to break before concept declarations. enum BreakBeforeConceptDeclarationsStyle : int8_t { /// Keep the template declaration line together with ``concept``. @@ -5354,10 +5423,16 @@ struct FormatStyle { BreakAdjacentStringLiterals == R.BreakAdjacentStringLiterals && BreakAfterAttributes == R.BreakAfterAttributes && BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations && + BreakAfterOpenBracketIf == R.BreakAfterOpenBracketIf && + BreakAfterOpenBracketLoop == R.BreakAfterOpenBracketLoop && + BreakAfterOpenBracketSwitch == R.BreakAfterOpenBracketSwitch && BreakAfterReturnType == R.BreakAfterReturnType && BreakArrays == R.BreakArrays && BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators && BreakBeforeBraces == R.BreakBeforeBraces && + BreakBeforeCloseBracketIf == R.BreakBeforeCloseBracketIf && + BreakBeforeCloseBracketLoop == R.BreakBeforeCloseBracketLoop && + BreakBeforeCloseBracketSwitch == R.BreakBeforeCloseBracketSwitch && BreakBeforeConceptDeclarations == R.BreakBeforeConceptDeclarations && BreakBeforeInlineASMColon == R.BreakBeforeInlineASMColon && BreakBeforeTemplateCloser == R.BreakBeforeTemplateCloser && diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 4e4e48f90a89f..5c83c419ef5c4 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -358,10 +358,13 @@ bool ContinuationIndenter::canBreak(const LineState &State) { // Allow breaking before the right parens with block indentation if there was // a break after the left parens, which is tracked by BreakBeforeClosingParen. - if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent && - Current.is(tok::r_paren)) { + bool might_break_before = + Style.BreakBeforeCloseBracketIf || Style.BreakBeforeCloseBracketLoop || + Style.BreakBeforeCloseBracketSwitch || + Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent; + + if (might_break_before && Current.is(tok::r_paren)) return CurrentState.BreakBeforeClosingParen; - } if (Style.BreakBeforeTemplateCloser && Current.is(TT_TemplateCloser)) return CurrentState.BreakBeforeClosingAngle; @@ -814,6 +817,11 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, // parenthesis by disallowing any further line breaks if there is no line // break after the opening parenthesis. Don't break if it doesn't conserve // columns. + auto IsLoopConditional = [&](const FormatToken &Tok) { + return Tok.isOneOf(tok::kw_for, tok::kw_while) || + (Style.isJavaScript() && Tok.is(Keywords.kw_await) && Tok.Previous && + Tok.Previous->is(tok::kw_for)); + }; auto IsOpeningBracket = [&](const FormatToken &Tok) { auto IsStartOfBracedList = [&]() { return Tok.is(tok::l_brace) && Tok.isNot(BK_Block) && @@ -826,25 +834,32 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, if (!Tok.Previous) return true; if (Tok.Previous->isIf()) - return Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak; - return !Tok.Previous->isOneOf(TT_CastRParen, tok::kw_for, tok::kw_while, - tok::kw_switch) && - !(Style.isJavaScript() && Tok.Previous->is(Keywords.kw_await)); + return Style.BreakAfterOpenBracketIf; + if (IsLoopConditional(*Tok.Previous)) + return Style.BreakAfterOpenBracketLoop; + if (Tok.Previous->is(tok::kw_switch)) + return Style.BreakAfterOpenBracketSwitch; + if (Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak || + Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) { + return !Tok.Previous->is(TT_CastRParen) && + !(Style.isJavaScript() && Tok.is(Keywords.kw_await)); + } + return false; }; auto IsFunctionCallParen = [](const FormatToken &Tok) { return Tok.is(tok::l_paren) && Tok.ParameterCount > 0 && Tok.Previous && Tok.Previous->is(tok::identifier); }; - auto IsInTemplateString = [this](const FormatToken &Tok) { + auto IsInTemplateString = [this](const FormatToken &Tok, bool NestBlocks) { if (!Style.isJavaScript()) return false; for (const auto *Prev = &Tok; Prev; Prev = Prev->Previous) { if (Prev->is(TT_TemplateString) && Prev->opensScope()) return true; - if (Prev->opensScope() || - (Prev->is(TT_TemplateString) && Prev->closesScope())) { - break; - } + if (Prev->opensScope() && !NestBlocks) + return false; + if (Prev->is(TT_TemplateString) && Prev->closesScope()) + return false; } return false; }; @@ -866,21 +881,25 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, Tok.isOneOf(tok::ellipsis, Keywords.kw_await))) { return true; } - const auto *Previous = Tok.Previous; - if (!Previous || (!Previous->isOneOf(TT_FunctionDeclarationLParen, - TT_LambdaDefinitionLParen) && - !IsFunctionCallParen(*Previous))) { + const auto *Previous = TokAfterLParen.Previous; + assert(Previous); // IsOpeningBracket(Previous) + if (Previous->Previous && + (Previous->Previous->isIf() || IsLoopConditional(*Previous->Previous) || + Previous->Previous->is(tok::kw_switch))) { + return false; + } + if (!Previous->isOneOf(TT_FunctionDeclarationLParen, + TT_LambdaDefinitionLParen) && + !IsFunctionCallParen(*Previous)) { return true; } - if (IsOpeningBracket(Tok) || IsInTemplateString(Tok)) + if (IsOpeningBracket(Tok) || IsInTemplateString(Tok, true)) return true; const auto *Next = Tok.Next; return !Next || Next->isMemberAccess() || Next->is(TT_FunctionDeclarationLParen) || IsFunctionCallParen(*Next); }; - if ((Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak || - Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) && - IsOpeningBracket(Previous) && State.Column > getNewLineColumn(State) && + if (IsOpeningBracket(Previous) && State.Column > getNewLineColumn(State) && // Don't do this for simple (no expressions) one-argument function calls // as that feels like needlessly wasting whitespace, e.g.: // @@ -910,7 +929,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, !(Current.MacroParent && Previous.MacroParent) && (Current.isNot(TT_LineComment) || Previous.isOneOf(BK_BracedInit, TT_VerilogMultiLineListLParen)) && - !IsInTemplateString(Current)) { + !IsInTemplateString(Current, false)) { CurrentState.Indent = State.Column + Spaces; CurrentState.IsAligned = true; } @@ -1247,8 +1266,28 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, } if (PreviousNonComment && PreviousNonComment->is(tok::l_paren)) { - CurrentState.BreakBeforeClosingParen = - Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent; + auto Previous = PreviousNonComment->Previous; + if (Previous) { + + auto IsLoopConditional = [&](const FormatToken &Tok) { + return Tok.isOneOf(tok::kw_for, tok::kw_while) || + (Style.isJavaScript() && Tok.is(Keywords.kw_await) && + Tok.Previous && Tok.Previous->is(tok::kw_for)); + }; + + if (Previous->isIf()) { + CurrentState.BreakBeforeClosingParen = Style.BreakBeforeCloseBracketIf; + } else if (IsLoopConditional(*Previous)) { + CurrentState.BreakBeforeClosingParen = + Style.BreakBeforeCloseBracketLoop; + } else if (Previous->is(tok::kw_switch)) { + CurrentState.BreakBeforeClosingParen = + Style.BreakBeforeCloseBracketSwitch; + } else { + CurrentState.BreakBeforeClosingParen = + Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent; + } + } } if (PreviousNonComment && PreviousNonComment->is(TT_TemplateOpener)) @@ -1398,6 +1437,11 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { State.Stack.size() > 1) { return State.Stack[State.Stack.size() - 2].LastSpace; } + if ((Style.BreakBeforeCloseBracketIf || Style.BreakBeforeCloseBracketLoop || + Style.BreakBeforeCloseBracketSwitch) && + Current.is(tok::r_paren) && State.Stack.size() > 1) { + return State.Stack[State.Stack.size() - 2].LastSpace; + } if (Style.BreakBeforeTemplateCloser && Current.is(TT_TemplateCloser) && State.Stack.size() > 1) { return State.Stack[State.Stack.size() - 2].LastSpace; diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 0cfa061681053..27dadbb1593b1 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1027,10 +1027,21 @@ template <> struct MappingTraits { IO.mapOptional("BreakAfterAttributes", Style.BreakAfterAttributes); IO.mapOptional("BreakAfterJavaFieldAnnotations", Style.BreakAfterJavaFieldAnnotations); + IO.mapOptional("BreakAfterOpenBracketIf", Style.BreakAfterOpenBracketIf); + IO.mapOptional("BreakAfterOpenBracketLoop", + Style.BreakAfterOpenBracketLoop); + IO.mapOptional("BreakAfterOpenBracketSwitch", + Style.BreakAfterOpenBracketSwitch); IO.mapOptional("BreakAfterReturnType", Style.BreakAfterReturnType); IO.mapOptional("BreakArrays", Style.BreakArrays); IO.mapOptional("BreakBeforeBinaryOperators", Style.BreakBeforeBinaryOperators); + IO.mapOptional("BreakBeforeCloseBracketIf", + Style.BreakBeforeCloseBracketIf); + IO.mapOptional("BreakBeforeCloseBracketLoop", + Style.BreakBeforeCloseBracketLoop); + IO.mapOptional("BreakBeforeCloseBracketSwitch", + Style.BreakBeforeCloseBracketSwitch); IO.mapOptional("BreakBeforeConceptDeclarations", Style.BreakBeforeConceptDeclarations); IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); @@ -1558,10 +1569,16 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.BreakAdjacentStringLiterals = true; LLVMStyle.BreakAfterAttributes = FormatStyle::ABS_Leave; LLVMStyle.BreakAfterJavaFieldAnnotations = false; + LLVMStyle.BreakAfterOpenBracketIf = false; + LLVMStyle.BreakAfterOpenBracketLoop = false; + LLVMStyle.BreakAfterOpenBracketSwitch = false; LLVMStyle.BreakAfterReturnType = FormatStyle::RTBS_None; LLVMStyle.BreakArrays = true; LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None; LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; + LLVMStyle.BreakBeforeCloseBracketIf = false; + LLVMStyle.BreakBeforeCloseBracketLoop = false; + LLVMStyle.BreakBeforeCloseBracketSwitch = false; LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always; LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline; LLVMStyle.BreakBeforeTemplateCloser = false; @@ -1822,6 +1839,9 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { GoogleStyle.SpacesBeforeTrailingComments = 1; } else if (Language == FormatStyle::LK_JavaScript) { GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak; + GoogleStyle.BreakAfterOpenBracketIf = true; + GoogleStyle.BreakAfterOpenBracketLoop = false; + GoogleStyle.BreakAfterOpenBracketSwitch = false; GoogleStyle.AlignOperands = FormatStyle::OAS_DontAlign; GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; // TODO: still under discussion whether to switch to SLS_All. diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 542c362ccacae..17f4175affd14 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -6210,19 +6210,31 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, (Right.isBlockIndentedInitRBrace(Style))); } - // We only break before r_paren if we're in a block indented context. + // We can break before r_paren if we're in a block indented context or + // a control statement with an explicit style option. if (Right.is(tok::r_paren)) { - if (Style.AlignAfterOpenBracket != FormatStyle::BAS_BlockIndent || - !Right.MatchingParen) { + if (!Right.MatchingParen) return false; - } auto Next = Right.Next; if (Next && Next->is(tok::r_paren)) Next = Next->Next; if (Next && Next->is(tok::l_paren)) return false; const FormatToken *Previous = Right.MatchingParen->Previous; - return !(Previous && (Previous->is(tok::kw_for) || Previous->isIf())); + if (!Previous) + return false; + if (Previous->isIf()) + return Style.BreakBeforeCloseBracketIf; + auto IsLoopConditional = [&](const FormatToken &Tok) { + return Tok.isOneOf(tok::kw_for, tok::kw_while) || + (Style.isJavaScript() && Tok.is(Keywords.kw_await) && + Tok.Previous && Tok.Previous->is(tok::kw_for)); + }; + if (IsLoopConditional(*Previous)) + return Style.BreakBeforeCloseBracketLoop; + if (Previous->is(tok::kw_switch)) + return Style.BreakBeforeCloseBracketSwitch; + return Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent; } if (Left.isOneOf(tok::r_paren, TT_TrailingAnnotation) && diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index 5b9055d0a80be..874fb0a309b5c 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -171,6 +171,12 @@ TEST(ConfigParseTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL(BinPackLongBracedList); CHECK_PARSE_BOOL(BreakAdjacentStringLiterals); CHECK_PARSE_BOOL(BreakAfterJavaFieldAnnotations); + CHECK_PARSE_BOOL(BreakAfterOpenBracketIf); + CHECK_PARSE_BOOL(BreakAfterOpenBracketLoop); + CHECK_PARSE_BOOL(BreakAfterOpenBracketSwitch); + CHECK_PARSE_BOOL(BreakBeforeCloseBracketIf); + CHECK_PARSE_BOOL(BreakBeforeCloseBracketLoop); + CHECK_PARSE_BOOL(BreakBeforeCloseBracketSwitch); CHECK_PARSE_BOOL(BreakBeforeTemplateCloser); CHECK_PARSE_BOOL(BreakBeforeTernaryOperators); CHECK_PARSE_BOOL(BreakStringLiterals); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index c0633ba3c29b3..39bcdcad85116 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -9694,6 +9694,339 @@ TEST_F(FormatTest, ParenthesesAndOperandAlignment) { Style); } +TEST_F(FormatTest, AlignAndBreakControlStatements) { + FormatStyle Style = getLLVMStyle(); + + Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign; + Style.BreakAfterOpenBracketIf = true; + Style.BreakAfterOpenBracketLoop = true; + Style.BreakAfterOpenBracketSwitch = true; + + verifyFormat("void foo() {\n" + " if constexpr (\n" + " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbb) == 0) {\n" + " return;\n" + " } else if (\n" + " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbb) == 0) {\n" + " return;\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " switch (\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n" + " default:\n" + " break;\n" + " }\n" + "}", + Style); + + verifyFormat( + "void foo() {\n" + " for (\n" + " aaaaaaaaaaaaaaaaaaaaaa = 0;\n" + " (aaaaaaaaaaaaaaaaaaaaaa->bbbbbbbbbbbbbb |\n" + " aaaaaaaaaaaaaaaaaaaaaa->ccccccccccccccccccccccc) == 0;\n" + " aaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaaaaa->next) {\n" + " ;\n" + " }\n" + "}", + Style); + + verifyFormat( + "void foo() {\n" + " while (\n" + " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) == 0) " + "{\n" + " continue;\n" + " }\n" + "}", + Style); + + Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak; + Style.BreakAfterOpenBracketIf = true; + Style.BreakAfterOpenBracketLoop = true; + Style.BreakAfterOpenBracketSwitch = true; + Style.BreakBeforeCloseBracketIf = false; + Style.BreakBeforeCloseBracketLoop = false; + Style.BreakBeforeCloseBracketSwitch = false; + + verifyFormat("void foo() {\n" + " if constexpr (\n" + " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ") == 0) {\n" + " return;\n" + " } else if (\n" + " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ") == 0) {\n" + " return;\n" + " }\n" + "}", + Style); + Style.BreakAfterOpenBracketIf = false; + verifyFormat("void foo() {\n" + " if constexpr ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbb) ==\n" + " 0) {\n" + " return;\n" + " } else if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbb) == 0) {\n" + " return;\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " switch (\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n" + " default:\n" + " break;\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " for (\n" + " aaaaaaaaaaaaaaaaaaaaaa = 0;\n" + " (aaaaaaaaaaaaaaaaaaaaaa->bbbbbbbbbbbbbb |\n" + " aaaaaaaaaaaaaaaaaaaaaa->ccccccccccccccccccccccc) == 0;\n" + " aaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaaaaa->next) {\n" + " ;\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " while (\n" + " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) == 0) " + "{\n" + " continue;\n" + " }\n" + "}", + Style); + + Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak; + Style.BreakAfterOpenBracketIf = true; + Style.BreakAfterOpenBracketLoop = true; + Style.BreakAfterOpenBracketSwitch = true; + + verifyFormat("void foo() {\n" + " if constexpr (\n" + " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ") == 0) {\n" + " return;\n" + " } else if (\n" + " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ") == 0) {\n" + " return;\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " switch (\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n" + " default:\n" + " break;\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " for (\n" + " aaaaaaaaaaaaaaaaaaaaaa = 0;\n" + " (aaaaaaaaaaaaaaaaaaaaaa->bbbbbbbbbbbbbb |\n" + " aaaaaaaaaaaaaaaaaaaaaa->ccccccccccccccccccccccc) == 0;\n" + " aaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaaaaa->next) {\n" + " ;\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " while (\n" + " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) == 0) " + "{\n" + " continue;\n" + " }\n" + "}", + Style); + + Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak; + Style.BreakAfterOpenBracketIf = false; + Style.BreakAfterOpenBracketLoop = false; + Style.BreakAfterOpenBracketSwitch = false; + + verifyFormat("void foo() {\n" + " if constexpr ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbb) ==\n" + " 0) {\n" + " return;\n" + " } else if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbb) == 0) {\n" + " return;\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " switch (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n" + " default:\n" + " break;\n" + " }\n" + "}", + Style); + + verifyFormat( + "void foo() {\n" + " for (aaaaaaaaaaaaaaaaaaaaaa = 0;\n" + " (aaaaaaaaaaaaaaaaaaaaaa->bbbbbbbbbbbbbb |\n" + " aaaaaaaaaaaaaaaaaaaaaa->ccccccccccccccccccccccc) == 0;\n" + " aaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaaaaa->next) {\n" + " ;\n" + " }\n" + "}", + Style); + + verifyFormat( + "void foo() {\n" + " while ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) == 0) " + "{\n" + " continue;\n" + " }\n" + "}", + Style); + + Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent; + Style.BreakAfterOpenBracketIf = true; + Style.BreakAfterOpenBracketLoop = true; + Style.BreakAfterOpenBracketSwitch = true; + Style.BreakBeforeCloseBracketIf = true; + Style.BreakBeforeCloseBracketLoop = true; + Style.BreakBeforeCloseBracketSwitch = true; + + verifyFormat( + "void foo() {\n" + " if constexpr (\n" + " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) == 0\n" + " ) {\n" + " return;\n" + " } else if (\n" + " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) == 0\n" + " ) {\n" + " return;\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " switch (\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | " + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" + " ) {\n" + " default:\n" + " break;\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " for (\n" + " aaaaaaaaaaaaaaaaaaaaaa = 0;\n" + " (aaaaaaaaaaaaaaaaaaaaaa->bbbbbbbbbbbbbb |\n" + " aaaaaaaaaaaaaaaaaaaaaa->ccccccccccccccccccccccc) == 0;\n" + " aaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaaaaa->next\n" + " ) {\n" + " ;\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " while (\n" + " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) == 0\n" + " ) {\n" + " continue;\n" + " }\n" + "}", + Style); + + Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent; + Style.BreakAfterOpenBracketIf = false; + Style.BreakAfterOpenBracketLoop = false; + Style.BreakAfterOpenBracketSwitch = false; + Style.BreakBeforeCloseBracketIf = false; + Style.BreakBeforeCloseBracketLoop = false; + Style.BreakBeforeCloseBracketSwitch = false; + + verifyFormat("void foo() {\n" + " if constexpr ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbbbbb) ==\n" + " 0) {\n" + " return;\n" + " } else if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbbbb) == 0) {\n" + " return;\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " switch (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n" + " default:\n" + " break;\n" + " }\n" + "}", + Style); + + verifyFormat( + "void foo() {\n" + " for (aaaaaaaaaaaaaaaaaaaaaa = 0;\n" + " (aaaaaaaaaaaaaaaaaaaaaa->bbbbbbbbbbbbbb |\n" + " aaaaaaaaaaaaaaaaaaaaaa->ccccccccccccccccccccccc) == 0;\n" + " aaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaaaaa->next) {\n" + " ;\n" + " }\n" + "}", + Style); + + verifyFormat( + "void foo() {\n" + " while ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) == 0) {\n" + " continue;\n" + " }\n" + "}", + Style); +} + TEST_F(FormatTest, BreaksConditionalExpressions) { verifyFormat( "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaa\n"