Added an option to allow short function bodies be placed on a single line.

Summary:
The AllowShortFunctionsOnASingleLine option now controls short function
body placement on a single line independent of the BreakBeforeBraces option.
Updated tests using BreakBeforeBraces other than BS_Attach.

Addresses http://llvm.org/PR17888

Reviewers: klimek, djasper

Reviewed By: klimek

CC: cfe-commits, klimek

Differential Revision: http://llvm-reviews.chandlerc.com/D2230

llvm-svn: 195256
This commit is contained in:
Alexander Kornienko 2013-11-20 16:33:05 +00:00
parent d8430928f1
commit 3cfa973978
6 changed files with 78 additions and 37 deletions

View File

@ -141,6 +141,10 @@ struct FormatStyle {
/// single line. /// single line.
bool AllowShortLoopsOnASingleLine; bool AllowShortLoopsOnASingleLine;
/// \brief If \c true, <tt>int f() { return 0; }</tt> can be put on a single
/// line.
bool AllowShortFunctionsOnASingleLine;
/// \brief Add a space in front of an Objective-C protocol list, i.e. use /// \brief Add a space in front of an Objective-C protocol list, i.e. use
/// <tt>Foo <Protocol></tt> instead of \c Foo<Protocol>. /// <tt>Foo <Protocol></tt> instead of \c Foo<Protocol>.
bool ObjCSpaceBeforeProtocolList; bool ObjCSpaceBeforeProtocolList;
@ -255,6 +259,8 @@ struct FormatStyle {
AlignTrailingComments == R.AlignTrailingComments && AlignTrailingComments == R.AlignTrailingComments &&
AllowAllParametersOfDeclarationOnNextLine == AllowAllParametersOfDeclarationOnNextLine ==
R.AllowAllParametersOfDeclarationOnNextLine && R.AllowAllParametersOfDeclarationOnNextLine &&
AllowShortFunctionsOnASingleLine ==
R.AllowShortFunctionsOnASingleLine &&
AllowShortIfStatementsOnASingleLine == AllowShortIfStatementsOnASingleLine ==
R.AllowShortIfStatementsOnASingleLine && R.AllowShortIfStatementsOnASingleLine &&
AllowShortLoopsOnASingleLine == R.AllowShortLoopsOnASingleLine && AllowShortLoopsOnASingleLine == R.AllowShortLoopsOnASingleLine &&

View File

@ -117,6 +117,8 @@ template <> struct MappingTraits<clang::format::FormatStyle> {
Style.AllowShortIfStatementsOnASingleLine); Style.AllowShortIfStatementsOnASingleLine);
IO.mapOptional("AllowShortLoopsOnASingleLine", IO.mapOptional("AllowShortLoopsOnASingleLine",
Style.AllowShortLoopsOnASingleLine); Style.AllowShortLoopsOnASingleLine);
IO.mapOptional("AllowShortFunctionsOnASingleLine",
Style.AllowShortFunctionsOnASingleLine);
IO.mapOptional("AlwaysBreakTemplateDeclarations", IO.mapOptional("AlwaysBreakTemplateDeclarations",
Style.AlwaysBreakTemplateDeclarations); Style.AlwaysBreakTemplateDeclarations);
IO.mapOptional("AlwaysBreakBeforeMultilineStrings", IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
@ -190,6 +192,7 @@ FormatStyle getLLVMStyle() {
LLVMStyle.AlignEscapedNewlinesLeft = false; LLVMStyle.AlignEscapedNewlinesLeft = false;
LLVMStyle.AlignTrailingComments = true; LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
LLVMStyle.AllowShortFunctionsOnASingleLine = true;
LLVMStyle.AllowShortIfStatementsOnASingleLine = false; LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
LLVMStyle.AllowShortLoopsOnASingleLine = false; LLVMStyle.AllowShortLoopsOnASingleLine = false;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false; LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
@ -237,6 +240,7 @@ FormatStyle getGoogleStyle() {
GoogleStyle.AlignEscapedNewlinesLeft = true; GoogleStyle.AlignEscapedNewlinesLeft = true;
GoogleStyle.AlignTrailingComments = true; GoogleStyle.AlignTrailingComments = true;
GoogleStyle.AllowAllParametersOfDeclarationOnNextLine = true; GoogleStyle.AllowAllParametersOfDeclarationOnNextLine = true;
GoogleStyle.AllowShortFunctionsOnASingleLine = true;
GoogleStyle.AllowShortIfStatementsOnASingleLine = true; GoogleStyle.AllowShortIfStatementsOnASingleLine = true;
GoogleStyle.AllowShortLoopsOnASingleLine = true; GoogleStyle.AllowShortLoopsOnASingleLine = true;
GoogleStyle.AlwaysBreakBeforeMultilineStrings = true; GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
@ -381,7 +385,7 @@ public:
/// \brief Calculates how many lines can be merged into 1 starting at \p I. /// \brief Calculates how many lines can be merged into 1 starting at \p I.
unsigned unsigned
tryFitMultipleLinesInOne(unsigned Indent, tryFitMultipleLinesInOne(unsigned Indent,
SmallVectorImpl<AnnotatedLine *>::const_iterator &I, SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E) { SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
// We can never merge stuff if there are trailing line comments. // We can never merge stuff if there are trailing line comments.
AnnotatedLine *TheLine = *I; AnnotatedLine *TheLine = *I;
@ -402,16 +406,43 @@ public:
if (I + 1 == E || I[1]->Type == LT_Invalid) if (I + 1 == E || I[1]->Type == LT_Invalid)
return 0; return 0;
if (TheLine->Last->Type == TT_FunctionLBrace) {
return Style.AllowShortFunctionsOnASingleLine
? tryMergeSimpleBlock(I, E, Limit)
: 0;
}
if (TheLine->Last->is(tok::l_brace)) { if (TheLine->Last->is(tok::l_brace)) {
return tryMergeSimpleBlock(I, E, Limit); return Style.BreakBeforeBraces == clang::format::FormatStyle::BS_Attach
} else if (Style.AllowShortIfStatementsOnASingleLine && ? tryMergeSimpleBlock(I, E, Limit)
TheLine->First->is(tok::kw_if)) { : 0;
return tryMergeSimpleControlStatement(I, E, Limit); }
} else if (Style.AllowShortLoopsOnASingleLine && if (I[1]->First->Type == TT_FunctionLBrace &&
TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) { Style.BreakBeforeBraces != FormatStyle::BS_Attach) {
return tryMergeSimpleControlStatement(I, E, Limit); // Reduce the column limit by the number of spaces we need to insert
} else if (TheLine->InPPDirective && (TheLine->First->HasUnescapedNewline || // around braces.
TheLine->First->IsFirst)) { Limit = Limit > 3 ? Limit - 3 : 0;
unsigned MergedLines = 0;
if (Style.AllowShortFunctionsOnASingleLine) {
MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
// If we managed to merge the block, count the function header, which is
// on a separate line.
if (MergedLines > 0)
++MergedLines;
}
return MergedLines;
}
if (TheLine->First->is(tok::kw_if)) {
return Style.AllowShortIfStatementsOnASingleLine
? tryMergeSimpleControlStatement(I, E, Limit)
: 0;
}
if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
return Style.AllowShortLoopsOnASingleLine
? tryMergeSimpleControlStatement(I, E, Limit)
: 0;
}
if (TheLine->InPPDirective &&
(TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {
return tryMergeSimplePPDirective(I, E, Limit); return tryMergeSimplePPDirective(I, E, Limit);
} }
return 0; return 0;
@ -419,7 +450,7 @@ public:
private: private:
unsigned unsigned
tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator &I, tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E, SmallVectorImpl<AnnotatedLine *>::const_iterator E,
unsigned Limit) { unsigned Limit) {
if (Limit == 0) if (Limit == 0)
@ -434,7 +465,7 @@ private:
} }
unsigned tryMergeSimpleControlStatement( unsigned tryMergeSimpleControlStatement(
SmallVectorImpl<AnnotatedLine *>::const_iterator &I, SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) { SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
if (Limit == 0) if (Limit == 0)
return 0; return 0;
@ -450,7 +481,7 @@ private:
if (1 + I[1]->Last->TotalLength > Limit) if (1 + I[1]->Last->TotalLength > Limit)
return 0; return 0;
if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for, if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for,
tok::kw_while) || tok::kw_while) ||
I[1]->First->Type == TT_LineComment) I[1]->First->Type == TT_LineComment)
return 0; return 0;
// Only inline simple if's (no nested if or else). // Only inline simple if's (no nested if or else).
@ -461,13 +492,9 @@ private:
} }
unsigned unsigned
tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator &I, tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E, SmallVectorImpl<AnnotatedLine *>::const_iterator E,
unsigned Limit) { unsigned Limit) {
// No merging if the brace already is on the next line.
if (Style.BreakBeforeBraces != FormatStyle::BS_Attach)
return 0;
// First, check that the current line allows merging. This is the case if // First, check that the current line allows merging. This is the case if
// we're not in a control flow statement and the last token is an opening // we're not in a control flow statement and the last token is an opening
// brace. // brace.
@ -583,8 +610,7 @@ public:
} }
} else if (TheLine.Type != LT_Invalid && } else if (TheLine.Type != LT_Invalid &&
(WasMoved || FormatPPDirective || touchesLine(TheLine))) { (WasMoved || FormatPPDirective || touchesLine(TheLine))) {
unsigned LevelIndent = unsigned LevelIndent = getIndent(IndentForLevel, TheLine.Level);
getIndent(IndentForLevel, TheLine.Level);
if (FirstTok->WhitespaceRange.isValid()) { if (FirstTok->WhitespaceRange.isValid()) {
if (!DryRun) if (!DryRun)
formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level, formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level,
@ -732,9 +758,9 @@ private:
if (PreviousLine && PreviousLine->First->isAccessSpecifier()) if (PreviousLine && PreviousLine->First->isAccessSpecifier())
Newlines = std::min(1u, Newlines); Newlines = std::min(1u, Newlines);
Whitespaces->replaceWhitespace( Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,
RootToken, Newlines, IndentLevel, Indent, Indent, Indent, InPPDirective &&
InPPDirective && !RootToken.HasUnescapedNewline); !RootToken.HasUnescapedNewline);
} }
/// \brief Get the indent of \p Level from \p IndentForLevel. /// \brief Get the indent of \p Level from \p IndentForLevel.
@ -961,7 +987,7 @@ private:
// Cannot merge multiple statements into a single line. // Cannot merge multiple statements into a single line.
if (Previous.Children.size() > 1) if (Previous.Children.size() > 1)
return false; return false;
// We can't put the closing "}" on a line with a trailing comment. // We can't put the closing "}" on a line with a trailing comment.
if (Previous.Children[0]->Last->isTrailingComment()) if (Previous.Children[0]->Last->isTrailingComment())

View File

@ -39,6 +39,7 @@ enum TokenType {
TT_ImplicitStringLiteral, TT_ImplicitStringLiteral,
TT_InlineASMColon, TT_InlineASMColon,
TT_InheritanceColon, TT_InheritanceColon,
TT_FunctionLBrace,
TT_FunctionTypeLParen, TT_FunctionTypeLParen,
TT_LambdaLSquare, TT_LambdaLSquare,
TT_LineComment, TT_LineComment,

View File

@ -538,6 +538,7 @@ private:
// Reset token type in case we have already looked at it and then // Reset token type in case we have already looked at it and then
// recovered from an error (e.g. failure to find the matching >). // recovered from an error (e.g. failure to find the matching >).
if (CurrentToken->Type != TT_LambdaLSquare && if (CurrentToken->Type != TT_LambdaLSquare &&
CurrentToken->Type != TT_FunctionLBrace &&
CurrentToken->Type != TT_ImplicitStringLiteral) CurrentToken->Type != TT_ImplicitStringLiteral)
CurrentToken->Type = TT_Unknown; CurrentToken->Type = TT_Unknown;
if (CurrentToken->Role) if (CurrentToken->Role)

View File

@ -681,6 +681,7 @@ void UnwrappedLineParser::parseStructuralElement() {
Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup || Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup ||
Style.BreakBeforeBraces == FormatStyle::BS_Allman) Style.BreakBeforeBraces == FormatStyle::BS_Allman)
addUnwrappedLine(); addUnwrappedLine();
FormatTok->Type = TT_FunctionLBrace;
parseBlock(/*MustBeDeclaration=*/false); parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine(); addUnwrappedLine();
return; return;

View File

@ -4776,7 +4776,14 @@ TEST_F(FormatTest, FormatsBracedListsInColumnLayout) {
} }
TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) { TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
FormatStyle DoNotMerge = getLLVMStyle();
DoNotMerge.AllowShortFunctionsOnASingleLine = false;
verifyFormat("void f() { return 42; }"); verifyFormat("void f() { return 42; }");
verifyFormat("void f() {\n"
" return 42;\n"
"}",
DoNotMerge);
verifyFormat("void f() {\n" verifyFormat("void f() {\n"
" // Comment\n" " // Comment\n"
"}"); "}");
@ -4790,6 +4797,13 @@ TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
"}"); "}");
verifyFormat("void f() {} // comment"); verifyFormat("void f() {} // comment");
verifyFormat("void f() { int a; } // comment"); verifyFormat("void f() { int a; } // comment");
verifyFormat("void f() {\n"
"} // comment",
DoNotMerge);
verifyFormat("void f() {\n"
" int a;\n"
"} // comment",
DoNotMerge);
verifyFormat("void f() {\n" verifyFormat("void f() {\n"
"} // comment", "} // comment",
getLLVMStyleWithColumns(15)); getLLVMStyleWithColumns(15));
@ -6613,10 +6627,7 @@ TEST_F(FormatTest, LinuxBraceBreaking) {
" b();\n" " b();\n"
" }\n" " }\n"
" }\n" " }\n"
" void g()\n" " void g() { return; }\n"
" {\n"
" return;\n"
" }\n"
"}\n" "}\n"
"}", "}",
BreakBeforeBrace); BreakBeforeBrace);
@ -6634,10 +6645,7 @@ TEST_F(FormatTest, StroustrupBraceBreaking) {
" b();\n" " b();\n"
" }\n" " }\n"
" }\n" " }\n"
" void g()\n" " void g() { return; }\n"
" {\n"
" return;\n"
" }\n"
"}\n" "}\n"
"}", "}",
BreakBeforeBrace); BreakBeforeBrace);
@ -6658,10 +6666,7 @@ TEST_F(FormatTest, AllmanBraceBreaking) {
" b();\n" " b();\n"
" }\n" " }\n"
" }\n" " }\n"
" void g()\n" " void g() { return; }\n"
" {\n"
" return;\n"
" }\n"
"}\n" "}\n"
"}", "}",
BreakBeforeBrace); BreakBeforeBrace);
@ -6822,6 +6827,7 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft); CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft);
CHECK_PARSE_BOOL(AlignTrailingComments); CHECK_PARSE_BOOL(AlignTrailingComments);
CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine); CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);
CHECK_PARSE_BOOL(AllowShortFunctionsOnASingleLine);
CHECK_PARSE_BOOL(AllowShortIfStatementsOnASingleLine); CHECK_PARSE_BOOL(AllowShortIfStatementsOnASingleLine);
CHECK_PARSE_BOOL(AllowShortLoopsOnASingleLine); CHECK_PARSE_BOOL(AllowShortLoopsOnASingleLine);
CHECK_PARSE_BOOL(AlwaysBreakTemplateDeclarations); CHECK_PARSE_BOOL(AlwaysBreakTemplateDeclarations);
@ -7126,7 +7132,7 @@ TEST_F(FormatTest, FormatsWithWebKitStyle) {
" : aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa)\n" " : aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
" , aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaa, // break\n" " , aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaa, // break\n"
" aaaaaaaaaaaaaa)\n" " aaaaaaaaaaaaaa)\n"
" , aaaaaaaaaaaaaaaaaaaaaaa()\n{\n}", " , aaaaaaaaaaaaaaaaaaaaaaa() {}",
Style); Style);
// Access specifiers should be aligned left. // Access specifiers should be aligned left.