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:``. 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 T foo() { - /// } - /// template T foo(int aaaaaaaaaaaaaaaaaaaaa, - /// int bbbbbbbbbbbbbbbbbbbbb) { - /// } - /// \endcode - BTDS_No, - /// Force break after template declaration only when the following - /// declaration spans multiple lines. - /// \code - /// template T foo() { - /// } - /// template - /// T foo(int aaaaaaaaaaaaaaaaaaaaa, - /// int bbbbbbbbbbbbbbbbbbbbb) { - /// } - /// \endcode - BTDS_MultiLine, - /// Always break after template declaration. - /// \code - /// template - /// T foo() { - /// } - /// template - /// T foo(int aaaaaaaaaaaaaaaaaaaaa, - /// int bbbbbbbbbbbbbbbbbbbbb) { - /// } - /// \endcode - BTDS_Yes + /// Do not force break before declaration. + /// ``PenaltyBreakTemplateDeclaration`` is taken into account. + /// \code + /// template T foo() { + /// } + /// template T foo(int aaaaaaaaaaaaaaaaaaaaa, + /// int bbbbbbbbbbbbbbbbbbbbb) { + /// } + /// \endcode + BTDS_No, + /// Force break after template declaration only when the following + /// declaration spans multiple lines. + /// \code + /// template T foo() { + /// } + /// template + /// T foo(int aaaaaaaaaaaaaaaaaaaaa, + /// int bbbbbbbbbbbbbbbbbbbbb) { + /// } + /// \endcode + BTDS_MultiLine, + /// Always break after template declaration. + /// \code + /// template + /// T foo() { + /// } + /// template + /// 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/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/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/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);