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

llvm-svn: 196901
This commit is contained in:
Alexander Kornienko
2013-12-10 10:18:34 +00:00
parent b2eb3d3177
commit fdca83d487
5 changed files with 151 additions and 22 deletions

View File

@@ -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 <Protocol>`` instead of ``Foo<Protocol>``.
**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

View File

@@ -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 (<tt>for/if/while...</tt>).
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;
}

View File

@@ -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<clang::format::FormatStyle> {
static void mapping(llvm::yaml::IO &IO, clang::format::FormatStyle &Style) {
if (IO.outputting()) {
@@ -179,11 +197,16 @@ template <> struct MappingTraits<clang::format::FormatStyle> {
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;

View File

@@ -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;

View File

@@ -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);