Skip to content

Commit

Permalink
Support AlwaysBreakAfterReturnType
Browse files Browse the repository at this point in the history
This changes the behavior of AlwaysBreakAfterDeclarationReturnType
so that it supports breaking after declarations, definitions, or
both.

Differential Revision: http://reviews.llvm.org/D10370
Reviewed By: Daniel Jasper

llvm-svn: 256046
  • Loading branch information
Zachary Turner committed Dec 18, 2015
1 parent 82b8d4e commit 448592e
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 26 deletions.
23 changes: 21 additions & 2 deletions clang/docs/ClangFormatStyleOptions.rst
Expand Up @@ -254,7 +254,8 @@ the configuration (without a prefix: ``Auto``).
single line.

**AlwaysBreakAfterDefinitionReturnType** (``DefinitionReturnTypeBreakingStyle``)
The function definition return type breaking style to use.
The function definition return type breaking style to use. This
option is deprecated and is retained for backwards compatibility.

Possible values:

Expand All @@ -264,7 +265,25 @@ the configuration (without a prefix: ``Auto``).
* ``DRTBS_All`` (in configuration: ``All``)
Always break after the return type.
* ``DRTBS_TopLevel`` (in configuration: ``TopLevel``)
Always break after the return types of top level functions.
Always break after the return types of top-level functions.


**AlwaysBreakAfterReturnType** (``ReturnTypeBreakingStyle``)
The function declaration return type breaking style to use.

Possible values:

* ``RTBS_None`` (in configuration: ``None``)
Break after return type automatically.
``PenaltyReturnTypeOnItsOwnLine`` is taken into account.
* ``RTBS_All`` (in configuration: ``All``)
Always break after the return type.
* ``RTBS_TopLevel`` (in configuration: ``TopLevel``)
Always break after the return types of top-level functions.
* ``RTBS_AllDefinitions`` (in configuration: ``AllDefinitions``)
Always break after the return type of function definitions.
* ``RTBS_TopLevelDefinitions`` (in configuration: ``TopLevelDefinitions``)
Always break after the return type of top-level definitions.


**AlwaysBreakBeforeMultilineStrings** (``bool``)
Expand Down
27 changes: 23 additions & 4 deletions clang/include/clang/Format/Format.h
Expand Up @@ -156,13 +156,33 @@ struct FormatStyle {
DRTBS_None,
/// Always break after the return type.
DRTBS_All,
/// Always break after the return types of top level functions.
/// Always break after the return types of top-level functions.
DRTBS_TopLevel,
};

/// \brief The function definition return type breaking style to use.
/// \brief Different ways to break after the function definition or
/// declaration return type.
enum ReturnTypeBreakingStyle {
/// Break after return type automatically.
/// \c PenaltyReturnTypeOnItsOwnLine is taken into account.
RTBS_None,
/// Always break after the return type.
RTBS_All,
/// Always break after the return types of top-level functions.
RTBS_TopLevel,
/// Always break after the return type of function definitions.
RTBS_AllDefinitions,
/// Always break after the return type of top-level definitions.
RTBS_TopLevelDefinitions,
};

/// \brief The function definition return type breaking style to use. This
/// option is deprecated and is retained for backwards compatibility.
DefinitionReturnTypeBreakingStyle AlwaysBreakAfterDefinitionReturnType;

/// \brief The function declaration return type breaking style to use.
ReturnTypeBreakingStyle AlwaysBreakAfterReturnType;

/// \brief If \c true, always break before multiline string literals.
///
/// This flag is mean to make cases where there are multiple multiline strings
Expand Down Expand Up @@ -584,8 +604,7 @@ struct FormatStyle {
AllowShortIfStatementsOnASingleLine ==
R.AllowShortIfStatementsOnASingleLine &&
AllowShortLoopsOnASingleLine == R.AllowShortLoopsOnASingleLine &&
AlwaysBreakAfterDefinitionReturnType ==
R.AlwaysBreakAfterDefinitionReturnType &&
AlwaysBreakAfterReturnType == R.AlwaysBreakAfterReturnType &&
AlwaysBreakBeforeMultilineStrings ==
R.AlwaysBreakBeforeMultilineStrings &&
AlwaysBreakTemplateDeclarations ==
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Format/ContinuationIndenter.cpp
Expand Up @@ -125,10 +125,10 @@ bool ContinuationIndenter::canBreak(const LineState &State) {

// Don't break after very short return types (e.g. "void") as that is often
// unexpected.
if (Current.is(TT_FunctionDeclarationName) &&
Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_None &&
State.Column < 6)
return false;
if (Current.is(TT_FunctionDeclarationName) && State.Column < 6) {
if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None)
return false;
}

return !State.Stack.back().NoLineBreak;
}
Expand Down
31 changes: 31 additions & 0 deletions clang/lib/Format/Format.cpp
Expand Up @@ -104,6 +104,18 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
}
};

template <>
struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
IO.enumCase(Value, "None", FormatStyle::RTBS_None);
IO.enumCase(Value, "All", FormatStyle::RTBS_All);
IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel);
IO.enumCase(Value, "TopLevelDefinitions",
FormatStyle::RTBS_TopLevelDefinitions);
IO.enumCase(Value, "AllDefinitions", FormatStyle::RTBS_AllDefinitions);
}
};

template <>
struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> {
static void
Expand Down Expand Up @@ -233,6 +245,21 @@ template <> struct MappingTraits<FormatStyle> {
Style.AllowShortLoopsOnASingleLine);
IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",
Style.AlwaysBreakAfterDefinitionReturnType);
IO.mapOptional("AlwaysBreakAfterReturnType",
Style.AlwaysBreakAfterReturnType);
// If AlwaysBreakAfterDefinitionReturnType was specified but
// AlwaysBreakAfterReturnType was not, initialize the latter from the
// former for backwards compatibility.
if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None &&
Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) {
if (Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_All)
Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
else if (Style.AlwaysBreakAfterDefinitionReturnType ==
FormatStyle::DRTBS_TopLevel)
Style.AlwaysBreakAfterReturnType =
FormatStyle::RTBS_TopLevelDefinitions;
}

IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
Style.AlwaysBreakBeforeMultilineStrings);
IO.mapOptional("AlwaysBreakTemplateDeclarations",
Expand Down Expand Up @@ -449,6 +476,7 @@ FormatStyle getLLVMStyle() {
LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
LLVMStyle.AllowShortLoopsOnASingleLine = false;
LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
LLVMStyle.AlwaysBreakTemplateDeclarations = false;
Expand Down Expand Up @@ -585,6 +613,8 @@ FormatStyle getMozillaStyle() {
FormatStyle MozillaStyle = getLLVMStyle();
MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
MozillaStyle.AlwaysBreakAfterReturnType =
FormatStyle::RTBS_TopLevelDefinitions;
MozillaStyle.AlwaysBreakAfterDefinitionReturnType =
FormatStyle::DRTBS_TopLevel;
MozillaStyle.AlwaysBreakTemplateDeclarations = true;
Expand Down Expand Up @@ -624,6 +654,7 @@ FormatStyle getWebKitStyle() {
FormatStyle getGNUStyle() {
FormatStyle Style = getLLVMStyle();
Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Style.BreakBeforeBraces = FormatStyle::BS_GNU;
Style.BreakBeforeTernaryOperators = true;
Expand Down
35 changes: 26 additions & 9 deletions clang/lib/Format/TokenAnnotator.cpp
Expand Up @@ -1562,6 +1562,29 @@ static bool isFunctionDeclarationName(const FormatToken &Current) {
return false;
}

bool TokenAnnotator::mustBreakForReturnType(const AnnotatedLine &Line) const {
assert(Line.MightBeFunctionDecl);

if ((Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_TopLevel ||
Style.AlwaysBreakAfterReturnType ==
FormatStyle::RTBS_TopLevelDefinitions) &&
Line.Level > 0)
return false;

switch (Style.AlwaysBreakAfterReturnType) {
case FormatStyle::RTBS_None:
return false;
case FormatStyle::RTBS_All:
case FormatStyle::RTBS_TopLevel:
return true;
case FormatStyle::RTBS_AllDefinitions:
case FormatStyle::RTBS_TopLevelDefinitions:
return Line.mightBeFunctionDefinition();
}

return false;
}

void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(),
E = Line.Children.end();
Expand Down Expand Up @@ -1613,15 +1636,9 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
Current->MustBreakBefore =
Current->MustBreakBefore || mustBreakBefore(Line, *Current);

if ((Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_All ||
(Style.AlwaysBreakAfterDefinitionReturnType ==
FormatStyle::DRTBS_TopLevel &&
Line.Level == 0)) &&
InFunctionDecl && Current->is(TT_FunctionDeclarationName) &&
!Line.Last->isOneOf(tok::semi, tok::comment)) // Only for definitions.
// FIXME: Line.Last points to other characters than tok::semi
// and tok::lbrace.
Current->MustBreakBefore = true;
if (!Current->MustBreakBefore && InFunctionDecl &&
Current->is(TT_FunctionDeclarationName))
Current->MustBreakBefore = mustBreakForReturnType(Line);

Current->CanBreakBefore =
Current->MustBreakBefore || canBreakBefore(Line, *Current);
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Format/TokenAnnotator.h
Expand Up @@ -86,6 +86,15 @@ class AnnotatedLine {
return startsWith(First, Tokens...);
}

/// \c true if this line looks like a function definition instead of a
/// function declaration. Asserts MightBeFunctionDecl.
bool mightBeFunctionDefinition() const {
assert(MightBeFunctionDecl);
// FIXME: Line.Last points to other characters than tok::semi
// and tok::lbrace.
return !Last->isOneOf(tok::semi, tok::comment);
}

FormatToken *First;
FormatToken *Last;

Expand Down Expand Up @@ -156,6 +165,8 @@ class TokenAnnotator {

bool canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right);

bool mustBreakForReturnType(const AnnotatedLine &Line) const;

void printDebugInfo(const AnnotatedLine &Line);

void calculateUnbreakableTailLengths(AnnotatedLine &Line);
Expand Down
81 changes: 74 additions & 7 deletions clang/unittests/Format/FormatTest.cpp
Expand Up @@ -4732,28 +4732,82 @@ TEST_F(FormatTest, AlignsStringLiterals) {
" \"c\";");
}

TEST_F(FormatTest, DefinitionReturnTypeBreakingStyle) {
TEST_F(FormatTest, ReturnTypeBreakingStyle) {
FormatStyle Style = getLLVMStyle();
Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_TopLevel;
verifyFormat("class C {\n"
// No declarations or definitions should be moved to own line.
Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
verifyFormat("class A {\n"
" int f() { return 1; }\n"
" int g();\n"
"};\n"
"int f() { return 1; }\n"
"int g();\n",
Style);

// All declarations and definitions should have the return type moved to its
// own
// line.
Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_All;
verifyFormat("class E {\n"
" int\n"
" f() {\n"
" return 1;\n"
" }\n"
" int\n"
" g();\n"
"};\n"
"int\n"
"f() {\n"
" return 1;\n"
"}",
"}\n"
"int\n"
"g();\n",
Style);
Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;

// Top-level definitions, and no kinds of declarations should have the
// return type moved to its own line.
Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevelDefinitions;
verifyFormat("class B {\n"
" int f() { return 1; }\n"
" int g();\n"
"};\n"
"int\n"
"f() {\n"
" return 1;\n"
"}\n"
"int g();\n",
Style);

// Top-level definitions and declarations should have the return type moved
// to its own line.
Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel;
verifyFormat("class C {\n"
" int f() { return 1; }\n"
" int g();\n"
"};\n"
"int\n"
"f() {\n"
" return 1;\n"
"}\n"
"int\n"
"g();\n",
Style);

// All definitions should have the return type moved to its own line, but no
// kinds of declarations.
Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
verifyFormat("class D {\n"
" int\n"
" f() {\n"
" return 1;\n"
" }\n"
" int g();\n"
"};\n"
"int\n"
"f() {\n"
" return 1;\n"
"}",
"}\n"
"int g();\n",
Style);
verifyFormat("const char *\n"
"f(void) {\n" // Break here.
Expand Down Expand Up @@ -5688,7 +5742,7 @@ TEST_F(FormatTest, UnderstandsAttributes) {
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa __attribute__((unused))\n"
"aaaaaaaaaaaaaaaaaaaaaaa(int i);");
FormatStyle AfterType = getLLVMStyle();
AfterType.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
AfterType.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
verifyFormat("__attribute__((nodebug)) void\n"
"foo() {}\n",
AfterType);
Expand Down Expand Up @@ -9829,6 +9883,19 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE("BreakBeforeBraces: Custom", BreakBeforeBraces,
FormatStyle::BS_Custom);

Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_All;
CHECK_PARSE("AlwaysBreakAfterReturnType: None", AlwaysBreakAfterReturnType,
FormatStyle::RTBS_None);
CHECK_PARSE("AlwaysBreakAfterReturnType: All", AlwaysBreakAfterReturnType,
FormatStyle::RTBS_All);
CHECK_PARSE("AlwaysBreakAfterReturnType: TopLevel",
AlwaysBreakAfterReturnType, FormatStyle::DRTBS_TopLevel);
CHECK_PARSE("AlwaysBreakAfterReturnType: AllDefinitions",
AlwaysBreakAfterReturnType, FormatStyle::RTBS_AllDefinitions);
CHECK_PARSE("AlwaysBreakAfterReturnType: TopLevelDefinitions",
AlwaysBreakAfterReturnType,
FormatStyle::RTBS_TopLevelDefinitions);

Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All;
CHECK_PARSE("AlwaysBreakAfterDefinitionReturnType: None",
AlwaysBreakAfterDefinitionReturnType, FormatStyle::DRTBS_None);
Expand Down

0 comments on commit 448592e

Please sign in to comment.