crayroud created this revision.
crayroud added reviewers: aaron.ballman, rsmith.
crayroud added projects: clang, clang-format.
crayroud requested review of this revision.

For some projects the coding style defined requires to have a space before 
opening parentheses for function definitions.

This revision adds the 
ControlStatementsAndFunctionDefinitionsExceptControlMacros option to 
SpaceBeforeParens which act as SBPO_ControlStatementsExceptControlMacros but 
also put a space before opening parentheses for function definitions.

The goal of this commit is too add the support of clang-format to these 
projects.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D110833

Files:
  clang/docs/ClangFormatStyleOptions.rst
  clang/include/clang/Format/Format.h
  clang/lib/Format/Format.cpp
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTest.cpp

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<int>(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) {
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/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/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/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. '()'
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to