-**AlignOperands** (``bool``)
+**AlignOperands** (``OperandAlignmentStyle``)
If ``true``, horizontally align operands of binary and ternary
expressions.
- Specifically, this aligns operands of a single expression that needs to be
- split over multiple lines, e.g.:
+ Possible values:
+
+ * ``OAS_DontAlign`` (in configuration: ``DontAlign``)
+ Do not align operands of binary and ternary expressions.
+ The wrapped lines are indented ``ContinuationIndentWidth`` spaces from
+ the start of the line.
+
+ * ``OAS_Align`` (in configuration: ``Align``)
+ Horizontally align operands of binary and ternary expressions.
+
+ Specifically, this aligns operands of a single expression that needs
+ to be split over multiple lines, e.g.:
+
+ .. code-block:: c++
+
+ int aaa = bbbbbbbbbbbbbbb +
+ ccccccccccccccc;
+
+ When ``BreakBeforeBinaryOperators`` is set, the wrapped operator is
+ aligned with the operand on the first line.
+
+ .. code-block:: c++
+
+ int aaa = bbbbbbbbbbbbbbb
+ + ccccccccccccccc;
+
+ * ``OAS_AlignAfterOperator`` (in configuration: ``AlignAfterOperator``)
+ Horizontally align operands of binary and ternary expressions.
+
+ This is similar to ``AO_Align``, except when
+ ``BreakBeforeBinaryOperators`` is set, the operator is un-indented so
+ that the wrapped operand is aligned with the operand on the first line.
+
+ .. code-block:: c++
+
+ int aaa = bbbbbbbbbbbbbbb
+ + ccccccccccccccc;
- .. code-block:: c++
- int aaa = bbbbbbbbbbbbbbb +
- ccccccccccccccc;
**AlignTrailingComments** (``bool``)
If ``true``, aligns trailing comments.
/// Options for aligning backslashes in escaped newlines.
EscapedNewlineAlignmentStyle AlignEscapedNewlines;
+ /// Different styles for aligning operands.
+ enum OperandAlignmentStyle {
+ /// Do not align operands of binary and ternary expressions.
+ /// The wrapped lines are indented ``ContinuationIndentWidth`` spaces from
+ /// the start of the line.
+ OAS_DontAlign,
+ /// Horizontally align operands of binary and ternary expressions.
+ ///
+ /// Specifically, this aligns operands of a single expression that needs
+ /// to be split over multiple lines, e.g.:
+ /// \code
+ /// int aaa = bbbbbbbbbbbbbbb +
+ /// ccccccccccccccc;
+ /// \endcode
+ ///
+ /// When ``BreakBeforeBinaryOperators`` is set, the wrapped operator is
+ /// aligned with the operand on the first line.
+ /// \code
+ /// int aaa = bbbbbbbbbbbbbbb
+ /// + ccccccccccccccc;
+ /// \endcode
+ OAS_Align,
+ /// Horizontally align operands of binary and ternary expressions.
+ ///
+ /// This is similar to ``AO_Align``, except when
+ /// ``BreakBeforeBinaryOperators`` is set, the operator is un-indented so
+ /// that the wrapped operand is aligned with the operand on the first line.
+ /// \code
+ /// int aaa = bbbbbbbbbbbbbbb
+ /// + ccccccccccccccc;
+ /// \endcode
+ OAS_AlignAfterOperator,
+ };
+
/// If ``true``, horizontally align operands of binary and ternary
/// expressions.
- ///
- /// Specifically, this aligns operands of a single expression that needs to be
- /// split over multiple lines, e.g.:
- /// \code
- /// int aaa = bbbbbbbbbbbbbbb +
- /// ccccccccccccccc;
- /// \endcode
- bool AlignOperands;
+ OperandAlignmentStyle AlignOperands;
/// If ``true``, aligns trailing comments.
/// \code
// does not help.
bool HasTwoOperands =
P->OperatorIndex == 0 && !P->NextOperator && !P->is(TT_ConditionalExpr);
- if ((!BreakBeforeOperator && !(HasTwoOperands && Style.AlignOperands)) ||
+ if ((!BreakBeforeOperator &&
+ !(HasTwoOperands &&
+ Style.AlignOperands != FormatStyle::OAS_DontAlign)) ||
(!State.Stack.back().LastOperatorWrapped && BreakBeforeOperator))
State.Stack.back().NoLineBreakInOperand = true;
}
// BreakBeforeTernaryOperators=true
unsigned Indent =
State.Stack.back().Indent - Style.ContinuationIndentWidth;
+ if (Style.BreakBeforeTernaryOperators &&
+ State.Stack.back().UnindentOperator)
+ Indent -= 2;
return Indent;
}
return State.Stack.back().QuestionColumn;
return ContinuationIndent;
if (Current.is(TT_ProtoExtensionLSquare))
return State.Stack.back().Indent;
+ if (Current.isBinaryOperator() && State.Stack.back().UnindentOperator)
+ return State.Stack.back().Indent - Current.Tok.getLength() -
+ Current.SpacesRequiredBefore;
+ if (Current.isOneOf(tok::comment, TT_BlockComment, TT_LineComment) &&
+ NextNonComment->isBinaryOperator() && State.Stack.back().UnindentOperator)
+ return State.Stack.back().Indent - NextNonComment->Tok.getLength() -
+ NextNonComment->SpacesRequiredBefore;
if (State.Stack.back().Indent == State.FirstIndent && PreviousNonComment &&
!PreviousNonComment->isOneOf(tok::r_brace, TT_CtorInitializerComma))
// Ensure that we fall back to the continuation indent width instead of
(Previous && (Previous->opensScope() ||
Previous->isOneOf(tok::semi, tok::kw_return) ||
(Previous->getPrecedence() == prec::Assignment &&
- Style.AlignOperands) ||
+ Style.AlignOperands != FormatStyle::OAS_DontAlign) ||
Previous->is(TT_ObjCMethodExpr)));
for (SmallVectorImpl<prec::Level>::const_reverse_iterator
I = Current.FakeLParens.rbegin(),
NewParenState.LastOperatorWrapped = true;
NewParenState.IsChainedConditional = false;
NewParenState.IsWrappedConditional = false;
+ NewParenState.UnindentOperator = false;
NewParenState.NoLineBreak =
NewParenState.NoLineBreak || State.Stack.back().NoLineBreakInOperand;
// a builder type call after 'return' or, if the alignment after opening
// brackets is disabled.
if (!Current.isTrailingComment() &&
- (Style.AlignOperands || *I < prec::Assignment) &&
+ (Style.AlignOperands != FormatStyle::OAS_DontAlign ||
+ *I < prec::Assignment) &&
(!Previous || Previous->isNot(tok::kw_return) ||
(Style.Language != FormatStyle::LK_Java && *I > 0)) &&
(Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign ||
- *I != prec::Comma || Current.NestingLevel == 0))
+ *I != prec::Comma || Current.NestingLevel == 0)) {
NewParenState.Indent =
std::max(std::max(State.Column, NewParenState.Indent),
State.Stack.back().LastSpace);
+ }
+
+ // If BreakBeforeBinaryOperators is set, un-indent a bit to account for
+ // the operator and keep the operands aligned
+ if (Style.AlignOperands == FormatStyle::OAS_AlignAfterOperator &&
+ Previous &&
+ (Previous->getPrecedence() == prec::Assignment ||
+ Previous->is(tok::kw_return) ||
+ (*I == prec::Conditional && Previous->is(tok::question) &&
+ Previous->is(TT_ConditionalExpr))) &&
+ !Newline)
+ NewParenState.UnindentOperator = true;
// Do not indent relative to the fake parentheses inserted for "." or "->".
// This is a special case to make the following to statements consistent:
Previous->is(TT_ConditionalExpr) && I == Current.FakeLParens.rbegin() &&
!State.Stack.back().IsWrappedConditional) {
NewParenState.IsChainedConditional = true;
+ NewParenState.UnindentOperator = State.Stack.back().UnindentOperator;
} else if (*I == prec::Conditional ||
(!SkipFirstExtraIndent && *I > prec::Assignment &&
!Current.isTrailingComment())) {
AlignColons(true), ObjCSelectorNameFound(false),
HasMultipleNestedBlocks(false), NestedBlockInlined(false),
IsInsideObjCArrayLiteral(false), IsCSharpGenericTypeConstraint(false),
- IsChainedConditional(false), IsWrappedConditional(false) {}
+ IsChainedConditional(false), IsWrappedConditional(false),
+ UnindentOperator(false) {}
/// \brief The token opening this parenthesis level, or nullptr if this level
/// is opened by fake parenthesis.
/// question mark)
bool IsWrappedConditional : 1;
+ /// \brief Indicates the indent should be reduced by the length of the
+ /// operator.
+ bool UnindentOperator : 1;
+
bool operator<(const ParenState &Other) const {
if (Indent != Other.Indent)
return Indent < Other.Indent;
return IsChainedConditional;
if (IsWrappedConditional != Other.IsWrappedConditional)
return IsWrappedConditional;
+ if (UnindentOperator != Other.UnindentOperator)
+ return UnindentOperator;
return false;
}
};
}
};
+template <> struct ScalarEnumerationTraits<FormatStyle::OperandAlignmentStyle> {
+ static void enumeration(IO &IO, FormatStyle::OperandAlignmentStyle &Value) {
+ IO.enumCase(Value, "DontAlign", FormatStyle::OAS_DontAlign);
+ IO.enumCase(Value, "Align", FormatStyle::OAS_Align);
+ IO.enumCase(Value, "AlignAfterOperator",
+ FormatStyle::OAS_AlignAfterOperator);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "true", FormatStyle::OAS_Align);
+ IO.enumCase(Value, "false", FormatStyle::OAS_DontAlign);
+ }
+};
+
template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) {
IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle);
LLVMStyle.AccessModifierOffset = -2;
LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
- LLVMStyle.AlignOperands = true;
+ LLVMStyle.AlignOperands = FormatStyle::OAS_Align;
LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AlignConsecutiveAssignments = false;
LLVMStyle.AlignConsecutiveDeclarations = false;
if (Language == FormatStyle::LK_Java) {
GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
- GoogleStyle.AlignOperands = false;
+ GoogleStyle.AlignOperands = FormatStyle::OAS_DontAlign;
GoogleStyle.AlignTrailingComments = false;
GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
GoogleStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
GoogleStyle.SpacesBeforeTrailingComments = 1;
} else if (Language == FormatStyle::LK_JavaScript) {
GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
- GoogleStyle.AlignOperands = false;
+ GoogleStyle.AlignOperands = FormatStyle::OAS_DontAlign;
GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
// TODO: still under discussion whether to switch to SLS_All.
GoogleStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_Empty;
FormatStyle Style = getLLVMStyle();
Style.AccessModifierOffset = -4;
Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
- Style.AlignOperands = false;
+ Style.AlignOperands = FormatStyle::OAS_DontAlign;
Style.AlignTrailingComments = false;
Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
" > ccccc) {\n"
"}",
Style);
+ verifyFormat("return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " && bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;",
+ Style);
verifyFormat("return (a)\n"
" // comment\n"
" + b;",
Style.ColumnLimit = 60;
verifyFormat("zzzzzzzzzz\n"
- " = bbbbbbbbbbbbbbbbb\n"
+ " = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
" >> aaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaa);",
Style);
Style.TabWidth = 4;
Style.UseTab = FormatStyle::UT_Always;
Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
- Style.AlignOperands = false;
+ Style.AlignOperands = FormatStyle::OAS_DontAlign;
EXPECT_EQ("return someVeryVeryLongConditionThatBarelyFitsOnALine\n"
"\t&& (someOtherLongishConditionPart1\n"
"\t\t|| someOtherEvenLongerNestedConditionPart2);",
Style));
}
+TEST_F(FormatTest, ExpressionIndentationStrictAlign) {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
+ Style.AlignOperands = FormatStyle::OAS_AlignAfterOperator;
+
+ verifyFormat("bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " > ccccccccccccccccccccccccccccccccccccccccc;",
+ Style);
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " == bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}",
+ Style);
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " == bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}",
+ Style);
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}",
+ Style);
+ verifyFormat("if () {\n"
+ "} else if (aaaaa\n"
+ " && bbbbb // break\n"
+ " > ccccc) {\n"
+ "}",
+ Style);
+ verifyFormat("return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " && bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;",
+ Style);
+ verifyFormat("return (a)\n"
+ " // comment\n"
+ " + b;",
+ Style);
+ verifyFormat(
+ "int aaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " + cc;",
+ Style);
+ verifyFormat("return aaaaaaaaaaaaaaaa ? 1111111111111111\n"
+ " : bbbbbbbbbbbbbbbb ? 2222222222222222\n"
+ " : 3333333333333333;",
+ Style);
+ verifyFormat(
+ "return aaaaaaaaaaaaaaaa ? (aaaaaaaaaaaaaa ? bbbbbbbbbbbbbbbbbb\n"
+ " : ccccccccccccccc ? dddddddddddddddddd\n"
+ " : eeeeeeeeeeeeeeeeee)\n"
+ " : bbbbbbbbbbbbbbbb ? 2222222222222222\n"
+ " : 3333333333333333;",
+ Style);
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " = aaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ Style);
+
+ verifyFormat("return boost::fusion::at_c<0>(iiii).second\n"
+ " == boost::fusion::at_c<1>(iiii).second;",
+ Style);
+
+ Style.ColumnLimit = 60;
+ verifyFormat("zzzzzzzzzzzzz\n"
+ " = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ " >> aaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ Style);
+
+ // Forced by comments.
+ Style.ColumnLimit = 80;
+ verifyFormat(
+ "unsigned ContentSize\n"
+ " = sizeof(int16_t) // DWARF ARange version number\n"
+ " + sizeof(int32_t) // Offset of CU in the .debug_info section\n"
+ " + sizeof(int8_t) // Pointer Size (in bytes)\n"
+ " + sizeof(int8_t); // Segment Size (in bytes)",
+ Style);
+
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
+ verifyFormat(
+ "unsigned ContentSize =\n"
+ " sizeof(int16_t) // DWARF ARange version number\n"
+ " + sizeof(int32_t) // Offset of CU in the .debug_info section\n"
+ " + sizeof(int8_t) // Pointer Size (in bytes)\n"
+ " + sizeof(int8_t); // Segment Size (in bytes)",
+ Style);
+
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
+ verifyFormat(
+ "unsigned ContentSize =\n"
+ " sizeof(int16_t) // DWARF ARange version number\n"
+ " + sizeof(int32_t) // Offset of CU in the .debug_info section\n"
+ " + sizeof(int8_t) // Pointer Size (in bytes)\n"
+ " + sizeof(int8_t); // Segment Size (in bytes)",
+ Style);
+}
+
TEST_F(FormatTest, EnforcedOperatorWraps) {
// Here we'd like to wrap after the || operators, but a comment is forcing an
// earlier wrap.
TEST_F(FormatTest, NoOperandAlignment) {
FormatStyle Style = getLLVMStyle();
- Style.AlignOperands = false;
+ Style.AlignOperands = FormatStyle::OAS_DontAlign;
verifyFormat("aaaaaaaaaaaaaa(aaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
" bbbbbbbbbbbbbbbbbbbbbb);",
Style);
Style.AlignAfterOpenBracket = FormatStyle::BAS_Align;
- Style.AlignOperands = false;
+ Style.AlignOperands = FormatStyle::OAS_DontAlign;
verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n"
" bbbbbbbbbbbbbbbbbbbbbb);",
Style);
Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
- Style.AlignOperands = true;
+ Style.AlignOperands = FormatStyle::OAS_Align;
verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n"
" bbbbbbbbbbbbbbbbbbbbbb);",
Style);
Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
- Style.AlignOperands = false;
+ Style.AlignOperands = FormatStyle::OAS_DontAlign;
verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n"
" bbbbbbbbbbbbbbbbbbbbbb);",
Style);
// Chained conditionals
FormatStyle Style = getLLVMStyle();
Style.ColumnLimit = 70;
- Style.AlignOperands = true;
+ Style.AlignOperands = FormatStyle::OAS_Align;
verifyFormat("return aaaaaaaaaaaaaaaa ? 1111111111111111\n"
" : bbbbbbbbbbbbbb ? 2222222222222222\n"
" : 3333333333333333;",
TEST_F(FormatTest, ParsesConfigurationBools) {
FormatStyle Style = {};
Style.Language = FormatStyle::LK_Cpp;
- CHECK_PARSE_BOOL(AlignOperands);
CHECK_PARSE_BOOL(AlignTrailingComments);
CHECK_PARSE_BOOL(AlignConsecutiveAssignments);
CHECK_PARSE_BOOL(AlignConsecutiveDeclarations);
CHECK_PARSE("AlignEscapedNewlinesLeft: false", AlignEscapedNewlines,
FormatStyle::ENAS_Right);
+ Style.AlignOperands = FormatStyle::OAS_Align;
+ CHECK_PARSE("AlignOperands: DontAlign", AlignOperands,
+ FormatStyle::OAS_DontAlign);
+ CHECK_PARSE("AlignOperands: Align", AlignOperands, FormatStyle::OAS_Align);
+ CHECK_PARSE("AlignOperands: AlignAfterOperator", AlignOperands,
+ FormatStyle::OAS_AlignAfterOperator);
+ // For backward compatibility:
+ CHECK_PARSE("AlignOperands: false", AlignOperands,
+ FormatStyle::OAS_DontAlign);
+ CHECK_PARSE("AlignOperands: true", AlignOperands, FormatStyle::OAS_Align);
+
Style.UseTab = FormatStyle::UT_ForIndentation;
CHECK_PARSE("UseTab: Never", UseTab, FormatStyle::UT_Never);
CHECK_PARSE("UseTab: ForIndentation", UseTab, FormatStyle::UT_ForIndentation);
verifyFormat("var x = aaaaaaaaaaaaaaaaaaaaaaaaa() in\n"
" aaaa.aaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
FormatStyle Style = getGoogleJSStyleWithColumns(80);
- Style.AlignOperands = true;
+ Style.AlignOperands = FormatStyle::OAS_Align;
verifyFormat("var x = aaaaaaaaaaaaaaaaaaaaaaaaa() in\n"
" aaaa.aaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
Style);