Index: clang/docs/ClangFormatStyleOptions.rst =================================================================== --- clang/docs/ClangFormatStyleOptions.rst +++ clang/docs/ClangFormatStyleOptions.rst @@ -3656,6 +3656,21 @@ } } + * ``SBPO_ControlStatementsAndFunctionDefinitionsExceptControlMacros`` (in configuration: ``ControlStatementsAndFunctionDefinitionsExceptControlMacros``) + Same as ``SBPO_ControlStatementsExceptControlMacros`` but also put a + space before opening parentheses for function definitions. + + .. code-block:: c++ + + void f(); + void f () { + if (true) { + Q_FOREACH(...) { + f(); + } + } + } + * ``SBPO_NonEmptyParentheses`` (in configuration: ``NonEmptyParentheses``) Put a space before opening parentheses only if the parentheses are not empty i.e. '()' Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -3286,6 +3286,19 @@ /// } /// \endcode SBPO_ControlStatementsExceptControlMacros, + /// Same as ``SBPO_ControlStatementsExceptControlMacros`` but also put a + /// space before opening parentheses for function definitions. + /// \code + /// void f(); + /// void f () { + /// if (true) { + /// Q_FOREACH(...) { + /// f(); + /// } + /// } + /// } + /// \endcode + SBPO_ControlStatementsAndFunctionDefinitionsExceptControlMacros, /// Put a space before opening parentheses only if the parentheses are not /// empty i.e. '()' /// \code Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -459,6 +459,10 @@ FormatStyle::SBPO_ControlStatements); IO.enumCase(Value, "ControlStatementsExceptControlMacros", FormatStyle::SBPO_ControlStatementsExceptControlMacros); + IO.enumCase( + Value, "ControlStatementsAndFunctionDefinitionsExceptControlMacros", + FormatStyle:: + SBPO_ControlStatementsAndFunctionDefinitionsExceptControlMacros); IO.enumCase(Value, "NonEmptyParentheses", FormatStyle::SBPO_NonEmptyParentheses); IO.enumCase(Value, "Always", FormatStyle::SBPO_Always); Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -3138,12 +3138,18 @@ if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) || (Left.is(tok::r_square) && Left.is(TT_AttributeSquare))) return true; - if (Style.SpaceBeforeParens == - FormatStyle::SBPO_ControlStatementsExceptControlMacros && + if ((Style.SpaceBeforeParens == + FormatStyle::SBPO_ControlStatementsExceptControlMacros || + Style.SpaceBeforeParens == + FormatStyle:: + SBPO_ControlStatementsAndFunctionDefinitionsExceptControlMacros) && Left.is(TT_ForEachMacro)) return false; - if (Style.SpaceBeforeParens == - FormatStyle::SBPO_ControlStatementsExceptControlMacros && + if ((Style.SpaceBeforeParens == + FormatStyle::SBPO_ControlStatementsExceptControlMacros || + Style.SpaceBeforeParens == + FormatStyle:: + SBPO_ControlStatementsAndFunctionDefinitionsExceptControlMacros) && Left.is(TT_IfMacro)) return false; return Line.Type == LT_ObjCDecl || Left.is(tok::semi) || @@ -3440,6 +3446,26 @@ if (Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow) || Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow)) return true; + if (Right.is(tok::l_paren) && Line.MightBeFunctionDecl) { + if (Style.SpaceBeforeParens == + FormatStyle:: + SBPO_ControlStatementsAndFunctionDefinitionsExceptControlMacros) { + // Find in the line if there was another set of parenthesis, + // indeed we want to add a space only before the first one + bool IsFirstLParen = true; + const FormatToken *Tok = Right.Previous; + while (Tok) { + if (Tok->is(tok::r_paren)) { + IsFirstLParen = false; + break; + } + Tok = Tok->Previous; + } + if (IsFirstLParen && Line.mightBeFunctionDefinition()) { + return true; + } + } + } if (Right.is(TT_OverloadedOperatorLParen)) return spaceRequiredBeforeParens(Right); if (Left.is(tok::comma)) Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -2117,6 +2117,13 @@ "}", Style); + Style.SpaceBeforeParens = FormatStyle:: + SBPO_ControlStatementsAndFunctionDefinitionsExceptControlMacros; + verifyFormat("void f () {\n" + " Q_FOREACH(Item *item, itemlist) {}\n" + "}", + Style); + // As function-like macros. verifyFormat("#define foreach(x, y)\n" "#define Q_FOREACH(x, y)\n" @@ -14133,6 +14140,62 @@ verifyFormat("X A::operator++ (T);", SomeSpace); verifyFormat("int x = int (y);", SomeSpace); verifyFormat("auto lambda = []() { return 0; };", SomeSpace); + + FormatStyle SomeSpace2 = getLLVMStyle(); + SomeSpace2.SpaceBeforeParens = FormatStyle:: + SBPO_ControlStatementsAndFunctionDefinitionsExceptControlMacros; + + verifyFormat("int f();", SomeSpace2); + verifyFormat("void f (int a, T b) {\n" + " while (true)\n" + " continue;\n" + "}", + SomeSpace2); + verifyFormat("if (true)\n" + " f();\n" + "else if (true)\n" + " f();", + SomeSpace2); + verifyFormat("do {\n" + " do_something();\n" + "} while (something());", + SomeSpace2); + verifyFormat("switch (x) {\n" + "default:\n" + " break;\n" + "}", + SomeSpace2); + verifyFormat("A::A () : a(1) {}", SomeSpace2); + verifyFormat("void f() __attribute__((asdf));", SomeSpace2); + verifyFormat("*(&a + 1);\n" + "&((&a)[1]);\n" + "a[(b + c) * d];\n" + "(((a + 1) * 2) + 3) * 4;", + SomeSpace2); + verifyFormat("#define A(x) x", SomeSpace2); + verifyFormat("#define A (x) x", SomeSpace2); + verifyFormat("#if defined(x)\n" + "#endif", + SomeSpace2); + verifyFormat("auto i = std::make_unique(5);", SomeSpace2); + verifyFormat("size_t x = sizeof(x);", SomeSpace2); + verifyFormat("auto f(int x) -> decltype(x);", SomeSpace2); + verifyFormat("auto f(int x) -> typeof(x);", SomeSpace2); + verifyFormat("auto f(int x) -> _Atomic(x);", SomeSpace2); + verifyFormat("auto f(int x) -> __underlying_type(x);", SomeSpace2); + verifyFormat("int f(T x) noexcept(x.create());", SomeSpace2); + verifyFormat("alignas(128) char a[128];", SomeSpace2); + verifyFormat("size_t x = alignof(MyType);", SomeSpace2); + verifyFormat("static_assert(sizeof(char) == 1, \"Impossible!\");", + SomeSpace2); + verifyFormat("int f() throw(Deprecated);", SomeSpace2); + verifyFormat("typedef void (*cb)(int);", SomeSpace2); + verifyFormat("T A::operator()();", SomeSpace2); + verifyFormat("X A::operator++(T);", SomeSpace2); + verifyFormat("auto lambda = []() { return 0; };", SomeSpace2); + verifyFormat("int x = int(y);", SomeSpace2); + verifyFormat("M (std::size_t R, std::size_t C) : C(C), data(R) {}", + SomeSpace2); } TEST_F(FormatTest, SpaceAfterLogicalNot) {