From 1e171ff6b26339e29ca16e144644b85e5c85dc06 Mon Sep 17 00:00:00 2001 From: Daniel Jasper Date: Mon, 14 Apr 2014 11:08:45 +0000 Subject: [PATCH] clang-format: Don't allow hanging indentation for operators on new lines Before: if (aaaaaaaa && bbbbbbbbbbbbbbb // need to wrap == cccccccccccccc) ... After: if (aaaaaaaa && bbbbbbbbbbbbbbb // need to wrap == cccccccccccccc) ... The same rule has already be implemented for BreakBeforeBinaryOperators set to false in r205527. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206159 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Format/ContinuationIndenter.cpp | 38 +++++++++++++++++++---------- lib/Format/ContinuationIndenter.h | 16 ++++++++---- lib/Format/TokenAnnotator.cpp | 6 ++++- unittests/Format/FormatTest.cpp | 13 ++++++++-- 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index d25ab68e39..53b5867965 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -173,8 +173,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { if (Previous.Type == TT_BinaryOperator && (!IsComparison || LHSIsBinaryExpr) && Current.Type != TT_BinaryOperator && // For >>. - !Current.isTrailingComment() && - !Previous.isOneOf(tok::lessless, tok::question) && + !Current.isTrailingComment() && !Previous.is(tok::lessless) && Previous.getPrecedence() != prec::Assignment && State.Stack.back().BreakBeforeParameter) return true; @@ -485,7 +484,8 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { } } if (State.Stack.back().QuestionColumn != 0 && - (NextNonComment->Type == TT_ConditionalExpr || + ((NextNonComment->is(tok::colon) && + NextNonComment->Type == TT_ConditionalExpr) || Previous.Type == TT_ConditionalExpr)) return State.Stack.back().QuestionColumn; if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0) @@ -547,9 +547,15 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, if (Current.Type == TT_InheritanceColon) State.Stack.back().AvoidBinPacking = true; - if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator && - State.Stack.back().FirstLessLess == 0) - State.Stack.back().FirstLessLess = State.Column; + if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator) { + if (State.Stack.back().FirstLessLess == 0) + State.Stack.back().FirstLessLess = State.Column; + else + State.Stack.back().LastOperatorWrapped = Newline; + } + if ((Current.Type == TT_BinaryOperator && Current.isNot(tok::lessless)) || + Current.Type == TT_ConditionalExpr) + State.Stack.back().LastOperatorWrapped = Newline; if (Current.Type == TT_ArraySubscriptLSquare && State.Stack.back().StartOfArraySubscripts == 0) State.Stack.back().StartOfArraySubscripts = State.Column; @@ -615,13 +621,19 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, // there is a line-break right after the operator. // Exclude relational operators, as there, it is always more desirable to // have the LHS 'left' of the RHS. - // FIXME: Implement this for '<<' and BreakBeforeBinaryOperators. - if (!Newline && Previous && Previous->Type == TT_BinaryOperator && - !Previous->isOneOf(tok::lessless, tok::question, tok::colon) && - Previous->getPrecedence() > prec::Assignment && - Previous->getPrecedence() != prec::Relational && - !Style.BreakBeforeBinaryOperators) - NewParenState.NoLineBreak = true; + if (Previous && Previous->getPrecedence() > prec::Assignment && + (Previous->Type == TT_BinaryOperator || + Previous->Type == TT_ConditionalExpr) && + Previous->getPrecedence() != prec::Relational) { + bool BreakBeforeOperator = Previous->is(tok::lessless) || + (Previous->Type == TT_BinaryOperator && + Style.BreakBeforeBinaryOperators) || + (Previous->Type == TT_ConditionalExpr && + Style.BreakBeforeTernaryOperators); + if ((!Newline && !BreakBeforeOperator) || + (!State.Stack.back().LastOperatorWrapped && BreakBeforeOperator)) + NewParenState.NoLineBreak = true; + } // Do not indent relative to the fake parentheses inserted for "." or "->". // This is a special case to make the following to statements consistent: diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h index 04e31e68b1..e8a9131e8b 100644 --- a/lib/Format/ContinuationIndenter.h +++ b/lib/Format/ContinuationIndenter.h @@ -135,11 +135,11 @@ struct ParenState { : Indent(Indent), IndentLevel(IndentLevel), LastSpace(LastSpace), FirstLessLess(0), BreakBeforeClosingBrace(false), QuestionColumn(0), AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), - NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0), - StartOfArraySubscripts(0), NestedNameSpecifierContinuation(0), - CallContinuation(0), VariablePos(0), ContainsLineBreak(false), - ContainsUnwrappedBuilder(0), AlignColons(true), - ObjCSelectorNameFound(false), LambdasFound(0) {} + NoLineBreak(NoLineBreak), LastOperatorWrapped(true), ColonPos(0), + StartOfFunctionCall(0), StartOfArraySubscripts(0), + NestedNameSpecifierContinuation(0), CallContinuation(0), VariablePos(0), + ContainsLineBreak(false), ContainsUnwrappedBuilder(0), + AlignColons(true), ObjCSelectorNameFound(false), LambdasFound(0) {} /// \brief The position to which a specific parenthesis level needs to be /// indented. @@ -182,6 +182,10 @@ struct ParenState { /// \brief Line breaking in this context would break a formatting rule. bool NoLineBreak; + /// \brief True if the last binary operator on this level was wrapped to the + /// next line. + bool LastOperatorWrapped; + /// \brief The position of the colon in an ObjC method declaration/call. unsigned ColonPos; @@ -253,6 +257,8 @@ struct ParenState { return BreakBeforeParameter; if (NoLineBreak != Other.NoLineBreak) return NoLineBreak; + if (LastOperatorWrapped != Other.LastOperatorWrapped) + return LastOperatorWrapped; if (ColonPos != Other.ColonPos) return ColonPos < Other.ColonPos; if (StartOfFunctionCall != Other.StartOfFunctionCall) diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 016deecd9e..b81bf91c78 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -735,6 +735,8 @@ private: Current.Type = determineIncrementUsage(Current); } else if (Current.is(tok::exclaim)) { Current.Type = TT_UnaryOperator; + } else if (Current.is(tok::question)) { + Current.Type = TT_ConditionalExpr; } else if (Current.isBinaryOperator() && (!Current.Previous || Current.Previous->isNot(tok::l_square))) { @@ -858,6 +860,7 @@ private: tok::comma, tok::semi, tok::kw_return, tok::colon, tok::equal, tok::kw_delete, tok::kw_sizeof) || PrevToken->Type == TT_BinaryOperator || + PrevToken->Type == TT_ConditionalExpr || PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen) return TT_UnaryOperator; @@ -1494,7 +1497,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Tok.getPrecedence() == prec::Assignment) return false; if ((Tok.Type == TT_BinaryOperator && !Tok.Previous->is(tok::l_paren)) || - Tok.Previous->Type == TT_BinaryOperator) + Tok.Previous->Type == TT_BinaryOperator || + Tok.Previous->Type == TT_ConditionalExpr) return true; if (Tok.Previous->Type == TT_TemplateCloser && Tok.is(tok::l_paren)) return false; diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index fb33bd685b..0dc06594f1 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -2940,8 +2940,9 @@ TEST_F(FormatTest, ExpressionIndentationBreakingBeforeOperators) { " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}", Style); verifyFormat("if () {\n" - "} else if (aaaaa && bbbbb // break\n" - " > ccccc) {\n" + "} else if (aaaaa\n" + " && bbbbb // break\n" + " > ccccc) {\n" "}", Style); @@ -3697,6 +3698,12 @@ TEST_F(FormatTest, BreaksConditionalExpressions) { " : (bbbbbbbbbbbbbbb //\n" " ? ccccccccccccccc\n" " : ddddddddddddddd);"); + verifyFormat( + "int aaaaaaaaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " ? aaaaaaaaaaaaaaaaaaaaaaaaa +\n" + " aaaaaaaaaaaaaaaaaaaaa +\n" + " aaaaaaaaaaaaaaaaaaaaa\n" + " : aaaaaaaaaa;"); FormatStyle NoBinPacking = getLLVMStyle(); NoBinPacking.BinPackParameters = false; @@ -4000,6 +4007,8 @@ TEST_F(FormatTest, AlignsPipes) { " llvm::outs() << \"aaaaaaaaaaaaaaaaaaaa: \"\n" " << aaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaa);\n" "}"); + verifyFormat("llvm::outs() << \"aaaaaaaaaaaaaaaa: \"\n" + " << aaaaaaaa.aaaaaaaaaaaa(aaa)->aaaaaaaaaaaaaa();"); // Breaking before the first "<<" is generally not desirable. verifyFormat( -- 2.40.0