Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -1613,6 +1613,17 @@ /// } /// \endcode SBPO_ControlStatements, + /// Put a space before opening parentheses only if the parentheses are not + /// empty i.e. '()' + /// \code + /// void() { + /// if (true) { + /// f(); + /// g (x, y, z); + /// } + /// } + /// \endcode + SBPO_NonEmptyParentheses, /// 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 Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -272,6 +272,8 @@ IO.enumCase(Value, "Never", FormatStyle::SBPO_Never); IO.enumCase(Value, "ControlStatements", FormatStyle::SBPO_ControlStatements); + IO.enumCase(Value, "NonEmptyParentheses", + FormatStyle::SBPO_NonEmptyParentheses); IO.enumCase(Value, "Always", FormatStyle::SBPO_Always); // For backward compatibility. Index: lib/Format/TokenAnnotator.h =================================================================== --- lib/Format/TokenAnnotator.h +++ lib/Format/TokenAnnotator.h @@ -164,6 +164,8 @@ unsigned splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok, bool InFunctionDecl); + bool spaceRequiredBeforeParens(const FormatToken &Right) const; + bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left, const FormatToken &Right); Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -2400,6 +2400,12 @@ return 3; } +bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const { + return Style.SpaceBeforeParens == FormatStyle::SBPO_Always || + (Style.SpaceBeforeParens == FormatStyle::SBPO_NonEmptyParentheses && + Right.ParameterCount > 0); +} + bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left, const FormatToken &Right) { @@ -2539,19 +2545,19 @@ return true; return Line.Type == LT_ObjCDecl || Left.is(tok::semi) || (Style.SpaceBeforeParens != FormatStyle::SBPO_Never && - (Left.isOneOf(tok::kw_if, tok::pp_elif, tok::kw_for, tok::kw_while, - tok::kw_switch, tok::kw_case, TT_ForEachMacro, - TT_ObjCForIn) || - Left.endsSequence(tok::kw_constexpr, tok::kw_if) || - (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch, - tok::kw_new, tok::kw_delete) && - (!Left.Previous || Left.Previous->isNot(tok::period))))) || - (Style.SpaceBeforeParens == FormatStyle::SBPO_Always && - (Left.is(tok::identifier) || Left.isFunctionLikeKeyword() || - Left.is(tok::r_paren) || - (Left.is(tok::r_square) && Left.MatchingParen && - Left.MatchingParen->is(TT_LambdaLSquare))) && - Line.Type != LT_PreprocessorDirective); + ((Left.isOneOf(tok::kw_if, tok::pp_elif, tok::kw_for, tok::kw_while, + tok::kw_switch, tok::kw_case, TT_ForEachMacro, + TT_ObjCForIn) || + Left.endsSequence(tok::kw_constexpr, tok::kw_if) || + (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch, + tok::kw_new, tok::kw_delete) && + (!Left.Previous || Left.Previous->isNot(tok::period)))) || + (spaceRequiredBeforeParens(Right) && + ((Left.is(tok::identifier) || Left.isFunctionLikeKeyword() || + Left.is(tok::r_paren) || Left.isSimpleTypeSpecifier() || + (Left.is(tok::r_square) && Left.MatchingParen && + Left.MatchingParen->is(TT_LambdaLSquare))) && + Line.Type != LT_PreprocessorDirective)))); } if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword) return false; @@ -2742,7 +2748,7 @@ Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow)) return true; if (Right.is(TT_OverloadedOperatorLParen)) - return Style.SpaceBeforeParens == FormatStyle::SBPO_Always; + return spaceRequiredBeforeParens(Right); if (Left.is(tok::comma)) return true; if (Right.is(tok::comma)) @@ -2826,7 +2832,7 @@ return true; if (Left.is(TT_TemplateCloser) && Right.is(tok::l_paren) && Right.isNot(TT_FunctionTypeLParen)) - return Style.SpaceBeforeParens == FormatStyle::SBPO_Always; + return spaceRequiredBeforeParens(Right); if (Right.is(TT_TemplateOpener) && Left.is(tok::r_paren) && Left.MatchingParen && Left.MatchingParen->is(TT_OverloadedOperatorLParen)) return false; Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -9337,6 +9337,60 @@ verifyFormat("T A::operator() ();", Space); verifyFormat("X A::operator++ (T);", Space); verifyFormat("auto lambda = [] () { return 0; };", Space); + verifyFormat("int x = int (y);", Space); + + FormatStyle SomeSpace = getLLVMStyle(); + SomeSpace.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses; + + verifyFormat("[]() -> float {}", SomeSpace); + verifyFormat("[] (auto foo) {}", SomeSpace); + verifyFormat("[foo]() -> int {}", SomeSpace); + verifyFormat("int f();", SomeSpace); + verifyFormat("void f (int a, T b) {\n" + " while (true)\n" + " continue;\n" + "}", + SomeSpace); + verifyFormat("if (true)\n" + " f();\n" + "else if (true)\n" + " f();", + SomeSpace); + verifyFormat("do {\n" + " do_something();\n" + "} while (something());", + SomeSpace); + verifyFormat("switch (x) {\n" + "default:\n" + " break;\n" + "}", + SomeSpace); + verifyFormat("A::A() : a (1) {}", SomeSpace); + verifyFormat("void f() __attribute__ ((asdf));", SomeSpace); + verifyFormat("*(&a + 1);\n" + "&((&a)[1]);\n" + "a[(b + c) * d];\n" + "(((a + 1) * 2) + 3) * 4;", + SomeSpace); + verifyFormat("#define A(x) x", SomeSpace); + verifyFormat("#define A (x) x", SomeSpace); + verifyFormat("#if defined(x)\n" + "#endif", + SomeSpace); + verifyFormat("auto i = std::make_unique (5);", SomeSpace); + verifyFormat("size_t x = sizeof (x);", SomeSpace); + verifyFormat("auto f (int x) -> decltype (x);", SomeSpace); + verifyFormat("int f (T x) noexcept (x.create());", SomeSpace); + verifyFormat("alignas (128) char a[128];", SomeSpace); + verifyFormat("size_t x = alignof (MyType);", SomeSpace); + verifyFormat("static_assert (sizeof (char) == 1, \"Impossible!\");", + SomeSpace); + verifyFormat("int f() throw (Deprecated);", SomeSpace); + verifyFormat("typedef void (*cb) (int);", SomeSpace); + verifyFormat("T A::operator()();", SomeSpace); + verifyFormat("X A::operator++ (T);", SomeSpace); + verifyFormat("int x = int (y);", SomeSpace); + verifyFormat("auto lambda = []() { return 0; };", SomeSpace); } TEST_F(FormatTest, ConfigurableSpacesInParentheses) { @@ -11121,6 +11175,8 @@ FormatStyle::SBPO_Always); CHECK_PARSE("SpaceBeforeParens: ControlStatements", SpaceBeforeParens, FormatStyle::SBPO_ControlStatements); + CHECK_PARSE("SpaceBeforeParens: NonEmptyParentheses", SpaceBeforeParens, + FormatStyle::SBPO_NonEmptyParentheses); // For backward compatibility: CHECK_PARSE("SpaceAfterControlStatementKeyword: false", SpaceBeforeParens, FormatStyle::SBPO_Never);