r235580 - clang-format: Support nested block formatting with ColumnLimit=0.
Daniel Jasper
djasper at google.com
Thu Apr 23 02:23:17 PDT 2015
Author: djasper
Date: Thu Apr 23 04:23:17 2015
New Revision: 235580
URL: http://llvm.org/viewvc/llvm-project?rev=235580&view=rev
Log:
clang-format: Support nested block formatting with ColumnLimit=0.
Modified:
cfe/trunk/lib/Format/ContinuationIndenter.cpp
cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp
cfe/trunk/lib/Format/UnwrappedLineFormatter.h
cfe/trunk/unittests/Format/FormatTest.cpp
Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=235580&r1=235579&r2=235580&view=diff
==============================================================================
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original)
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Thu Apr 23 04:23:17 2015
@@ -839,12 +839,26 @@ void ContinuationIndenter::moveStatePast
(Current.PackingKind == PPK_OnePerLine ||
(!BinPackInconclusiveFunctions &&
Current.PackingKind == PPK_Inconclusive)));
- // If this '[' opens an ObjC call, determine whether all parameters fit
- // into one line and put one per line if they don't.
- if (Current.is(TT_ObjCMethodExpr) && Style.ColumnLimit != 0 &&
- getLengthToMatchingParen(Current) + State.Column >
+ if (Current.is(TT_ObjCMethodExpr) && Current.MatchingParen) {
+ if (Style.ColumnLimit) {
+ // If this '[' opens an ObjC call, determine whether all parameters fit
+ // into one line and put one per line if they don't.
+ if (getLengthToMatchingParen(Current) + State.Column >
getColumnLimit(State))
- BreakBeforeParameter = true;
+ BreakBeforeParameter = true;
+ } else {
+ // For ColumnLimit = 0, we have to figure out whether there is or has to
+ // be a line break within this call.
+ for (const FormatToken *Tok = &Current;
+ Tok && Tok != Current.MatchingParen; Tok = Tok->Next) {
+ if (Tok->MustBreakBefore ||
+ (Tok->CanBreakBefore && Tok->NewlinesBefore > 0)) {
+ BreakBeforeParameter = true;
+ break;
+ }
+ }
+ }
+ }
}
bool NoLineBreak = State.Stack.back().NoLineBreak ||
(Current.is(TT_TemplateOpener) &&
Modified: cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp?rev=235580&r1=235579&r2=235580&view=diff
==============================================================================
--- cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp (original)
+++ cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp Thu Apr 23 04:23:17 2015
@@ -303,7 +303,9 @@ private:
class NoColumnLimitFormatter {
public:
- NoColumnLimitFormatter(ContinuationIndenter *Indenter) : Indenter(Indenter) {}
+ NoColumnLimitFormatter(ContinuationIndenter *Indenter,
+ UnwrappedLineFormatter *Formatter)
+ : Indenter(Indenter), Formatter(Formatter) {}
/// \brief Formats the line starting at \p State, simply keeping all of the
/// input's line breaking decisions.
@@ -314,12 +316,15 @@ public:
bool Newline =
Indenter->mustBreak(State) ||
(Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);
+ unsigned Penalty = 0;
+ Formatter->formatChildren(State, Newline, /*DryRun=*/false, Penalty);
Indenter->addTokenToState(State, Newline, /*DryRun=*/false);
}
}
private:
ContinuationIndenter *Indenter;
+ UnwrappedLineFormatter *Formatter;
};
@@ -426,8 +431,7 @@ UnwrappedLineFormatter::format(const Sma
Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
}
} else if (Style.ColumnLimit == 0) {
- // FIXME: Implement nested blocks for ColumnLimit = 0.
- NoColumnLimitFormatter Formatter(Indenter);
+ NoColumnLimitFormatter Formatter(Indenter, this);
if (!DryRun)
Formatter.format(Indent, &TheLine);
} else {
Modified: cfe/trunk/lib/Format/UnwrappedLineFormatter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.h?rev=235580&r1=235579&r2=235580&view=diff
==============================================================================
--- cfe/trunk/lib/Format/UnwrappedLineFormatter.h (original)
+++ cfe/trunk/lib/Format/UnwrappedLineFormatter.h Thu Apr 23 04:23:17 2015
@@ -40,6 +40,30 @@ public:
unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
int AdditionalIndent = 0, bool FixBadIndentation = false);
+
+ /// \brief If the \p State's next token is an r_brace closing a nested block,
+ /// format the nested block before it.
+ ///
+ /// Returns \c true if all children could be placed successfully and adapts
+ /// \p Penalty as well as \p State. If \p DryRun is false, also directly
+ /// creates changes using \c Whitespaces.
+ ///
+ /// The crucial idea here is that children always get formatted upon
+ /// encountering the closing brace right after the nested block. Now, if we
+ /// are currently trying to keep the "}" on the same line (i.e. \p NewLine is
+ /// \c false), the entire block has to be kept on the same line (which is only
+ /// possible if it fits on the line, only contains a single statement, etc.
+ ///
+ /// If \p NewLine is true, we format the nested block on separate lines, i.e.
+ /// break after the "{", format all lines with correct indentation and the put
+ /// the closing "}" on yet another new line.
+ ///
+ /// This enables us to keep the simple structure of the
+ /// \c UnwrappedLineFormatter, where we only have two options for each token:
+ /// break or don't break.
+ bool formatChildren(LineState &State, bool NewLine, bool DryRun,
+ unsigned &Penalty);
+
private:
/// \brief Formats an \c AnnotatedLine and returns the penalty.
///
@@ -131,29 +155,6 @@ private:
void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
bool NewLine, unsigned *Count, QueueType *Queue);
- /// \brief If the \p State's next token is an r_brace closing a nested block,
- /// format the nested block before it.
- ///
- /// Returns \c true if all children could be placed successfully and adapts
- /// \p Penalty as well as \p State. If \p DryRun is false, also directly
- /// creates changes using \c Whitespaces.
- ///
- /// The crucial idea here is that children always get formatted upon
- /// encountering the closing brace right after the nested block. Now, if we
- /// are currently trying to keep the "}" on the same line (i.e. \p NewLine is
- /// \c false), the entire block has to be kept on the same line (which is only
- /// possible if it fits on the line, only contains a single statement, etc.
- ///
- /// If \p NewLine is true, we format the nested block on separate lines, i.e.
- /// break after the "{", format all lines with correct indentation and the put
- /// the closing "}" on yet another new line.
- ///
- /// This enables us to keep the simple structure of the
- /// \c UnwrappedLineFormatter, where we only have two options for each token:
- /// break or don't break.
- bool formatChildren(LineState &State, bool NewLine, bool DryRun,
- unsigned &Penalty);
-
ContinuationIndenter *Indenter;
WhitespaceManager *Whitespaces;
FormatStyle Style;
Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=235580&r1=235579&r2=235580&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Thu Apr 23 04:23:17 2015
@@ -9789,6 +9789,74 @@ TEST_F(FormatTest, FormatsBlocks) {
FourIndent);
}
+TEST_F(FormatTest, FormatsBlocksWithZeroColumnWidth) {
+ FormatStyle ZeroColumn = getLLVMStyle();
+ ZeroColumn.ColumnLimit = 0;
+
+ verifyFormat("[[SessionService sharedService] "
+ "loadWindowWithCompletionBlock:^(SessionWindow *window) {\n"
+ " if (window) {\n"
+ " [self windowDidLoad:window];\n"
+ " } else {\n"
+ " [self errorLoadingWindow];\n"
+ " }\n"
+ "}];",
+ ZeroColumn);
+ EXPECT_EQ("[[SessionService sharedService]\n"
+ " loadWindowWithCompletionBlock:^(SessionWindow *window) {\n"
+ " if (window) {\n"
+ " [self windowDidLoad:window];\n"
+ " } else {\n"
+ " [self errorLoadingWindow];\n"
+ " }\n"
+ " }];",
+ format("[[SessionService sharedService]\n"
+ "loadWindowWithCompletionBlock:^(SessionWindow *window) {\n"
+ " if (window) {\n"
+ " [self windowDidLoad:window];\n"
+ " } else {\n"
+ " [self errorLoadingWindow];\n"
+ " }\n"
+ "}];",
+ ZeroColumn));
+ verifyFormat("[myObject doSomethingWith:arg1\n"
+ " firstBlock:^(Foo *a) {\n"
+ " // ...\n"
+ " int i;\n"
+ " }\n"
+ " secondBlock:^(Bar *b) {\n"
+ " // ...\n"
+ " int i;\n"
+ " }\n"
+ " thirdBlock:^Foo(Bar *b) {\n"
+ " // ...\n"
+ " int i;\n"
+ " }];",
+ ZeroColumn);
+ verifyFormat("f(^{\n"
+ " @autoreleasepool {\n"
+ " if (a) {\n"
+ " g();\n"
+ " }\n"
+ " }\n"
+ "});",
+ ZeroColumn);
+ verifyFormat("void (^largeBlock)(void) = ^{\n"
+ " // ...\n"
+ "};",
+ ZeroColumn);
+
+ ZeroColumn.AllowShortBlocksOnASingleLine = true;
+ EXPECT_EQ("void (^largeBlock)(void) = ^{ int i; };",
+ format("void (^largeBlock)(void) = ^{ int i; };",
+ ZeroColumn));
+ ZeroColumn.AllowShortBlocksOnASingleLine = false;
+ EXPECT_EQ("void (^largeBlock)(void) = ^{\n"
+ " int i;\n"
+ "};",
+ format("void (^largeBlock)(void) = ^{ int i; };", ZeroColumn));
+}
+
TEST_F(FormatTest, SupportsCRLF) {
EXPECT_EQ("int a;\r\n"
"int b;\r\n"
More information about the cfe-commits
mailing list