MyDeveloperDay created this revision.
MyDeveloperDay added reviewers: klimek, djasper, JonasToth, russellmcc, reuk.
MyDeveloperDay added a project: clang-tools-extra.

Code::Blocks and Qt Creator code uses a style guide which recommends indenting 
the next line after the access modifier e.g.

  class Foo
  {
        int abc;
  
        public:
            int def;
            void foo();
  
        private:
            int ghi;
            void foo();
  }

The following patch with the addition of a new option

  AccessModifierIndentation: true

This PR was raised a long time ago (2014), and recently was pinged for an update

The following patch aim to address this issue, potentially allowing 
clang-format to be used (rather than astyle)


https://reviews.llvm.org/D60225

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

Index: clang/unittests/Format/FormatTest.cpp
===================================================================
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -1982,6 +1982,209 @@
                    Style));
 }
 
+TEST_F(FormatTest, FormatAccessModifierIndentation) {
+  FormatStyle Style = getLLVMStyle();
+  Style.AccessModifierIndentation = false;
+  EXPECT_EQ("class Foo1 {\n"
+            "  int i;\n"
+            "\n"
+            "public:\n"
+            "  int j;\n"
+            "  int k;\n"
+            "  Foo1() {}\n"
+            "\n"
+            "private:\n"
+            "  Bar() {}\n"
+            "  int l;\n"
+            "  int m;\n"
+            "\n"
+            "protected:\n"
+            "  Ping() {}\n"
+            "  int n;\n"
+            "  int o;\n"
+            "};\n",
+            format("class Foo1 {\n"
+                   "int i;\n"
+                   "public:\n"
+                   "int j;\n"
+                   "int k;\n"
+                   "Foo1() {}\n"
+                   "private:\n"
+                   "Bar() {}\n"
+                   "int l;\n"
+                   "int m;\n"
+                   "protected:\n"
+                   "Ping() {}\n"
+                   "int n;\n"
+                   "int o;\n"
+                   "};\n",
+                   Style));
+
+  Style.AccessModifierIndentation = true;
+  EXPECT_EQ("class Foo2 {\n"
+            "    int i;\n"
+            "\n"
+            "public:\n"
+            "    int j;\n"
+            "    int k;\n"
+            "    Foo2() {}\n"
+            "\n"
+            "private:\n"
+            "    Bar() {}\n"
+            "    int l;\n"
+            "    int m;\n"
+            "\n"
+            "protected:\n"
+            "    Ping() {}\n"
+            "    int n;\n"
+            "    int o;\n"
+            "};\n",
+            format("class Foo2 {\n"
+                   "int i;\n"
+                   "public:\n"
+                   "int j;\n"
+                   "int k;\n"
+                   "Foo2() {}\n"
+                   "private:\n"
+                   "Bar() {}\n"
+                   "int l;\n"
+                   "int m;\n"
+                   "protected:\n"
+                   "Ping() {}\n"
+                   "int n;\n"
+                   "int o;\n"
+                   "};\n",
+                   Style));
+
+  Style.BreakBeforeBraces = FormatStyle::BS_Allman;
+  Style.AccessModifierIndentation = false;
+  EXPECT_EQ("class Foo3\n"
+            "{\n"
+            "  int i;\n"
+            "\n"
+            "public:\n"
+            "  int j;\n"
+            "  int k;\n"
+            "  Foo3() {}\n"
+            "\n"
+            "private:\n"
+            "  Bar() {}\n"
+            "  int l;\n"
+            "  int m;\n"
+            "\n"
+            "protected:\n"
+            "  Ping() {}\n"
+            "  int n;\n"
+            "  int o;\n"
+            "};\n",
+            format("class Foo3 {\n"
+                   "int i;\n"
+                   "public:\n"
+                   "int j;\n"
+                   "int k;\n"
+                   "Foo3() {}\n"
+                   "private:\n"
+                   "Bar() {}\n"
+                   "int l;\n"
+                   "int m;\n"
+                   "protected:\n"
+                   "Ping() {}\n"
+                   "int n;\n"
+                   "int o;\n"
+                   "};\n",
+                   Style));
+
+  Style.AccessModifierIndentation = true;
+  EXPECT_EQ("class Foo4\n"
+            "{\n"
+            "    int i;\n"
+            "\n"
+            "public:\n"
+            "    int j;\n"
+            "    int k;\n"
+            "    Foo4() {}\n"
+            "\n"
+            "private:\n"
+            "    Bar() {}\n"
+            "    int l;\n"
+            "    int m;\n"
+            "\n"
+            "protected:\n"
+            "    Ping() {}\n"
+            "    int n;\n"
+            "    int o;\n"
+            "};\n",
+            format("class Foo4 {\n"
+                   "int i;\n"
+                   "public:\n"
+                   "int j;\n"
+                   "int k;\n"
+                   "Foo4() {}\n"
+                   "private:\n"
+                   "Bar() {}\n"
+                   "int l;\n"
+                   "int m;\n"
+                   "protected:\n"
+                   "Ping() {}\n"
+                   "int n;\n"
+                   "int o;\n"
+                   "};\n",
+                   Style));
+
+  EXPECT_EQ("class Foo5\n"
+            "{\n"
+            "    int i;\n"
+            "\n"
+            "public:\n"
+            "    int j;\n"
+            "    int k;\n"
+            "    Foo5() {}\n"
+            "    class Inner\n"
+            "    {\n"
+            "    private:\n"
+            "        Bar() {}\n"
+            "        int l;\n"
+            "        int m;\n"
+            "\n"
+            "    protected:\n"
+            "        Ping() {}\n"
+            "        int n;\n"
+            "        int o;\n"
+            "    };\n"
+            "};\n",
+            format("class Foo5 {\n"
+                   "int i;\n"
+                   "public:\n"
+                   "int j;\n"
+                   "int k;\n"
+                   "Foo5() {}\n"
+                   "class Inner {\n"
+                   "private:\n"
+                   "Bar() {}\n"
+                   "int l;\n"
+                   "int m;\n"
+                   "protected:\n"
+                   "Ping() {}\n"
+                   "int n;\n"
+                   "int o;\n"
+                   "};\n"
+                   "};\n",
+                   Style));
+
+  EXPECT_EQ("struct Foo6\n"
+            "{\n"
+            "  int i;\n"
+            "  int j;\n"
+            "  int k;\n"
+            "};\n",
+            format("struct Foo6 {\n"
+                   "int i;\n"
+                   "int j;\n"
+                   "int k;\n"
+                   "};\n",
+                   Style));
+}
+
 TEST_F(FormatTest, FormatsExternC) {
   verifyFormat("extern \"C\" {\nint a;");
   verifyFormat("extern \"C\" {}");
@@ -11308,6 +11511,7 @@
   CHECK_PARSE_BOOL(SpaceBeforeCtorInitializerColon);
   CHECK_PARSE_BOOL(SpaceBeforeInheritanceColon);
   CHECK_PARSE_BOOL(SpaceBeforeRangeBasedForLoopColon);
+  CHECK_PARSE_BOOL(AccessModifierIndentation);
 
   CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterClass);
   CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterControlStatement);
Index: clang/lib/Format/UnwrappedLineParser.h
===================================================================
--- clang/lib/Format/UnwrappedLineParser.h
+++ clang/lib/Format/UnwrappedLineParser.h
@@ -86,7 +86,7 @@
   void parseFile();
   void parseLevel(bool HasOpeningBrace);
   void parseBlock(bool MustBeDeclaration, bool AddLevel = true,
-                  bool MunchSemi = true);
+                  bool MunchSemi = true, bool IndentedAccessModifiers = false);
   void parseChildBlock();
   void parsePPDirective();
   void parsePPDefine();
Index: clang/lib/Format/UnwrappedLineParser.cpp
===================================================================
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -526,7 +526,8 @@
 }
 
 void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
-                                     bool MunchSemi) {
+                                     bool MunchSemi,
+                                     bool IndentedAccessModifiers) {
   assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) &&
          "'{' or macro block token expected");
   const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin);
@@ -552,6 +553,10 @@
                                           MustBeDeclaration);
   if (AddLevel)
     ++Line->Level;
+
+  if (IndentedAccessModifiers)
+    ++Line->Level;
+
   parseLevel(/*HasOpeningBrace=*/true);
 
   if (eof())
@@ -1997,6 +2002,13 @@
 }
 
 void UnwrappedLineParser::parseAccessSpecifier() {
+  // Indentation after an access modifier unindent one level
+  // if already in indented scope
+  // uneven/odd level nested access modifiers handles inner
+  // classes case
+  if (Style.AccessModifierIndentation && Line->Level % 2 == 0)
+    --Line->Level;
+
   nextToken();
   // Understand Qt's slots.
   if (FormatTok->isOneOf(Keywords.kw_slots, Keywords.kw_qslots))
@@ -2005,6 +2017,10 @@
   if (FormatTok->Tok.is(tok::colon))
     nextToken();
   addUnwrappedLine();
+
+  // After we wrap for Access modifier then indent a level if desired
+  if (Style.AccessModifierIndentation && Line->Level >= 1)
+    ++Line->Level;
 }
 
 bool UnwrappedLineParser::parseEnum() {
@@ -2197,8 +2213,45 @@
       if (ShouldBreakBeforeBrace(Style, InitialToken))
         addUnwrappedLine();
 
+      bool ContainsAccessModifier = false;
+
+      // If the block is a class or a struct, scan to the matching `}` to
+      // determine if it has any access modifiers, if so we must double the
+      // indent level of the class ahead of the first modifier, to ensure
+      // implicitly private members are aligned with indented members after
+      // first modifier
+      if (Style.AccessModifierIndentation &&
+          InitialToken.isOneOf(tok::kw_class, tok::kw_struct)) {
+        unsigned StoredPosition = Tokens->getPosition();
+        FormatToken *Next;
+        int BraceLevel = 1;
+        do {
+          Next = Tokens->getNextToken();
+          if (!Next)
+            break;
+          // Keep track of the token range of class or struct.
+          if (Next->is(tok::l_brace))
+            ++BraceLevel;
+          if (Next->is(tok::r_brace)) {
+            --BraceLevel;
+            if (BraceLevel == 0)
+              break;
+          }
+          // If any access specifiers or signals/slots (Qt) we will need
+          // to doubly indent
+          if (Next->isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected,
+                            Keywords.kw_signals, Keywords.kw_qsignals,
+                            Keywords.kw_slots, Keywords.kw_qslots)) {
+            ContainsAccessModifier = true;
+            break;
+          }
+        } while (Next);
+        FormatTok = Tokens->setPosition(StoredPosition);
+      }
+
       parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true,
-                 /*MunchSemi=*/false);
+                 /*MunchSemi=*/false,
+                 /*IndentedAccessModifiers=*/ContainsAccessModifier);
     }
   }
   // There is no addUnwrappedLine() here so that we fall through to parsing a
Index: clang/lib/Format/Format.cpp
===================================================================
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -455,6 +455,8 @@
     IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd);
     IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
     IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
+    IO.mapOptional("AccessModifierIndentation",
+                   Style.AccessModifierIndentation);
     IO.mapOptional("ObjCBinPackProtocolList", Style.ObjCBinPackProtocolList);
     IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
     IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
@@ -715,6 +717,7 @@
   LLVMStyle.MaxEmptyLinesToKeep = 1;
   LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
   LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
+  LLVMStyle.AccessModifierIndentation = false;
   LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto;
   LLVMStyle.ObjCBlockIndentWidth = 2;
   LLVMStyle.ObjCSpaceAfterProperty = false;
Index: clang/include/clang/Format/Format.h
===================================================================
--- clang/include/clang/Format/Format.h
+++ clang/include/clang/Format/Format.h
@@ -47,6 +47,14 @@
 /// The ``FormatStyle`` is used to configure the formatting to follow
 /// specific guidelines.
 struct FormatStyle {
+  /// Indents after access modifiers. i.e.
+  /// \code
+  ///    false:                                 true:
+  ///    public:              vs.               public:
+  ///    foo();                                     foo();
+  /// \endcode
+  bool AccessModifierIndentation;
+
   /// The extra indent or outdent of access modifiers, e.g. ``public:``.
   int AccessModifierOffset;
 
@@ -449,38 +457,38 @@
 
   /// Different ways to break after the template declaration.
   enum BreakTemplateDeclarationsStyle {
-      /// Do not force break before declaration.
-      /// ``PenaltyBreakTemplateDeclaration`` is taken into account.
-      /// \code
-      ///    template <typename T> T foo() {
-      ///    }
-      ///    template <typename T> T foo(int aaaaaaaaaaaaaaaaaaaaa,
-      ///                                int bbbbbbbbbbbbbbbbbbbbb) {
-      ///    }
-      /// \endcode
-      BTDS_No,
-      /// Force break after template declaration only when the following
-      /// declaration spans multiple lines.
-      /// \code
-      ///    template <typename T> T foo() {
-      ///    }
-      ///    template <typename T>
-      ///    T foo(int aaaaaaaaaaaaaaaaaaaaa,
-      ///          int bbbbbbbbbbbbbbbbbbbbb) {
-      ///    }
-      /// \endcode
-      BTDS_MultiLine,
-      /// Always break after template declaration.
-      /// \code
-      ///    template <typename T>
-      ///    T foo() {
-      ///    }
-      ///    template <typename T>
-      ///    T foo(int aaaaaaaaaaaaaaaaaaaaa,
-      ///          int bbbbbbbbbbbbbbbbbbbbb) {
-      ///    }
-      /// \endcode
-      BTDS_Yes
+    /// Do not force break before declaration.
+    /// ``PenaltyBreakTemplateDeclaration`` is taken into account.
+    /// \code
+    ///    template <typename T> T foo() {
+    ///    }
+    ///    template <typename T> T foo(int aaaaaaaaaaaaaaaaaaaaa,
+    ///                                int bbbbbbbbbbbbbbbbbbbbb) {
+    ///    }
+    /// \endcode
+    BTDS_No,
+    /// Force break after template declaration only when the following
+    /// declaration spans multiple lines.
+    /// \code
+    ///    template <typename T> T foo() {
+    ///    }
+    ///    template <typename T>
+    ///    T foo(int aaaaaaaaaaaaaaaaaaaaa,
+    ///          int bbbbbbbbbbbbbbbbbbbbb) {
+    ///    }
+    /// \endcode
+    BTDS_MultiLine,
+    /// Always break after template declaration.
+    /// \code
+    ///    template <typename T>
+    ///    T foo() {
+    ///    }
+    ///    template <typename T>
+    ///    T foo(int aaaaaaaaaaaaaaaaaaaaa,
+    ///          int bbbbbbbbbbbbbbbbbbbbb) {
+    ///    }
+    /// \endcode
+    BTDS_Yes
   };
 
   /// The template declaration breaking style to use.
@@ -1830,7 +1838,8 @@
   UseTabStyle UseTab;
 
   bool operator==(const FormatStyle &R) const {
-    return AccessModifierOffset == R.AccessModifierOffset &&
+    return AccessModifierIndentation == R.AccessModifierIndentation &&
+           AccessModifierOffset == R.AccessModifierOffset &&
            AlignAfterOpenBracket == R.AlignAfterOpenBracket &&
            AlignConsecutiveAssignments == R.AlignConsecutiveAssignments &&
            AlignConsecutiveDeclarations == R.AlignConsecutiveDeclarations &&
Index: clang/docs/ClangFormatStyleOptions.rst
===================================================================
--- clang/docs/ClangFormatStyleOptions.rst
+++ clang/docs/ClangFormatStyleOptions.rst
@@ -154,6 +154,15 @@
 
 .. START_FORMAT_STYLE_OPTIONS
 
+**AccessModifierIndentation** (``bool``)
+  Indents after access modifiers. i.e.
+
+  .. code-block:: c++
+
+     false:                                 true:
+     public:              vs.               public:
+     foo();                                     foo();
+
 **AccessModifierOffset** (``int``)
   The extra indent or outdent of access modifiers, e.g. ``public:``.
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to