From: Daniel Jasper Date: Fri, 12 Jul 2013 11:19:37 +0000 (+0000) Subject: clang-format: Break before/between array subscript expressions. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=011c35dabb4c8abcb7389d8fbc6316f8f23576ab;p=clang 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; git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186153 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index a98d565caa..b1f9f4c85b 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -334,8 +334,8 @@ private: 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 @@ private: /// \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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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) { diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 259378157e..cdac8ab686 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -1017,6 +1017,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, return 0; if (Left.is(tok::comma)) return 1; + if (Right.is(tok::l_square)) + return 150; if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator)) { if (Line.First->is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt) @@ -1296,7 +1298,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, (Left.is(tok::r_paren) && Right.isOneOf(tok::identifier, tok::kw_const, tok::kw___attribute)) || (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) || - (Left.is(tok::l_square) && !Right.is(tok::r_square)); + Right.is(tok::l_square); } void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 6e53f92e5a..50f033ccab 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -2121,10 +2121,10 @@ TEST_F(FormatTest, PreventConfusingIndents) { " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n" " aaaaaaaaaaaaaaaaaaaaaaaa);"); verifyFormat( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[\n" - " aaaaaaaaaaaaaaaaaaaaaaaa[\n" - " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa],\n" - " aaaaaaaaaaaaaaaaaaaaaaaa];"); + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " [aaaaaaaaaaaaaaaaaaaaaaaa\n" + " [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]\n" + " [aaaaaaaaaaaaaaaaaaaaaaaa]];"); verifyFormat( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<\n" " aaaaaaaaaaaaaaaaaaaaaaaa<\n" @@ -3593,11 +3593,11 @@ TEST_F(FormatTest, FormatsCasts) { verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *foo = (aaaaaaaaaaaaaaaaa *)\n" " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;"); + // FIXME: The indentation here is not ideal. verifyFormat( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[\n" - " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] =\n" - " (*cccccccccccccccc)[\n" - " dddddddddddddddddddddddddddddddddddddddddddddddddddddddd];"); + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = (*cccccccccccccccc)\n" + " [dddddddddddddddddddddddddddddddddddddddddddddddddddddddd];"); } TEST_F(FormatTest, FormatsFunctionTypes) { @@ -3677,6 +3677,22 @@ TEST_F(FormatTest, BreaksLongDeclarations) { " int aaaaaaaaaaaaaaaaaaaaaaa);"); } +TEST_F(FormatTest, FormatsArrays) { + verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaa[aaaaaaaaaaaaaaaaaaaaaaaaa]\n" + " [bbbbbbbbbbbbbbbbbbbbbbbbb] = c;"); + verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = ccccccccccc;"); + verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " [a][bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = cccccccc;"); + verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]\n" + " [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = ccccccccccc;"); + verifyFormat( + "llvm::outs() << \"aaaaaaaaaaaa: \"\n" + " << (*aaaaaaaiaaaaaaa)[aaaaaaaaaaaaaaaaaaaaaaaaa]\n" + " [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];"); +} + TEST_F(FormatTest, LineStartsWithSpecialCharacter) { verifyFormat("(a)->b();"); verifyFormat("--a;");