clang-format: Break before/between array subscript expressions.
clang-format used to treat array subscript expressions much like
function call (just replacing () with []). However, this is not really
appropriate especially for expressions with multiple subscripts.
Although it might seem counter-intuitive, the most consistent solution
seems to be to always (if necessary) break before a square bracket,
never after it. Also, multiple subscripts of the same expression should
be aligned if they are on subsequent lines.
Before:
aaaaaaaaaaaaaaaaaaaaaaaaa[aaaaaaaaaaaaaaaaaaaaaaaaa][
bbbbbbbbbbbbbbbbbbbbbbbbb] = c;
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa][
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = ccccccccccc;
After:
aaaaaaaaaaaaaaaaaaaaaaaaa[aaaaaaaaaaaaaaaaaaaaaaaaa]
[bbbbbbbbbbbbbbbbbbbbbbbbb] = c;
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
[bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = ccccccccccc;
llvm-svn: 186153
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index a98d565..b1f9f4c 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -334,8 +334,8 @@
BreakBeforeClosingBrace(false), QuestionColumn(0),
AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0),
- NestedNameSpecifierContinuation(0), CallContinuation(0),
- VariablePos(0), ContainsLineBreak(false) {}
+ StartOfArraySubscripts(0), NestedNameSpecifierContinuation(0),
+ CallContinuation(0), VariablePos(0), ContainsLineBreak(false) {}
/// \brief The position to which a specific parenthesis level needs to be
/// indented.
@@ -381,6 +381,10 @@
/// \brief The start of the most recent function in a builder-type call.
unsigned StartOfFunctionCall;
+ /// \brief Contains the start of array subscript expressions, so that they
+ /// can be aligned.
+ unsigned StartOfArraySubscripts;
+
/// \brief If a nested name specifier was broken over multiple lines, this
/// contains the start column of the second line. Otherwise 0.
unsigned NestedNameSpecifierContinuation;
@@ -422,6 +426,8 @@
return ColonPos < Other.ColonPos;
if (StartOfFunctionCall != Other.StartOfFunctionCall)
return StartOfFunctionCall < Other.StartOfFunctionCall;
+ if (StartOfArraySubscripts != Other.StartOfArraySubscripts)
+ return StartOfArraySubscripts < Other.StartOfArraySubscripts;
if (CallContinuation != Other.CallContinuation)
return CallContinuation < Other.CallContinuation;
if (VariablePos != Other.VariablePos)
@@ -571,6 +577,12 @@
State.Column = State.Stack.back().Indent;
State.Stack.back().ColonPos = State.Column + Current.CodePointCount;
}
+ } else if (Current.is(tok::l_square) &&
+ Current.Type != TT_ObjCMethodExpr) {
+ if (State.Stack.back().StartOfArraySubscripts != 0)
+ State.Column = State.Stack.back().StartOfArraySubscripts;
+ else
+ State.Column = ContinuationIndent;
} else if (Current.Type == TT_StartOfName ||
Previous.isOneOf(tok::coloncolon, tok::equal) ||
Previous.Type == TT_ObjCMethodExpr) {
@@ -730,6 +742,9 @@
State.Stack.back().AvoidBinPacking = true;
if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0)
State.Stack.back().FirstLessLess = State.Column;
+ if (Current.is(tok::l_square) &&
+ State.Stack.back().StartOfArraySubscripts == 0)
+ State.Stack.back().StartOfArraySubscripts = State.Column;
if (Current.is(tok::question))
State.Stack.back().QuestionColumn = State.Column;
if (!Current.opensScope() && !Current.closesScope())
@@ -835,6 +850,12 @@
State.Stack.pop_back();
--State.ParenLevel;
}
+ if (Current.is(tok::r_square)) {
+ // If this ends the array subscript expr, reset the corresponding value.
+ const FormatToken *NextNonComment = Current.getNextNonComment();
+ if (NextNonComment && NextNonComment->isNot(tok::l_square))
+ State.Stack.back().StartOfArraySubscripts = 0;
+ }
// Remove scopes created by fake parenthesis.
for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {