From 6d822720f0e4ee38ab558f12d12b193e775ba334 Mon Sep 17 00:00:00 2001 From: Daniel Jasper Date: Mon, 24 Dec 2012 16:43:00 +0000 Subject: [PATCH] Penalize tokens with a lower parenthesis level than the start of the line. This prevents formattings like this (assuming "parameter" doesn't fit the line): bool f = someFunction() && someFunctionWithParam( parameter) && someOtherFunction(); Here, "parameter" - the start of line 2 - has a parenthesis level of 2, but there are subsequent tokens ("&&" and "someOtherFunction") with a lower level. This is bad for readability as "parameter" hides "someOtherFunction". With this patch, this changes to: bool f = someFunction() && someFunctionWithParam(parameter) && someOtherFunction(); llvm-svn: 171038 --- clang/lib/Format/Format.cpp | 16 +++++++++++++++- clang/unittests/Format/FormatTest.cpp | 12 ++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 056376a4e28d..7d135d9b175a 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -83,6 +83,7 @@ FormatStyle getGoogleStyle() { struct OptimizationParameters { unsigned PenaltyIndentLevel; + unsigned PenaltyLevelDecrease; }; class UnwrappedLineFormatter { @@ -95,6 +96,7 @@ public: Annotations(Annotations), Replaces(Replaces), StructuralError(StructuralError) { Parameters.PenaltyIndentLevel = 15; + Parameters.PenaltyLevelDecrease = 10; } void format() { @@ -110,6 +112,7 @@ public: State.FirstLessLess.push_back(0); State.ForLoopVariablePos = 0; State.LineContainsContinuedForLoopSection = false; + State.StartOfLineLevel = 1; // The first token has already been indented and thus consumed. moveStateToNextToken(State); @@ -155,6 +158,9 @@ private: /// \brief The number of tokens already consumed. unsigned ConsumedTokens; + /// \brief The parenthesis level of the first token on the current line. + unsigned StartOfLineLevel; + /// \brief The position to which a specific parenthesis level needs to be /// indented. std::vector Indent; @@ -186,6 +192,8 @@ private: return Other.ConsumedTokens > ConsumedTokens; if (Other.Column != Column) return Other.Column > Column; + if (Other.StartOfLineLevel != StartOfLineLevel) + return Other.StartOfLineLevel > StartOfLineLevel; if (Other.Indent.size() != Indent.size()) return Other.Indent.size() > Indent.size(); for (int i = 0, e = Indent.size(); i != e; ++i) { @@ -247,6 +255,8 @@ private: State.Column = State.Indent[ParenLevel]; } + State.StartOfLineLevel = ParenLevel + 1; + if (Line.Tokens[0].Tok.is(tok::kw_for)) State.LineContainsContinuedForLoopSection = Previous.Tok.isNot(tok::semi); @@ -343,7 +353,7 @@ private: return Level; if (Right.Tok.is(tok::arrow) || Right.Tok.is(tok::period)) - return 200; + return 50; return 3; } @@ -375,6 +385,10 @@ private: if (NewLine) { CurrentPenalty += Parameters.PenaltyIndentLevel * State.Indent.size() + splitPenalty(State.ConsumedTokens - 1); + } else { + if (State.Indent.size() < State.StartOfLineLevel) + CurrentPenalty += Parameters.PenaltyLevelDecrease * + (State.StartOfLineLevel - State.Indent.size()); } addTokenToState(NewLine, true, State); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 9a1cb9074681..43003befb673 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -379,8 +379,9 @@ TEST_F(FormatTest, FormatsFunctionDefinition) { TEST_F(FormatTest, FormatsAwesomeMethodCall) { verifyFormat( - "SomeLongMethodName(SomeReallyLongMethod(CallOtherReallyLongMethod(\n" - " parameter, parameter, parameter)), SecondLongCall(parameter));"); + "SomeLongMethodName(SomeReallyLongMethod(\n" + " CallOtherReallyLongMethod(parameter, parameter, parameter)),\n" + " SecondLongCall(parameter));"); } TEST_F(FormatTest, ConstructorInitializers) { @@ -454,6 +455,13 @@ TEST_F(FormatTest, BreaksDesireably) { " aaaaaaaaaaa(aaaaaaaaa) || aaaaaaaaaaaaaaaaaaaaaaa ||\n" " aaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaa ||\n" " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);"); + + verifyFormat( + "{\n {\n {\n" + " Annotation.SpaceRequiredBefore =\n" + " Line.Tokens[i - 1].Tok.isNot(tok::l_paren) &&\n" + " Line.Tokens[i - 1].Tok.isNot(tok::l_square);\n" + " }\n }\n}"); } TEST_F(FormatTest, BreaksAccordingToOperatorPrecedence) {