LokiAstari created this revision.
LokiAstari added reviewers: djasper, klimek.
LokiAstari added a subscriber: cfe-commits.
Herald added a subscriber: klimek.

Access Modifiers (public/protected/private) causes standard indent.

```
class MyClass
{
    int value1;        // standard indent.
    public:            // access modifier (increases indent level)
        int value2;    // next item indent one more level 
    private:           // access modifier goes out a level
        int value3;    // next item indent one more level 
};
```

https://reviews.llvm.org/D22505

Files:
  docs/ClangFormatStyleOptions.rst
  include/clang/Format/Format.h
  lib/Format/Format.cpp
  lib/Format/TokenAnnotator.h
  lib/Format/UnwrappedLineFormatter.cpp
  lib/Format/UnwrappedLineParser.cpp
  lib/Format/UnwrappedLineParser.h
  unittests/Format/CMakeLists.txt
  unittests/Format/FormatTestAccess.cpp

Index: unittests/Format/FormatTestAccess.cpp
===================================================================
--- unittests/Format/FormatTestAccess.cpp
+++ unittests/Format/FormatTestAccess.cpp
@@ -0,0 +1,150 @@
+//===- unittest/Format/FormatTestAccess.cpp - Formatting unit tests
+//-------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Format/Format.h"
+
+#include "../Tooling/RewriterTestContext.h"
+#include "FormatTestUtils.h"
+
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+
+#define DEBUG_TYPE "format-test"
+
+namespace clang {
+namespace format {
+namespace {
+
+class FormatTestAccess : public ::testing::Test {
+protected:
+  std::string format(llvm::StringRef Code, bool normalFormat) {
+    const FormatStyle &Style = getGoogleStyleWithColumns(normalFormat);
+    DEBUG(llvm::errs() << "---\n");
+    DEBUG(llvm::errs() << Code << "\n\n");
+    std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
+    bool IncompleteFormat = false;
+    tooling::Replacements Replaces =
+        reformat(Style, Code, Ranges, "<stdin>", &IncompleteFormat);
+    EXPECT_FALSE(IncompleteFormat) << Code << "\n\n";
+    auto Result = applyAllReplacements(Code, Replaces);
+    EXPECT_TRUE(static_cast<bool>(Result));
+    DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
+    return *Result;
+  }
+
+  FormatStyle getGoogleStyleWithColumns(bool normalFormat) {
+    FormatStyle Style = getLLVMStyle();
+    Style.AccessModifierOffset = normalFormat ? 0 : -2;
+    Style.AccessModifierStandardIndent = normalFormat;
+    return Style;
+  }
+
+  void verifyFormat(llvm::StringRef Code, bool normalFormat) {
+    EXPECT_EQ(Code.str(), format(test::messUp(Code), normalFormat));
+  }
+};
+
+TEST_F(FormatTestAccess, NoChangeWithoutAccess) {
+  verifyFormat("class A {\n"
+               "  int a1;\n"
+               "};",
+               false);
+  verifyFormat("class B {\n"
+               "  int b1;\n"
+               "};",
+               true);
+}
+
+TEST_F(FormatTestAccess, ChangeWithAccess) {
+  verifyFormat("class C {\n"
+               "  int c1;\n"
+               "public:\n"
+               "  int c2;\n"
+               "};",
+               false);
+  verifyFormat("class D {\n"
+               "  int d1;\n"
+               "  public:\n"
+               "    int d2;\n"
+               "};",
+               true);
+}
+
+TEST_F(FormatTestAccess, MultipleAccessLevels) {
+  verifyFormat("class E {\n"
+               "  int e1;\n"
+               "public:\n"
+               "  int e2;\n"
+               "private:\n"
+               "  int e3;\n"
+               "protected:\n"
+               "  int e4;\n"
+               "};",
+               false);
+  verifyFormat("class F {\n"
+               "  int f1;\n"
+               "  public:\n"
+               "    int f2;\n"
+               "  private:\n"
+               "    int f3;\n"
+               "  protected:\n"
+               "    int f4;\n"
+               "};",
+               true);
+}
+
+TEST_F(FormatTestAccess, NestedClass) {
+  verifyFormat("class G {\n"
+               "  int g1;\n"
+               "  class GGA {\n"
+               "    int gg1;\n"
+               "  public:\n"
+               "    int gg2;\n"
+               "  };\n"
+               "public:\n"
+               "  class GGB {\n"
+               "    int gg1;\n"
+               "  public:\n"
+               "    int gg2;\n"
+               "  };\n"
+               "  int g2;\n"
+               "private:\n"
+               "  int g3;\n"
+               "protected:\n"
+               "  int g4;\n"
+               "};",
+               false);
+  verifyFormat("class H {\n"
+               "  int h1;\n"
+               "  class HHA {\n"
+               "    int hh1;\n"
+               "    public:\n"
+               "      int hh2;\n"
+               "  };\n"
+               "  public:\n"
+               "    class HHB {\n"
+               "      int hh1;\n"
+               "      public:\n"
+               "        int hh2;\n"
+               "    };\n"
+               "    int h2;\n"
+               "  private:\n"
+               "    int h3;\n"
+               "  protected:\n"
+               "    int h4;\n"
+               "};",
+               true);
+}
+
+} // end namespace
+} // end namespace format
+} // end namespace clang
Index: unittests/Format/CMakeLists.txt
===================================================================
--- unittests/Format/CMakeLists.txt
+++ unittests/Format/CMakeLists.txt
@@ -5,6 +5,7 @@
 add_clang_unittest(FormatTests
   CleanupTest.cpp
   FormatTest.cpp
+  FormatTestAccess.cpp
   FormatTestJava.cpp
   FormatTestJS.cpp
   FormatTestProto.cpp
Index: lib/Format/UnwrappedLineParser.h
===================================================================
--- lib/Format/UnwrappedLineParser.h
+++ lib/Format/UnwrappedLineParser.h
@@ -42,6 +42,8 @@
 
   /// \brief The indent level of the \c UnwrappedLine.
   unsigned Level;
+  /// \brief If an accesses specifier has been used at a particular level
+  std::vector<char> accessLevelMarker;
 
   /// \brief Whether this \c UnwrappedLine is part of a preprocessor directive.
   bool InPPDirective;
@@ -72,7 +74,7 @@
   void parseFile();
   void parseLevel(bool HasOpeningBrace);
   void parseBlock(bool MustBeDeclaration, bool AddLevel = true,
-                  bool MunchSemi = true);
+                  bool MunchSemi = true, bool ClassBlock = false);
   void parseChildBlock();
   void parsePPDirective();
   void parsePPDefine();
@@ -214,7 +216,9 @@
 };
 
 inline UnwrappedLine::UnwrappedLine()
-    : Level(0), InPPDirective(false), MustBeDeclaration(false) {}
+    : Level(0), InPPDirective(false), MustBeDeclaration(false) {
+  accessLevelMarker.push_back(0);
+}
 
 } // end namespace format
 } // end namespace clang
Index: lib/Format/UnwrappedLineParser.cpp
===================================================================
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -410,13 +410,14 @@
 }
 
 void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
-                                     bool MunchSemi) {
+                                     bool MunchSemi, bool ClassBlock) {
   assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) &&
          "'{' or macro block token expected");
   const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin);
   FormatTok->BlockKind = BK_Block;
 
   unsigned InitialLevel = Line->Level;
+  std::vector<char> InitialAccessUsed = Line->accessLevelMarker;
   nextToken();
 
   if (MacroBlock && FormatTok->is(tok::l_paren))
@@ -426,16 +427,21 @@
 
   ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
                                           MustBeDeclaration);
-  if (AddLevel)
+  if (AddLevel) {
+    if (ClassBlock) {
+      Line->accessLevelMarker.push_back(0);
+    }
     ++Line->Level;
+  }
   parseLevel(/*HasOpeningBrace=*/true);
 
   if (eof())
     return;
 
   if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd)
                  : !FormatTok->is(tok::r_brace)) {
     Line->Level = InitialLevel;
+    Line->accessLevelMarker = InitialAccessUsed;
     FormatTok->BlockKind = BK_Block;
     return;
   }
@@ -448,6 +454,7 @@
   if (MunchSemi && FormatTok->Tok.is(tok::semi))
     nextToken();
   Line->Level = InitialLevel;
+  Line->accessLevelMarker = InitialAccessUsed;
 }
 
 static bool isGoogScope(const UnwrappedLine &Line) {
@@ -1119,7 +1126,7 @@
     nextToken();
     return false;
   }
-  const FormatToken* Previous = getPreviousToken();
+  const FormatToken *Previous = getPreviousToken();
   if (Previous &&
       (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new,
                          tok::kw_delete) ||
@@ -1678,7 +1685,10 @@
   // Otherwise, we don't know what it is, and we'd better keep the next token.
   if (FormatTok->Tok.is(tok::colon))
     nextToken();
+  Line->accessLevelMarker.back() = 0;
+  addUnwrappedLine();
   addUnwrappedLine();
+  Line->accessLevelMarker.back() = 1;
 }
 
 bool UnwrappedLineParser::parseEnum() {
@@ -1853,7 +1863,7 @@
       addUnwrappedLine();
 
     parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true,
-               /*MunchSemi=*/false);
+               /*MunchSemi=*/false, /*ClassBlock=*/true);
   }
   // There is no addUnwrappedLine() here so that we fall through to parsing a
   // structural element afterwards. Thus, in "class A {} n, m;",
@@ -2003,6 +2013,7 @@
   });
   CurrentLines->push_back(std::move(*Line));
   Line->Tokens.clear();
+  Line->accessLevelMarker = CurrentLines->back().accessLevelMarker;
   if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) {
     CurrentLines->append(
         std::make_move_iterator(PreprocessorDirectives.begin()),
Index: lib/Format/UnwrappedLineFormatter.cpp
===================================================================
--- lib/Format/UnwrappedLineFormatter.cpp
+++ lib/Format/UnwrappedLineFormatter.cpp
@@ -10,6 +10,7 @@
 #include "UnwrappedLineFormatter.h"
 #include "WhitespaceManager.h"
 #include "llvm/Support/Debug.h"
+#include <numeric>
 #include <queue>
 
 #define DEBUG_TYPE "format-formatter"
@@ -56,11 +57,19 @@
     // having the right size in adjustToUnmodifiedline.
     while (IndentForLevel.size() <= Line.Level)
       IndentForLevel.push_back(-1);
+    unsigned currentLevel = Line.Level;
+    if (Style.AccessModifierStandardIndent) {
+      currentLevel += std::accumulate(std::begin(Line.accessLevelMarker),
+                                      std::end(Line.accessLevelMarker), 0);
+    }
     if (Line.InPPDirective) {
-      Indent = Line.Level * Style.IndentWidth + AdditionalIndent;
+      Indent = currentLevel * Style.IndentWidth + AdditionalIndent;
     } else {
-      IndentForLevel.resize(Line.Level + 1);
-      Indent = getIndent(IndentForLevel, Line.Level);
+      std::size_t oldSize = IndentForLevel.size();
+      IndentForLevel.resize(currentLevel + 1);
+      std::fill(std::begin(IndentForLevel) + oldSize, std::end(IndentForLevel),
+                -1);
+      Indent = getIndent(IndentForLevel, currentLevel);
     }
     if (static_cast<int>(Indent) + Offset >= 0)
       Indent += Offset;
Index: lib/Format/TokenAnnotator.h
===================================================================
--- lib/Format/TokenAnnotator.h
+++ lib/Format/TokenAnnotator.h
@@ -39,7 +39,7 @@
 public:
   AnnotatedLine(const UnwrappedLine &Line)
       : First(Line.Tokens.front().Tok), Level(Line.Level),
-        InPPDirective(Line.InPPDirective),
+        accessLevelMarker(Line.accessLevelMarker), InPPDirective(Line.InPPDirective),
         MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
         IsMultiVariableDeclStmt(false), Affected(false),
         LeadingEmptyLinesAffected(false), ChildrenAffected(false) {
@@ -109,6 +109,7 @@
 
   LineType Type;
   unsigned Level;
+  std::vector<char> accessLevelMarker;
   bool InPPDirective;
   bool MustBeDeclaration;
   bool MightBeFunctionDecl;
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -240,6 +240,8 @@
     }
 
     IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
+    IO.mapOptional("AccessModifierStandardIndent",
+                   Style.AccessModifierStandardIndent);
     IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket);
     IO.mapOptional("AlignConsecutiveAssignments",
                    Style.AlignConsecutiveAssignments);
@@ -487,6 +489,7 @@
   FormatStyle LLVMStyle;
   LLVMStyle.Language = FormatStyle::LK_Cpp;
   LLVMStyle.AccessModifierOffset = -2;
+  LLVMStyle.AccessModifierStandardIndent = false;
   LLVMStyle.AlignEscapedNewlinesLeft = false;
   LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
   LLVMStyle.AlignOperands = true;
@@ -1213,9 +1216,9 @@
 // necessary replacement to 'Replaces'. 'Includes' must be in strict source
 // order.
 static void sortCppIncludes(const FormatStyle &Style,
-                         const SmallVectorImpl<IncludeDirective> &Includes,
-                         ArrayRef<tooling::Range> Ranges, StringRef FileName,
-                         tooling::Replacements &Replaces, unsigned *Cursor) {
+                            const SmallVectorImpl<IncludeDirective> &Includes,
+                            ArrayRef<tooling::Range> Ranges, StringRef FileName,
+                            tooling::Replacements &Replaces, unsigned *Cursor) {
   if (!affectsRange(Ranges, Includes.front().Offset,
                     Includes.back().Offset + Includes.back().Text.size()))
     return;
Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -46,6 +46,7 @@
 struct FormatStyle {
   /// \brief The extra indent or outdent of access modifiers, e.g. ``public:``.
   int AccessModifierOffset;
+  bool AccessModifierStandardIndent;
 
   /// \brief Different styles for aligning after open brackets.
   enum BracketAlignmentStyle {
@@ -632,6 +633,7 @@
 
   bool operator==(const FormatStyle &R) const {
     return AccessModifierOffset == R.AccessModifierOffset &&
+           AccessModifierStandardIndent == R.AccessModifierStandardIndent &&
            AlignAfterOpenBracket == R.AlignAfterOpenBracket &&
            AlignConsecutiveAssignments == R.AlignConsecutiveAssignments &&
            AlignConsecutiveDeclarations == R.AlignConsecutiveDeclarations &&
Index: docs/ClangFormatStyleOptions.rst
===================================================================
--- docs/ClangFormatStyleOptions.rst
+++ docs/ClangFormatStyleOptions.rst
@@ -150,6 +150,9 @@
 **AccessModifierOffset** (``int``)
   The extra indent or outdent of access modifiers, e.g. ``public:``.
 
+**AccessModifierStandardIndent** (``bool``)
+  Indent accesses modifier in the normal method.
+
 **AlignAfterOpenBracket** (``BracketAlignmentStyle``)
   If ``true``, horizontally aligns arguments after an open bracket.
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to