From: Zachary Turner Date: Fri, 18 Dec 2015 22:20:15 +0000 (+0000) Subject: Support AlwaysBreakAfterReturnType X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bef33a25fe5cdc48025d3a29591e6ac784989b2f;p=clang Support AlwaysBreakAfterReturnType 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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@256046 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst index 9b4ffe300f..bfabd5985c 100644 --- a/docs/ClangFormatStyleOptions.rst +++ b/docs/ClangFormatStyleOptions.rst @@ -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: @@ -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``) diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index f957f39d88..128c4f8c91 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -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 @@ -584,8 +604,7 @@ struct FormatStyle { AllowShortIfStatementsOnASingleLine == R.AllowShortIfStatementsOnASingleLine && AllowShortLoopsOnASingleLine == R.AllowShortLoopsOnASingleLine && - AlwaysBreakAfterDefinitionReturnType == - R.AlwaysBreakAfterDefinitionReturnType && + AlwaysBreakAfterReturnType == R.AlwaysBreakAfterReturnType && AlwaysBreakBeforeMultilineStrings == R.AlwaysBreakBeforeMultilineStrings && AlwaysBreakTemplateDeclarations == diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index 3b6e193837..41451b91f8 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -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; } diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index a7e0799c11..97195aa946 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -104,6 +104,18 @@ template <> struct ScalarEnumerationTraits { } }; +template <> +struct ScalarEnumerationTraits { + 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 { static void @@ -233,6 +245,21 @@ template <> struct MappingTraits { 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", @@ -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; @@ -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; @@ -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; diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index b8487e1035..e06389c317 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -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::iterator I = Line.Children.begin(), E = Line.Children.end(); @@ -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); diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h index b8a6be057a..5329f1f3f2 100644 --- a/lib/Format/TokenAnnotator.h +++ b/lib/Format/TokenAnnotator.h @@ -86,6 +86,15 @@ public: 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; @@ -156,6 +165,8 @@ private: bool canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right); + bool mustBreakForReturnType(const AnnotatedLine &Line) const; + void printDebugInfo(const AnnotatedLine &Line); void calculateUnbreakableTailLengths(AnnotatedLine &Line); diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index e43453dd17..ec53c65821 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -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. @@ -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); @@ -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);