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:``. +**AdditionalIndentClassBlock** (``bool``) + If ``true``, adds an additional level of indention for class blocks. + **AlignAfterOpenBracket** (``BracketAlignmentStyle``) If ``true``, horizontally aligns arguments after an open bracket. Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -49,6 +49,9 @@ /// The extra indent or outdent of access modifiers, e.g. ``public:``. int AccessModifierOffset; + /// If ``true``, adds an additional level of indention for class blocks + bool AdditionalIndentClassBlock; + /// Different styles for aligning after open brackets. enum BracketAlignmentStyle { /// Align parameters on the open bracket, e.g.: @@ -1673,7 +1676,8 @@ UseTabStyle UseTab; bool operator==(const FormatStyle &R) const { - return AccessModifierOffset == R.AccessModifierOffset && + return AdditionalIndentClassBlock == R.AdditionalIndentClassBlock && + AccessModifierOffset == R.AccessModifierOffset && AlignAfterOpenBracket == R.AlignAfterOpenBracket && AlignConsecutiveAssignments == R.AlignConsecutiveAssignments && AlignConsecutiveDeclarations == R.AlignConsecutiveDeclarations && Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -313,6 +313,7 @@ } IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset); + IO.mapOptional("AdditionalIndentClassBlock", Style.AdditionalIndentClassBlock); IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket); IO.mapOptional("AlignConsecutiveAssignments", Style.AlignConsecutiveAssignments); @@ -621,6 +622,7 @@ FormatStyle LLVMStyle; LLVMStyle.Language = FormatStyle::LK_Cpp; LLVMStyle.AccessModifierOffset = -2; + LLVMStyle.AdditionalIndentClassBlock = false; LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right; LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align; LLVMStyle.AlignOperands = true; Index: lib/Format/UnwrappedLineParser.h =================================================================== --- lib/Format/UnwrappedLineParser.h +++ lib/Format/UnwrappedLineParser.h @@ -88,7 +88,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(); Index: lib/Format/UnwrappedLineParser.cpp =================================================================== --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -520,7 +520,7 @@ } 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); @@ -546,6 +546,9 @@ MustBeDeclaration); if (AddLevel) ++Line->Level; + + if (Style.AdditionalIndentClassBlock && ClassBlock) + ++Line->Level; parseLevel(/*HasOpeningBrace=*/true); if (eof()) @@ -2126,7 +2129,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 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 + FormatTestClassIndent.cpp FormatTestComments.cpp FormatTestJS.cpp FormatTestJava.cpp Index: unittests/Format/FormatTestClassIndent.cpp =================================================================== --- /dev/null +++ unittests/Format/FormatTestClassIndent.cpp @@ -0,0 +1,144 @@ +//===- 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 FormatTestClassIndent : public ::testing::Test { +protected: + std::string format(llvm::StringRef Code, const FormatStyle &Style) { + LLVM_DEBUG(llvm::errs() << "---\n"); + LLVM_DEBUG(llvm::errs() << Code << "\n\n"); + std::vector Ranges(1, tooling::Range(0, Code.size())); + bool IncompleteFormat = false; + tooling::Replacements Replaces = + reformat(Style, Code, Ranges, "", &IncompleteFormat); + EXPECT_FALSE(IncompleteFormat) << Code << "\n\n"; + auto Result = applyAllReplacements(Code, Replaces); + EXPECT_TRUE(static_cast(Result)); + LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); + return *Result; + } + + FormatStyle getStyleWithAdditionalIndent() { + FormatStyle Style = getLLVMStyle(); + Style.AdditionalIndentClassBlock = true; + return Style; + } + + void verifyFormat(llvm::StringRef Code, const FormatStyle & Style = getLLVMStyle()) { + EXPECT_EQ(Code.str(), format(test::messUp(Code), Style)); + } +}; + +TEST_F(FormatTestClassIndent, NoChangeWithoutAccess) { + verifyFormat("class A {\n" + " int a1;\n" + "};"); + verifyFormat("class B {\n" + " int b1;\n" + "};", + getStyleWithAdditionalIndent()); +} + +TEST_F(FormatTestClassIndent, ChangeWithAccess) { + verifyFormat("class C {\n" + " int c1;\n" + "public:\n" + " int c2;\n" + "};"); + verifyFormat("class D {\n" + " int d1;\n" + " public:\n" + " int d2;\n" + "};", + getStyleWithAdditionalIndent()); +} + +TEST_F(FormatTestClassIndent, MultipleAccessLevels) { + verifyFormat("class E {\n" + " int e1;\n" + "public:\n" + " int e2;\n" + "private:\n" + " int e3;\n" + "protected:\n" + " int e4;\n" + "};"); + verifyFormat("class F {\n" + " int f1;\n" + " public:\n" + " int f2;\n" + " private:\n" + " int f3;\n" + " protected:\n" + " int f4;\n" + "};", + getStyleWithAdditionalIndent()); +} + +TEST_F(FormatTestClassIndent, 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" + "};"); + 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" + "};", + getStyleWithAdditionalIndent()); +} + +} // end namespace +} // end namespace format +} // end namespace clang