From 229328d0e6b91cd5ea78e3d79ec9296a2ac57eea Mon Sep 17 00:00:00 2001 From: Alexander Kornienko Date: Tue, 10 Dec 2013 10:18:34 +0000 Subject: [PATCH] Support GNU style rule to put a space before opening parenthesis. Summary: The rule from the GNU style states: "We find it easier to read a program when it has spaces before the open-parentheses and after the commas." http://www.gnu.org/prep/standards/standards.html#index-spaces-before-open_002dparen This patch makes clang-format adds an option to put spaces before almost all open parentheses, except the cases, where different behavior is dictated by the style rules or language syntax: * preprocessor: ** function-like macro definitions can't have a space between the macro name and the parenthesis; ** `#if defined(...)` can have a space, but it seems, that it's more frequently used without a space in GCC, for example; * never add spaces after unary operators; * adding spaces between two opening parentheses is controlled with the `SpacesInParentheses` option; * never add spaces between `[` and `(` (there's no option yet). Reviewers: djasper Reviewed By: djasper CC: cfe-commits, klimek Differential Revision: http://llvm-reviews.chandlerc.com/D2326 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196901 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/ClangFormatStyleOptions.rst | 56 +++++++++++++++++++++++++++---- include/clang/Format/Format.h | 22 +++++++++--- lib/Format/Format.cpp | 31 ++++++++++++++--- lib/Format/TokenAnnotator.cpp | 7 ++-- unittests/Format/FormatTest.cpp | 57 +++++++++++++++++++++++++++++--- 5 files changed, 151 insertions(+), 22 deletions(-) diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst index d73801c7e7..bbe92c6cd8 100644 --- a/docs/ClangFormatStyleOptions.rst +++ b/docs/ClangFormatStyleOptions.rst @@ -106,6 +106,10 @@ the configuration (without a prefix: ``Auto``). Allow putting all parameters of a function declaration onto the next line even if ``BinPackParameters`` is ``false``. +**AllowShortFunctionsOnASingleLine** (``bool``) + If ``true``, ``int f() { return 0; }`` can be put on a single + line. + **AllowShortIfStatementsOnASingleLine** (``bool``) If ``true``, ``if (a) return;`` can be put on a single line. @@ -144,6 +148,9 @@ the configuration (without a prefix: ``Auto``). Always break before braces. +**BreakBeforeTernaryOperators** (``bool``) + If ``true``, ternary operators will be placed after line breaks. + **BreakConstructorInitializersBeforeComma** (``bool``) Always break constructor initializers before commas and align the commas with the colon. @@ -153,7 +160,7 @@ the configuration (without a prefix: ``Auto``). A column limit of ``0`` means that there is no column limit. In this case, clang-format will respect the input's line breaking decisions within - statements. + statements unless they contradict other rules. **ConstructorInitializerAllOnOneLineOrOnePerLine** (``bool``) If the constructor initializers don't fit on a line, put each @@ -163,6 +170,9 @@ the configuration (without a prefix: ``Auto``). The number of characters to use for indentation of constructor initializer lists. +**ContinuationIndentWidth** (``unsigned``) + Indent width for line continuations. + **Cpp11BracedListStyle** (``bool``) If ``true``, format braced lists as best suited for C++11 braced lists. @@ -206,6 +216,19 @@ the configuration (without a prefix: ``Auto``). **IndentWidth** (``unsigned``) The number of columns to use for indentation. +**Language** (``LanguageKind``) + Language, this format style is targeted at. + + Possible values: + + * ``LK_None`` (in configuration: ``None``) + Do not use. + * ``LK_Cpp`` (in configuration: ``Cpp``) + Should be used for C, C++, ObjectiveC, ObjectiveC++. + * ``LK_JavaScript`` (in configuration: ``JavaScript``) + Should be used for JavaScript. + + **MaxEmptyLinesToKeep** (``unsigned``) The maximum number of consecutive empty lines to keep. @@ -226,6 +249,9 @@ the configuration (without a prefix: ``Auto``). Add a space in front of an Objective-C protocol list, i.e. use ``Foo `` instead of ``Foo``. +**PenaltyBreakBeforeFirstCallParameter** (``unsigned``) + The penalty for breaking a function call after "call(". + **PenaltyBreakComment** (``unsigned``) The penalty for each line break introduced inside a comment. @@ -245,25 +271,41 @@ the configuration (without a prefix: ``Auto``). **PointerBindsToType** (``bool``) Set whether & and * bind to the type as opposed to the variable. -**SpaceAfterControlStatementKeyword** (``bool``) - If ``true``, spaces will be inserted between 'for'/'if'/'while'/... - and '('. - **SpaceBeforeAssignmentOperators** (``bool``) If ``false``, spaces will be removed before assignment operators. +**SpaceBeforeParens** (``SpaceBeforeParensOptions``) + Defines in which cases to put a space before opening parentheses. + + Possible values: + + * ``SBPO_Never`` (in configuration: ``Never``) + Never put a space before opening parentheses. + * ``SBPO_ControlStatements`` (in configuration: ``ControlStatements``) + Put a space before opening parentheses only after control statement + keywords (``for/if/while...``). + * ``SBPO_Always`` (in configuration: ``Always``) + Always put a space before opening parentheses, except when it's + prohibited by the syntax rules (in function-like macro definitions) or + when determined by other style rules (after unary operators, opening + parentheses, etc.) + + **SpaceInEmptyParentheses** (``bool``) If ``false``, spaces may be inserted into '()'. **SpacesBeforeTrailingComments** (``unsigned``) The number of spaces to before trailing line comments. +**SpacesInAngles** (``bool``) + If ``true``, spaces will be inserted after '<' and before '>' in + template argument lists + **SpacesInCStyleCastParentheses** (``bool``) If ``false``, spaces may be inserted into C style casts. **SpacesInParentheses** (``bool``) - If ``true``, spaces will be inserted after every '(' and before - every ')'. + If ``true``, spaces will be inserted after '(' and before ')'. **Standard** (``LanguageStandard``) Format compatible with this standard, e.g. use diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index 5da14fc9f3..954158b2d5 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -256,9 +256,22 @@ struct FormatStyle { /// \brief If \c false, spaces may be inserted into C style casts. bool SpacesInCStyleCastParentheses; - /// \brief If \c true, spaces will be inserted between 'for'/'if'/'while'/... - /// and '('. - bool SpaceAfterControlStatementKeyword; + /// \brief Different ways to put a space before opening parentheses. + enum SpaceBeforeParensOptions { + /// Never put a space before opening parentheses. + SBPO_Never, + /// Put a space before opening parentheses only after control statement + /// keywords (for/if/while...). + SBPO_ControlStatements, + /// Always put a space before opening parentheses, except when it's + /// prohibited by the syntax rules (in function-like macro definitions) or + /// when determined by other style rules (after unary operators, opening + /// parentheses, etc.) + SBPO_Always + }; + + /// \brief Defines in which cases to put a space before opening parentheses. + SpaceBeforeParensOptions SpaceBeforeParens; /// \brief If \c false, spaces will be removed before assignment operators. bool SpaceBeforeAssignmentOperators; @@ -315,8 +328,7 @@ struct FormatStyle { SpacesInAngles == R.SpacesInAngles && SpaceInEmptyParentheses == R.SpaceInEmptyParentheses && SpacesInCStyleCastParentheses == R.SpacesInCStyleCastParentheses && - SpaceAfterControlStatementKeyword == - R.SpaceAfterControlStatementKeyword && + SpaceBeforeParens == R.SpaceBeforeParens && SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators && ContinuationIndentWidth == R.ContinuationIndentWidth; } diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 26a320b05a..60d323d2a9 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -90,6 +90,24 @@ struct ScalarEnumerationTraits< } }; +template <> +struct ScalarEnumerationTraits< + clang::format::FormatStyle::SpaceBeforeParensOptions> { + static void + enumeration(IO &IO, + clang::format::FormatStyle::SpaceBeforeParensOptions &Value) { + IO.enumCase(Value, "Never", clang::format::FormatStyle::SBPO_Never); + IO.enumCase(Value, "ControlStatements", + clang::format::FormatStyle::SBPO_ControlStatements); + IO.enumCase(Value, "Always", clang::format::FormatStyle::SBPO_Always); + + // For backward compatibility. + IO.enumCase(Value, "false", clang::format::FormatStyle::SBPO_Never); + IO.enumCase(Value, "true", + clang::format::FormatStyle::SBPO_ControlStatements); + } +}; + template <> struct MappingTraits { static void mapping(llvm::yaml::IO &IO, clang::format::FormatStyle &Style) { if (IO.outputting()) { @@ -179,11 +197,16 @@ template <> struct MappingTraits { IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses); IO.mapOptional("SpacesInCStyleCastParentheses", Style.SpacesInCStyleCastParentheses); - IO.mapOptional("SpaceAfterControlStatementKeyword", - Style.SpaceAfterControlStatementKeyword); IO.mapOptional("SpaceBeforeAssignmentOperators", Style.SpaceBeforeAssignmentOperators); IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth); + + // For backward compatibility. + if (!IO.outputting()) { + IO.mapOptional("SpaceAfterControlStatementKeyword", + Style.SpaceBeforeParens); + } + IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens); } }; @@ -266,7 +289,7 @@ FormatStyle getLLVMStyle() { LLVMStyle.SpacesInParentheses = false; LLVMStyle.SpaceInEmptyParentheses = false; LLVMStyle.SpacesInCStyleCastParentheses = false; - LLVMStyle.SpaceAfterControlStatementKeyword = true; + LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; LLVMStyle.SpaceBeforeAssignmentOperators = true; LLVMStyle.ContinuationIndentWidth = 4; LLVMStyle.SpacesInAngles = false; @@ -315,7 +338,7 @@ FormatStyle getGoogleStyle() { GoogleStyle.SpacesInParentheses = false; GoogleStyle.SpaceInEmptyParentheses = false; GoogleStyle.SpacesInCStyleCastParentheses = false; - GoogleStyle.SpaceAfterControlStatementKeyword = true; + GoogleStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; GoogleStyle.SpaceBeforeAssignmentOperators = true; GoogleStyle.ContinuationIndentWidth = 4; GoogleStyle.SpacesInAngles = false; diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index d22facb922..b8905a9bfd 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -1293,9 +1293,12 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return Line.Type == LT_ObjCDecl || Left.isOneOf(tok::kw_return, tok::kw_new, tok::kw_delete, tok::semi) || - (Style.SpaceAfterControlStatementKeyword && + (Style.SpaceBeforeParens != FormatStyle::SBPO_Never && Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, - tok::kw_catch)); + tok::kw_catch)) || + (Style.SpaceBeforeParens == FormatStyle::SBPO_Always && + Left.isOneOf(tok::identifier, tok::kw___attribute) && + Line.Type != LT_PreprocessorDirective); } if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword) return false; diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index e2f8d2fa65..faaafc2c88 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -2082,7 +2082,8 @@ TEST_F(FormatTest, HashInMacroDefinition) { } TEST_F(FormatTest, RespectWhitespaceInMacroDefinitions) { - verifyFormat("#define A (1)"); + EXPECT_EQ("#define A (x)", format("#define A (x)")); + EXPECT_EQ("#define A(x)", format("#define A(x)")); } TEST_F(FormatTest, EmptyLinesInMacroDefinitions) { @@ -6660,9 +6661,9 @@ TEST_F(FormatTest, CalculatesOriginalColumn) { getLLVMStyle())); } -TEST_F(FormatTest, ConfigurableSpaceAfterControlStatementKeyword) { +TEST_F(FormatTest, ConfigurableSpaceBeforeParens) { FormatStyle NoSpace = getLLVMStyle(); - NoSpace.SpaceAfterControlStatementKeyword = false; + NoSpace.SpaceBeforeParens = FormatStyle::SBPO_Never; verifyFormat("while(true)\n" " continue;", NoSpace); @@ -6679,6 +6680,42 @@ TEST_F(FormatTest, ConfigurableSpaceAfterControlStatementKeyword) { "default:\n" " break;\n" "}", NoSpace); + + FormatStyle Space = getLLVMStyle(); + Space.SpaceBeforeParens = FormatStyle::SBPO_Always; + + verifyFormat("int f ();", Space); + verifyFormat("void f (int a, T b) {\n" + " while (true)\n" + " continue;\n" + "}", + Space); + verifyFormat("if (true)\n" + " f ();\n" + "else if (true)\n" + " f ();", + Space); + verifyFormat("do {\n" + " do_something ();\n" + "} while (something ());", + Space); + verifyFormat("switch (x) {\n" + "default:\n" + " break;\n" + "}", + Space); + verifyFormat("A::A () : a (1) {}", Space); + verifyFormat("void f () __attribute__ ((asdf));", Space); + verifyFormat("*(&a + 1);\n" + "&((&a)[1]);\n" + "a[(b + c) * d];\n" + "(((a + 1) * 2) + 3) * 4;", + Space); + verifyFormat("#define A(x) x", Space); + verifyFormat("#define A (x) x", Space); + verifyFormat("#if defined(x)\n" + "#endif", + Space); } TEST_F(FormatTest, ConfigurableSpacesInParentheses) { @@ -6988,7 +7025,6 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE_BOOL(SpacesInAngles); CHECK_PARSE_BOOL(SpaceInEmptyParentheses); CHECK_PARSE_BOOL(SpacesInCStyleCastParentheses); - CHECK_PARSE_BOOL(SpaceAfterControlStatementKeyword); CHECK_PARSE_BOOL(SpaceBeforeAssignmentOperators); CHECK_PARSE("AccessModifierOffset: -1234", AccessModifierOffset, -1234); @@ -7020,6 +7056,19 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE("UseTab: ForIndentation", UseTab, FormatStyle::UT_ForIndentation); CHECK_PARSE("UseTab: Always", UseTab, FormatStyle::UT_Always); + Style.SpaceBeforeParens = FormatStyle::SBPO_Always; + CHECK_PARSE("SpaceBeforeParens: Never", SpaceBeforeParens, + FormatStyle::SBPO_Never); + CHECK_PARSE("SpaceBeforeParens: Always", SpaceBeforeParens, + FormatStyle::SBPO_Always); + CHECK_PARSE("SpaceBeforeParens: ControlStatements", SpaceBeforeParens, + FormatStyle::SBPO_ControlStatements); + // For backward compatibility: + CHECK_PARSE("SpaceAfterControlStatementKeyword: false", SpaceBeforeParens, + FormatStyle::SBPO_Never); + CHECK_PARSE("SpaceAfterControlStatementKeyword: true", SpaceBeforeParens, + FormatStyle::SBPO_ControlStatements); + Style.ColumnLimit = 123; FormatStyle BaseStyle = getLLVMStyle(); CHECK_PARSE("BasedOnStyle: LLVM", ColumnLimit, BaseStyle.ColumnLimit); -- 2.40.0