Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -1584,6 +1584,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 @@ -260,6 +260,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.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -62,7 +62,7 @@ if (NonTemplateLess.count(CurrentToken->Previous)) return false; - const FormatToken &Previous = *CurrentToken->Previous; // The '<'. + const FormatToken &Previous = *CurrentToken->Previous; // The '<'. if (Previous.Previous) { if (Previous.Previous->Tok.isLiteral()) return false; @@ -366,7 +366,7 @@ // specifier parameter, although this is technically valid: // [[foo(:)]] if (AttrTok->is(tok::colon) || - AttrTok->startsSequence(tok::identifier, tok::identifier) || + AttrTok->startsSequence(tok::identifier, tok::identifier) || AttrTok->startsSequence(tok::r_paren, tok::identifier)) return false; if (AttrTok->is(tok::ellipsis)) @@ -523,11 +523,11 @@ // Here, we set FirstObjCSelectorName when the end of the method call is // reached, in case it was not set already. if (!Contexts.back().FirstObjCSelectorName) { - FormatToken* Previous = CurrentToken->getPreviousNonComment(); - if (Previous && Previous->is(TT_SelectorName)) { - Previous->ObjCSelectorNameParts = 1; - Contexts.back().FirstObjCSelectorName = Previous; - } + FormatToken *Previous = CurrentToken->getPreviousNonComment(); + if (Previous && Previous->is(TT_SelectorName)) { + Previous->ObjCSelectorNameParts = 1; + Contexts.back().FirstObjCSelectorName = Previous; + } } else { Left->ParameterCount = Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts; @@ -1388,7 +1388,8 @@ Current.Type = Current.Previous->Type; } } else if (canBeObjCSelectorComponent(Current) && - // FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen. + // FIXME(bug 36976): ObjC return types shouldn't use + // TT_CastRParen. Current.Previous && Current.Previous->is(TT_CastRParen) && Current.Previous->MatchingParen && Current.Previous->MatchingParen->Previous && @@ -2414,9 +2415,9 @@ if (Right.isOneOf(tok::semi, tok::comma)) return false; if (Right.is(tok::less) && Line.Type == LT_ObjCDecl) { - bool IsLightweightGeneric = - Right.MatchingParen && Right.MatchingParen->Next && - Right.MatchingParen->Next->is(tok::colon); + bool IsLightweightGeneric = Right.MatchingParen && + Right.MatchingParen->Next && + Right.MatchingParen->Next->is(tok::colon); return !IsLightweightGeneric && Style.ObjCSpaceBeforeProtocolList; } if (Right.is(tok::less) && Left.is(tok::kw_template)) @@ -2538,7 +2539,18 @@ (!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_paren) || + (Left.Tok.getIdentifierInfo() && + Left.Tok.getIdentifierInfo()->isKeyword( + getFormattingLangOpts(Style)))) && + Line.Type != LT_PreprocessorDirective) || + (Style.SpaceBeforeParens == FormatStyle::SBPO_NonEmptyParentheses && + Right.ParameterCount >= 1 && + (Left.is(tok::identifier) || Left.isFunctionLikeKeyword() || + Left.is(tok::r_square) || Left.is(tok::r_paren) || + (Left.Tok.getIdentifierInfo() && + Left.Tok.getIdentifierInfo()->isKeyword( + getFormattingLangOpts(Style)))) && Line.Type != LT_PreprocessorDirective); } if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword) @@ -2601,7 +2613,8 @@ // Slashes occur in text protocol extension syntax: [type/type] { ... }. if (Left.is(tok::slash) || Right.is(tok::slash)) return false; - if (Left.MatchingParen && Left.MatchingParen->is(TT_ProtoExtensionLSquare) && + if (Left.MatchingParen && + Left.MatchingParen->is(TT_ProtoExtensionLSquare) && Right.isOneOf(tok::l_brace, tok::less)) return !Style.Cpp11BracedListStyle; // A percent is probably part of a formatting specification, such as %lld. @@ -2729,7 +2742,9 @@ Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow)) return true; if (Right.is(TT_OverloadedOperatorLParen)) - return Style.SpaceBeforeParens == FormatStyle::SBPO_Always; + return Style.SpaceBeforeParens == FormatStyle::SBPO_Always || + (Style.SpaceBeforeParens == FormatStyle::SBPO_NonEmptyParentheses && + Right.ParameterCount >= 1); if (Left.is(tok::comma)) return true; if (Right.is(tok::comma)) @@ -2813,7 +2828,9 @@ return true; if (Left.is(TT_TemplateCloser) && Right.is(tok::l_paren) && Right.isNot(TT_FunctionTypeLParen)) - return Style.SpaceBeforeParens == FormatStyle::SBPO_Always; + return Style.SpaceBeforeParens == FormatStyle::SBPO_Always || + (Style.SpaceBeforeParens == FormatStyle::SBPO_NonEmptyParentheses && + Right.ParameterCount >= 1); if (Right.is(TT_TemplateOpener) && Left.is(tok::r_paren) && Left.MatchingParen && Left.MatchingParen->is(TT_OverloadedOperatorLParen)) return false; @@ -3118,7 +3135,7 @@ // function f(): a is B { ... } // Do not break before is in these cases. if (Right.is(Keywords.kw_is)) { - const FormatToken* Next = Right.getNextNonComment(); + const FormatToken *Next = Right.getNextNonComment(); // If `is` is followed by a colon, it's likely that it's a dict key, so // ignore it for this check. // For example this is common in Polymer: Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -9271,6 +9271,59 @@ verifyFormat("typedef void (*cb) (int);", Space); verifyFormat("T A::operator() ();", Space); verifyFormat("X A::operator++ (T);", 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); } TEST_F(FormatTest, ConfigurableSpacesInParentheses) { @@ -11055,6 +11108,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);