https://github.com/noambouillet updated https://github.com/llvm/llvm-project/pull/227704
>From f55190042b1ba98c2946eb94e468cc4899718a38 Mon Sep 17 00:00:00 2001 From: Noam Bouillet <[email protected]> Date: Wed, 30 Sep 2026 14:07:44 +0200 Subject: [PATCH 1/5] feat(format): make implicit access indent optional Preserve existing output by default while allowing records without an explicit access label to use one indentation level. Refs #61631 --- clang/docs/ClangFormatStyleOptions.md | 17 +++++-- clang/docs/ReleaseNotes.md | 4 ++ clang/include/clang/Format/Format.h | 16 +++++-- clang/lib/Format/Format.cpp | 3 ++ clang/lib/Format/UnwrappedLineParser.cpp | 47 ++++++++++++++----- clang/lib/Format/UnwrappedLineParser.h | 6 ++- clang/unittests/Format/ConfigParseTest.cpp | 1 + clang/unittests/Format/FormatTest.cpp | 53 ++++++++++++++++++++++ clang/unittests/Format/FormatTestJava.cpp | 12 +++++ 9 files changed, 140 insertions(+), 19 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.md b/clang/docs/ClangFormatStyleOptions.md index 81984ff185e53..d831bcac07c9c 100644 --- a/clang/docs/ClangFormatStyleOptions.md +++ b/clang/docs/ClangFormatStyleOptions.md @@ -4752,9 +4752,10 @@ the configuration (without a prefix: `Auto`). the record members, respecting the `AccessModifierOffset`. Record members are indented one level below the record. When `true`, access modifiers get their own indentation level. As a - consequence, record members are always indented 2 levels below the record, - regardless of the access modifier presence. Value of the - `AccessModifierOffset` is ignored. + consequence, record members are by default indented 2 levels below the + record, regardless of the access modifier presence. Value of the + `AccessModifierOffset` is ignored. `IndentImplicitAccessModifiers` can + change the indentation before the first explicit access modifier. ```c++ false: true: @@ -4952,6 +4953,16 @@ the configuration (without a prefix: `Auto`). +(indentimplicitaccessmodifiers)= + +**IndentImplicitAccessModifiers** (`Boolean`) {versionbadge}`clang-format 24` {ref}`¶ <IndentImplicitAccessModifiers>` + +: When `IndentAccessModifiers` is `true`, indent members before the first + explicit access modifier by two levels. Set this option to `false` to + indent those members by one level. Members after an explicit access + modifier still use two levels. This option has no effect if + `IndentAccessModifiers` is false. + (indentppdirectives)= **IndentPPDirectives** (`PPDirectiveIndentStyle`) {versionbadge}`clang-format 6` {ref}`¶ <IndentPPDirectives>` diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index c778703e8cc6f..a2090bb98df30 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -944,6 +944,10 @@ features cannot lower the translation-unit ABI level; ### clang-format +- Add `IndentImplicitAccessModifiers` to allow members before the first + explicit access modifier to use one indentation level when + `IndentAccessModifiers` is enabled. The default preserves existing formatting. + - Add `SpacesInBlockComments` option to control spacing after `/*` and before `*/` in ordinary block comments. - Add `AfterRequiresExpression` sub-option of `BraceWrapping` to wrap the diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 6d4fa6e8ee2a7..40ae52a0148e8 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3187,9 +3187,10 @@ struct FormatStyle { /// the record members, respecting the `AccessModifierOffset`. Record /// members are indented one level below the record. /// When `true`, access modifiers get their own indentation level. As a - /// consequence, record members are always indented 2 levels below the record, - /// regardless of the access modifier presence. Value of the - /// `AccessModifierOffset` is ignored. + /// consequence, record members are by default indented 2 levels below the + /// record, regardless of the access modifier presence. Value of the + /// `AccessModifierOffset` is ignored. `IndentImplicitAccessModifiers` can + /// change the indentation before the first explicit access modifier. /// \code /// false: true: /// class C { vs. class C { @@ -3208,6 +3209,14 @@ struct FormatStyle { /// \version 13 bool IndentAccessModifiers; + /// When `IndentAccessModifiers` is `true`, indent members before the first + /// explicit access modifier by two levels. Set this option to `false` to + /// indent those members by one level. Members after an explicit access + /// modifier still use two levels. This option has no effect if + /// `IndentAccessModifiers` is false. + /// \version 24 + bool IndentImplicitAccessModifiers; + /// Indent case label blocks one level from the case label. /// /// When `false`, the block following the case label uses the same @@ -6242,6 +6251,7 @@ struct FormatStyle { R.IncludeStyle.IncludeIsMainSourceRegex && IncludeStyle.MainIncludeChar == R.IncludeStyle.MainIncludeChar && IndentAccessModifiers == R.IndentAccessModifiers && + IndentImplicitAccessModifiers == R.IndentImplicitAccessModifiers && IndentCaseBlocks == R.IndentCaseBlocks && IndentCaseLabels == R.IndentCaseLabels && IndentExportBlock == R.IndentExportBlock && diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 4c78c1dbe9f80..2f6d70d2bf4e2 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1399,6 +1399,8 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("IncludeIsMainSourceRegex", Style.IncludeStyle.IncludeIsMainSourceRegex); IO.mapOptional("IndentAccessModifiers", Style.IndentAccessModifiers); + IO.mapOptional("IndentImplicitAccessModifiers", + Style.IndentImplicitAccessModifiers); IO.mapOptional("IndentCaseBlocks", Style.IndentCaseBlocks); IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); IO.mapOptional("IndentExportBlock", Style.IndentExportBlock); @@ -1977,6 +1979,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.IncludeStyle.IncludeIsMainRegex = "(Test)?$"; LLVMStyle.IncludeStyle.MainIncludeChar = tooling::IncludeStyle::MICD_Quote; LLVMStyle.IndentAccessModifiers = false; + LLVMStyle.IndentImplicitAccessModifiers = true; LLVMStyle.IndentCaseBlocks = false; LLVMStyle.IndentCaseLabels = false; LLVMStyle.IndentExportBlock = true; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 4825e825af1fa..0e0825112b513 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -352,7 +352,8 @@ bool UnwrappedLineParser::precededByCommentOrPPDirective() const { /// (A simple block has a single statement.) bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, IfStmtKind *IfKind, - FormatToken **IfLeftBrace) { + FormatToken **IfLeftBrace, + bool *SeenExplicitAccessModifier) { const bool InRequiresExpression = OpeningBrace && OpeningBrace->is(TT_RequiresExpressionLBrace); const bool IsPrecededByCommentOrPPDirective = @@ -377,7 +378,18 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, Kind = tok::r_brace; auto ParseDefault = [this, OpeningBrace, IfKind, &IfLBrace, &HasDoWhile, - &HasLabel, &StatementCount] { + &HasLabel, &StatementCount, + SeenExplicitAccessModifier] { + const bool IsQtAccessLabel = + SeenExplicitAccessModifier && !*SeenExplicitAccessModifier && + FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals, + Keywords.kw_slots, Keywords.kw_qslots) && + Tokens->peekNextToken(/*SkipComment=*/true)->is(tok::colon); + if (SeenExplicitAccessModifier && !*SeenExplicitAccessModifier && + (FormatTok->isAccessSpecifierKeyword() || IsQtAccessLabel)) { + ++Line->Level; + *SeenExplicitAccessModifier = true; + } parseStructuralElement(OpeningBrace, IfKind, &IfLBrace, HasDoWhile ? nullptr : &HasDoWhile, HasLabel ? nullptr : &HasLabel); @@ -744,11 +756,10 @@ bool UnwrappedLineParser::mightFitOnOneLine( return Line.Level * Style.IndentWidth + Length <= ColumnLimit; } -FormatToken *UnwrappedLineParser::parseBlock(bool MustBeDeclaration, - unsigned AddLevels, bool MunchSemi, - bool KeepBraces, - IfStmtKind *IfKind, - bool UnindentWhitesmithsBraces) { +FormatToken *UnwrappedLineParser::parseBlock( + bool MustBeDeclaration, unsigned AddLevels, bool MunchSemi, bool KeepBraces, + IfStmtKind *IfKind, bool UnindentWhitesmithsBraces, + bool IndentAfterExplicitAccessModifier) { auto HandleVerilogBlockLabel = [this]() { // ":" name if (Style.isVerilog() && FormatTok->is(tok::colon)) { @@ -820,7 +831,11 @@ FormatToken *UnwrappedLineParser::parseBlock(bool MustBeDeclaration, Line->Level += AddLevels - (IsWhitesmiths ? 1 : 0); FormatToken *IfLBrace = nullptr; - const bool SimpleBlock = parseLevel(Tok, IfKind, &IfLBrace); + bool SeenExplicitAccessModifier = false; + const bool SimpleBlock = + parseLevel(Tok, IfKind, &IfLBrace, + IndentAfterExplicitAccessModifier ? &SeenExplicitAccessModifier + : nullptr); if (eof()) return IfLBrace; @@ -879,7 +894,8 @@ FormatToken *UnwrappedLineParser::parseBlock(bool MustBeDeclaration, size_t PPEndHash = computePPHash(); // Munch the closing brace. - nextToken(/*LevelDifference=*/-AddLevels); + nextToken(/*LevelDifference=*/ + -static_cast<int>(AddLevels + SeenExplicitAccessModifier)); // When this is a function block and there is an unnecessary semicolon // afterwards then mark it as optional (so the RemoveSemi pass can get rid of @@ -4298,8 +4314,17 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, bool IsJavaRecord) { addUnwrappedLine(); } - unsigned AddLevels = Style.IndentAccessModifiers ? 2u : 1u; - parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/false); + const bool IndentAfterExplicitAccessModifier = + Style.isCpp() && Style.IndentAccessModifiers && + !Style.IndentImplicitAccessModifiers; + unsigned AddLevels = + Style.IndentAccessModifiers && !IndentAfterExplicitAccessModifier + ? 2u + : 1u; + parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/false, + /*KeepBraces=*/true, /*IfKind=*/nullptr, + /*UnindentWhitesmithsBraces=*/false, + IndentAfterExplicitAccessModifier); } setPreviousRBraceType(ClosingBraceType); } diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index 5b93c8f346d75..2e1755ad3b2c6 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -126,13 +126,15 @@ class UnwrappedLineParser { bool precededByCommentOrPPDirective() const; bool parseLevel(const FormatToken *OpeningBrace = nullptr, IfStmtKind *IfKind = nullptr, - FormatToken **IfLeftBrace = nullptr); + FormatToken **IfLeftBrace = nullptr, + bool *SeenExplicitAccessModifier = nullptr); bool mightFitOnOneLine(UnwrappedLine &Line, const FormatToken *OpeningBrace = nullptr) const; FormatToken *parseBlock(bool MustBeDeclaration = false, unsigned AddLevels = 1u, bool MunchSemi = true, bool KeepBraces = true, IfStmtKind *IfKind = nullptr, - bool UnindentWhitesmithsBraces = false); + bool UnindentWhitesmithsBraces = false, + bool IndentAfterExplicitAccessModifier = false); void parseChildBlock(); void parsePPDirective(); void parsePPDefine(); diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index 86511edb9d40d..ccbc346901460 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -190,6 +190,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding"); CHECK_PARSE_BOOL(DisableFormat); CHECK_PARSE_BOOL(IndentAccessModifiers); + CHECK_PARSE_BOOL(IndentImplicitAccessModifiers); CHECK_PARSE_BOOL(IndentCaseBlocks); CHECK_PARSE_BOOL(IndentCaseLabels); CHECK_PARSE_BOOL(IndentExportBlock); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index bb630da34d7d9..656a352ecb005 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -24920,6 +24920,59 @@ TEST_F(FormatTest, IndentAccessModifiers) { Style); } +TEST_F(FormatTest, IndentImplicitAccessModifiers) { + FormatStyle Style = getLLVMStyle(); + Style.IndentAccessModifiers = true; + Style.IndentImplicitAccessModifiers = false; + Style.IndentWidth = 4; + Style.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_Never; + Style.BreakBeforeBraces = FormatStyle::BS_Allman; + + verifyFormat("class Outer\n" + "{\n" + " public:\n" + " struct Inner\n" + " {\n" + " bool first;\n" + " bool second;\n" + " };\n" + "};", + Style); + verifyFormat("struct S\n" + "{\n" + " int before;\n" + " private:\n" + " int after;\n" + "};", + Style); + verifyFormat("union U\n" + "{\n" + " int first;\n" + " class Inner\n" + " {\n" + " public:\n" + " int member;\n" + " };\n" + " int last;\n" + "};", + Style); + verifyFormat("class QtObject\n" + "{\n" + " signals:\n" + " void changed();\n" + "};", + Style); + + Style.BreakBeforeBraces = FormatStyle::BS_Whitesmiths; + verifyFormat("struct S\n" + " {\n" + " int before;\n" + " public:\n" + " int after;\n" + " };", + Style); +} + TEST_F(FormatTest, LimitlessStringsAndComments) { auto Style = getLLVMStyleWithColumns(0); constexpr StringRef Code( diff --git a/clang/unittests/Format/FormatTestJava.cpp b/clang/unittests/Format/FormatTestJava.cpp index a11fce963d820..86e4b2fc361b2 100644 --- a/clang/unittests/Format/FormatTestJava.cpp +++ b/clang/unittests/Format/FormatTestJava.cpp @@ -28,6 +28,18 @@ class FormatTestJava : public test::FormatTestBase { } }; +TEST_F(FormatTestJava, IndentImplicitAccessModifiersDoesNotAffectJava) { + FormatStyle Style = getDefaultStyle(); + Style.IndentWidth = 4; + Style.IndentAccessModifiers = true; + Style.IndentImplicitAccessModifiers = false; + verifyFormat("class C {\n" + " int before;\n" + " public int after;\n" + "}", + Style); +} + TEST_F(FormatTestJava, NoAlternativeOperatorNames) { verifyFormat("someObject.and();"); } >From beb4dc8d614e0d71afcd45298dbbbe7dd1857e63 Mon Sep 17 00:00:00 2001 From: Noam Bouillet <[email protected]> Date: Thu, 1 Oct 2026 18:15:19 +0200 Subject: [PATCH 2/5] refactor(format): use enum for access indent Preserve existing YAML true/false values while replacing the added boolean with a three-mode enum. C++ FormatStyle callers must use enum values instead of bool assignments. Refs #61631 --- clang/docs/ClangFormatStyleOptions.md | 69 ++++++++++++++------- clang/docs/ReleaseNotes.md | 7 +-- clang/include/clang/Format/Format.h | 61 +++++++++++------- clang/lib/Format/Format.cpp | 18 ++++-- clang/lib/Format/UnwrappedLineFormatter.cpp | 5 +- clang/lib/Format/UnwrappedLineParser.cpp | 43 ++++++++----- clang/unittests/Format/ConfigParseTest.cpp | 15 ++++- clang/unittests/Format/FormatTest.cpp | 46 ++++++++++++-- clang/unittests/Format/FormatTestCSharp.cpp | 11 ++++ clang/unittests/Format/FormatTestJava.cpp | 5 +- 10 files changed, 200 insertions(+), 80 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.md b/clang/docs/ClangFormatStyleOptions.md index d831bcac07c9c..5aabda184da0f 100644 --- a/clang/docs/ClangFormatStyleOptions.md +++ b/clang/docs/ClangFormatStyleOptions.md @@ -4744,21 +4744,24 @@ the configuration (without a prefix: `Auto`). (indentaccessmodifiers)= -**IndentAccessModifiers** (`Boolean`) {versionbadge}`clang-format 13` {ref}`¶ <IndentAccessModifiers>` - -: Specify whether access modifiers should have their own indentation level. - - When `false`, access modifiers are indented (or outdented) relative to - the record members, respecting the `AccessModifierOffset`. Record - members are indented one level below the record. - When `true`, access modifiers get their own indentation level. As a - consequence, record members are by default indented 2 levels below the - record, regardless of the access modifier presence. Value of the - `AccessModifierOffset` is ignored. `IndentImplicitAccessModifiers` can - change the indentation before the first explicit access modifier. +**IndentAccessModifiers** (`IndentAccessModifierStyle`) {versionbadge}`clang-format 13` {ref}`¶ <IndentAccessModifiers>` + +: Specify how access modifiers and record members are indented. + + `Never` (also `false` in configuration) uses `AccessModifierOffset` for + access modifiers and indents members one level below the record. `Always` + (also `true` in configuration) gives access modifiers their own + indentation level and indents all members two levels below the record, + even if there is no explicit access modifier. + `AfterFirstAccessModifier` gives members one level before the first + explicit access modifier and two levels afterwards. If there is no + explicit access modifier, members stay at one level. This behavior applies + to C, C++, and Objective-C; other languages treat it like `Always`. + `AccessModifierOffset` is ignored by `Always` and + `AfterFirstAccessModifier`. ```c++ - false: true: + Never (false): Always (true): class C { vs. class C { class D { class D { void bar(); void bar(); @@ -4773,6 +4776,36 @@ the configuration (without a prefix: `Auto`). } } ``` + ```yaml + IndentAccessModifiers: AfterFirstAccessModifier + ``` + + ```c++ + struct S { + int before; + + public: + int after; + }; + ``` + + Possible values: + + - `IAMS_Never` (in configuration: `Never`) + Use `AccessModifierOffset` for access modifiers and indent members one + level below the record. + + - `IAMS_Always` (in configuration: `Always`) + Give access modifiers their own indentation level and indent all + members two levels below the record. + + - `IAMS_AfterFirstAccessModifier` (in configuration: `AfterFirstAccessModifier`) + In C, C++, and Objective-C, indent members one level until the first + explicit access modifier, then two levels. Other languages use the + `Always` behavior. Available since clang-format 24. + + + (indentcaseblocks)= **IndentCaseBlocks** (`Boolean`) {versionbadge}`clang-format 11` {ref}`¶ <IndentCaseBlocks>` @@ -4953,16 +4986,6 @@ the configuration (without a prefix: `Auto`). -(indentimplicitaccessmodifiers)= - -**IndentImplicitAccessModifiers** (`Boolean`) {versionbadge}`clang-format 24` {ref}`¶ <IndentImplicitAccessModifiers>` - -: When `IndentAccessModifiers` is `true`, indent members before the first - explicit access modifier by two levels. Set this option to `false` to - indent those members by one level. Members after an explicit access - modifier still use two levels. This option has no effect if - `IndentAccessModifiers` is false. - (indentppdirectives)= **IndentPPDirectives** (`PPDirectiveIndentStyle`) {versionbadge}`clang-format 6` {ref}`¶ <IndentPPDirectives>` diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index a2090bb98df30..edbdf4f5dd31b 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -944,10 +944,6 @@ features cannot lower the translation-unit ABI level; ### clang-format -- Add `IndentImplicitAccessModifiers` to allow members before the first - explicit access modifier to use one indentation level when - `IndentAccessModifiers` is enabled. The default preserves existing formatting. - - Add `SpacesInBlockComments` option to control spacing after `/*` and before `*/` in ordinary block comments. - Add `AfterRequiresExpression` sub-option of `BraceWrapping` to wrap the @@ -957,6 +953,9 @@ features cannot lower the translation-unit ABI level; - `QualifierOrder` now supports `typedef`, `consteval`, `constinit`, `thread_local`, `extern`, `mutable`, `signed`, `unsigned`, `long`, `short`, and `explicit` declaration specifiers. +- Extend `IndentAccessModifiers` with `AfterFirstAccessModifier` to indent + members before the first explicit access modifier by one level. Existing + configuration values `true` and `false` remain supported. ### libclang diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 40ae52a0148e8..e6c8aa1f90604 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3181,18 +3181,35 @@ struct FormatStyle { /// \version 13 std::vector<std::string> IfMacros; - /// Specify whether access modifiers should have their own indentation level. - /// - /// When `false`, access modifiers are indented (or outdented) relative to - /// the record members, respecting the `AccessModifierOffset`. Record - /// members are indented one level below the record. - /// When `true`, access modifiers get their own indentation level. As a - /// consequence, record members are by default indented 2 levels below the - /// record, regardless of the access modifier presence. Value of the - /// `AccessModifierOffset` is ignored. `IndentImplicitAccessModifiers` can - /// change the indentation before the first explicit access modifier. + /// Modes for indenting access modifiers and record members. + enum IndentAccessModifierStyle : int8_t { + /// Use `AccessModifierOffset` for access modifiers and indent members one + /// level below the record. + IAMS_Never, + /// Give access modifiers their own indentation level and indent all + /// members two levels below the record. + IAMS_Always, + /// In C, C++, and Objective-C, indent members one level until the first + /// explicit access modifier, then two levels. Other languages use the + /// `Always` behavior. Available since clang-format 24. + IAMS_AfterFirstAccessModifier, + }; + + /// Specify how access modifiers and record members are indented. + /// + /// `Never` (also `false` in configuration) uses `AccessModifierOffset` for + /// access modifiers and indents members one level below the record. `Always` + /// (also `true` in configuration) gives access modifiers their own + /// indentation level and indents all members two levels below the record, + /// even if there is no explicit access modifier. + /// `AfterFirstAccessModifier` gives members one level before the first + /// explicit access modifier and two levels afterwards. If there is no + /// explicit access modifier, members stay at one level. This behavior applies + /// to C, C++, and Objective-C; other languages treat it like `Always`. + /// `AccessModifierOffset` is ignored by `Always` and + /// `AfterFirstAccessModifier`. /// \code - /// false: true: + /// Never (false): Always (true): /// class C { vs. class C { /// class D { class D { /// void bar(); void bar(); @@ -3206,16 +3223,19 @@ struct FormatStyle { /// return 1; return 1; /// } } /// \endcode + /// \code{.yaml} + /// IndentAccessModifiers: AfterFirstAccessModifier + /// \endcode + /// \code + /// struct S { + /// int before; + /// + /// public: + /// int after; + /// }; + /// \endcode /// \version 13 - bool IndentAccessModifiers; - - /// When `IndentAccessModifiers` is `true`, indent members before the first - /// explicit access modifier by two levels. Set this option to `false` to - /// indent those members by one level. Members after an explicit access - /// modifier still use two levels. This option has no effect if - /// `IndentAccessModifiers` is false. - /// \version 24 - bool IndentImplicitAccessModifiers; + IndentAccessModifierStyle IndentAccessModifiers; /// Indent case label blocks one level from the case label. /// @@ -6251,7 +6271,6 @@ struct FormatStyle { R.IncludeStyle.IncludeIsMainSourceRegex && IncludeStyle.MainIncludeChar == R.IncludeStyle.MainIncludeChar && IndentAccessModifiers == R.IndentAccessModifiers && - IndentImplicitAccessModifiers == R.IndentImplicitAccessModifiers && IndentCaseBlocks == R.IndentCaseBlocks && IndentCaseLabels == R.IndentCaseLabels && IndentExportBlock == R.IndentExportBlock && diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 2f6d70d2bf4e2..bdb15326a1603 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -477,6 +477,19 @@ struct ScalarEnumerationTraits<FormatStyle::EnumTrailingCommaStyle> { } }; +template <> +struct ScalarEnumerationTraits<FormatStyle::IndentAccessModifierStyle> { + static void enumeration(IO &IO, + FormatStyle::IndentAccessModifierStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::IAMS_Never); + IO.enumCase(Value, "Always", FormatStyle::IAMS_Always); + IO.enumCase(Value, "AfterFirstAccessModifier", + FormatStyle::IAMS_AfterFirstAccessModifier); + IO.enumCase(Value, "false", FormatStyle::IAMS_Never); + IO.enumCase(Value, "true", FormatStyle::IAMS_Always); + } +}; + template <> struct ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> { static void enumeration(IO &IO, FormatStyle::IndentExternBlockStyle &Value) { @@ -1399,8 +1412,6 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("IncludeIsMainSourceRegex", Style.IncludeStyle.IncludeIsMainSourceRegex); IO.mapOptional("IndentAccessModifiers", Style.IndentAccessModifiers); - IO.mapOptional("IndentImplicitAccessModifiers", - Style.IndentImplicitAccessModifiers); IO.mapOptional("IndentCaseBlocks", Style.IndentCaseBlocks); IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); IO.mapOptional("IndentExportBlock", Style.IndentExportBlock); @@ -1978,8 +1989,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { {".*", 1, 0, false}}; LLVMStyle.IncludeStyle.IncludeIsMainRegex = "(Test)?$"; LLVMStyle.IncludeStyle.MainIncludeChar = tooling::IncludeStyle::MICD_Quote; - LLVMStyle.IndentAccessModifiers = false; - LLVMStyle.IndentImplicitAccessModifiers = true; + LLVMStyle.IndentAccessModifiers = FormatStyle::IAMS_Never; LLVMStyle.IndentCaseBlocks = false; LLVMStyle.IndentCaseLabels = false; LLVMStyle.IndentExportBlock = true; diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index f005f228328ce..4d27ddde33ff0 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -136,8 +136,9 @@ class LevelIndentTracker { // The AccessModifierOffset may be overridden by IndentAccessModifiers, // in which case we take a negative value of the IndentWidth to simulate // the upper indent level. - return Style.IndentAccessModifiers ? -Style.IndentWidth - : Style.AccessModifierOffset; + return Style.IndentAccessModifiers != FormatStyle::IAMS_Never + ? -Style.IndentWidth + : Style.AccessModifierOffset; } return 0; } diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 0e0825112b513..11c70db50435e 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -380,15 +380,15 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, auto ParseDefault = [this, OpeningBrace, IfKind, &IfLBrace, &HasDoWhile, &HasLabel, &StatementCount, SeenExplicitAccessModifier] { - const bool IsQtAccessLabel = - SeenExplicitAccessModifier && !*SeenExplicitAccessModifier && - FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals, - Keywords.kw_slots, Keywords.kw_qslots) && - Tokens->peekNextToken(/*SkipComment=*/true)->is(tok::colon); - if (SeenExplicitAccessModifier && !*SeenExplicitAccessModifier && - (FormatTok->isAccessSpecifierKeyword() || IsQtAccessLabel)) { - ++Line->Level; - *SeenExplicitAccessModifier = true; + if (SeenExplicitAccessModifier && !*SeenExplicitAccessModifier) { + const bool IsQtAccessLabel = + FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals, + Keywords.kw_slots, Keywords.kw_qslots) && + Tokens->peekNextToken(/*SkipComment=*/true)->is(tok::colon); + if (FormatTok->isAccessSpecifierKeyword() || IsQtAccessLabel) { + ++Line->Level; + *SeenExplicitAccessModifier = true; + } } parseStructuralElement(OpeningBrace, IfKind, &IfLBrace, HasDoWhile ? nullptr : &HasDoWhile, @@ -894,8 +894,9 @@ FormatToken *UnwrappedLineParser::parseBlock( size_t PPEndHash = computePPHash(); // Munch the closing brace. - nextToken(/*LevelDifference=*/ - -static_cast<int>(AddLevels + SeenExplicitAccessModifier)); + if (SeenExplicitAccessModifier) + ++AddLevels; + nextToken(/*LevelDifference=*/-static_cast<int>(AddLevels)); // When this is a function block and there is an unnecessary semicolon // afterwards then mark it as optional (so the RemoveSemi pass can get rid of @@ -4315,12 +4316,20 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, bool IsJavaRecord) { } const bool IndentAfterExplicitAccessModifier = - Style.isCpp() && Style.IndentAccessModifiers && - !Style.IndentImplicitAccessModifiers; - unsigned AddLevels = - Style.IndentAccessModifiers && !IndentAfterExplicitAccessModifier - ? 2u - : 1u; + Style.isCpp() && Style.IndentAccessModifiers == + FormatStyle::IAMS_AfterFirstAccessModifier; + unsigned AddLevels = 1u; + switch (Style.IndentAccessModifiers) { + case FormatStyle::IAMS_Never: + break; + case FormatStyle::IAMS_Always: + AddLevels = 2u; + break; + case FormatStyle::IAMS_AfterFirstAccessModifier: + // Other languages keep the indentation of the old true setting. + AddLevels = IndentAfterExplicitAccessModifier ? 1u : 2u; + break; + } parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/false, /*KeepBraces=*/true, /*IfKind=*/nullptr, /*UnindentWhitesmithsBraces=*/false, diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index ccbc346901460..c0afbfab9ede2 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -189,8 +189,6 @@ TEST(ConfigParseTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL(DerivePointerAlignment); CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding"); CHECK_PARSE_BOOL(DisableFormat); - CHECK_PARSE_BOOL(IndentAccessModifiers); - CHECK_PARSE_BOOL(IndentImplicitAccessModifiers); CHECK_PARSE_BOOL(IndentCaseBlocks); CHECK_PARSE_BOOL(IndentCaseLabels); CHECK_PARSE_BOOL(IndentExportBlock); @@ -1030,6 +1028,19 @@ TEST(ConfigParseTest, ParsesConfiguration) { AllowShortIfStatementsOnASingleLine, FormatStyle::SIS_WithoutElse); + Style.IndentAccessModifiers = FormatStyle::IAMS_Always; + CHECK_PARSE("IndentAccessModifiers: Never", IndentAccessModifiers, + FormatStyle::IAMS_Never); + CHECK_PARSE("IndentAccessModifiers: Always", IndentAccessModifiers, + FormatStyle::IAMS_Always); + CHECK_PARSE("IndentAccessModifiers: AfterFirstAccessModifier", + IndentAccessModifiers, + FormatStyle::IAMS_AfterFirstAccessModifier); + CHECK_PARSE("IndentAccessModifiers: false", IndentAccessModifiers, + FormatStyle::IAMS_Never); + CHECK_PARSE("IndentAccessModifiers: true", IndentAccessModifiers, + FormatStyle::IAMS_Always); + Style.IndentExternBlock = FormatStyle::IEBS_NoIndent; CHECK_PARSE("IndentExternBlock: AfterExternBlock", IndentExternBlock, FormatStyle::IEBS_AfterExternBlock); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 656a352ecb005..e2bb45a7e67d4 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -24839,7 +24839,7 @@ TEST_F(FormatTest, StatementAttributeLikeMacros) { TEST_F(FormatTest, IndentAccessModifiers) { FormatStyle Style = getLLVMStyle(); - Style.IndentAccessModifiers = true; + Style.IndentAccessModifiers = FormatStyle::IAMS_Always; // Members are *two* levels below the record; // Style.IndentWidth == 2, thus yielding a 4 spaces wide indentation. verifyFormat("class C {\n" @@ -24920,10 +24920,48 @@ TEST_F(FormatTest, IndentAccessModifiers) { Style); } -TEST_F(FormatTest, IndentImplicitAccessModifiers) { +TEST_F(FormatTest, IndentAccessModifiersAfterFirst) { FormatStyle Style = getLLVMStyle(); - Style.IndentAccessModifiers = true; - Style.IndentImplicitAccessModifiers = false; + verifyFormat("struct S {\n" + " int before;\n" + "\n" + "public:\n" + " int after;\n" + "};", + Style); + + Style.IndentAccessModifiers = FormatStyle::IAMS_Always; + verifyFormat("struct S {\n" + " int before;\n" + "\n" + " public:\n" + " int after;\n" + "};", + Style); + Style.IndentAccessModifiers = FormatStyle::IAMS_AfterFirstAccessModifier; + verifyFormat("struct S {\n" + " int member;\n" + "};", + Style); + verifyFormat("struct S {\n" + " int before;\n" + "\n" + " public:\n" + " int after;\n" + "};", + Style); + verifyFormat("struct S {\n" + " int before;\n" + "\n" + " public:\n" + " int after;\n" + "\n" + " private:\n" + " int last;\n" + "};", + Style); + + // Also cover the Allman layout from issue #61631. Style.IndentWidth = 4; Style.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_Never; Style.BreakBeforeBraces = FormatStyle::BS_Allman; diff --git a/clang/unittests/Format/FormatTestCSharp.cpp b/clang/unittests/Format/FormatTestCSharp.cpp index 805fe6f9bd3c2..be98501db166f 100644 --- a/clang/unittests/Format/FormatTestCSharp.cpp +++ b/clang/unittests/Format/FormatTestCSharp.cpp @@ -124,6 +124,17 @@ TEST_F(FormatTestCSharp, AccessModifiers) { "}"); } +TEST_F(FormatTestCSharp, IndentAccessModifiersAfterFirstUsesAlways) { + FormatStyle Style = getDefaultStyle(); + Style.IndentAccessModifiers = FormatStyle::IAMS_AfterFirstAccessModifier; + verifyFormat("class C\n" + "{\n" + " int Before;\n" + " public int After;\n" + "}", + Style); +} + TEST_F(FormatTestCSharp, NoStringLiteralBreaks) { // Breaking of interpolated strings is not implemented. auto Style = getDefaultStyle(); diff --git a/clang/unittests/Format/FormatTestJava.cpp b/clang/unittests/Format/FormatTestJava.cpp index 86e4b2fc361b2..53168ef6a19e1 100644 --- a/clang/unittests/Format/FormatTestJava.cpp +++ b/clang/unittests/Format/FormatTestJava.cpp @@ -28,11 +28,10 @@ class FormatTestJava : public test::FormatTestBase { } }; -TEST_F(FormatTestJava, IndentImplicitAccessModifiersDoesNotAffectJava) { +TEST_F(FormatTestJava, IndentAccessModifiersAfterFirstDoesNotAffectJava) { FormatStyle Style = getDefaultStyle(); Style.IndentWidth = 4; - Style.IndentAccessModifiers = true; - Style.IndentImplicitAccessModifiers = false; + Style.IndentAccessModifiers = FormatStyle::IAMS_AfterFirstAccessModifier; verifyFormat("class C {\n" " int before;\n" " public int after;\n" >From b27ce0fd6f1dc72cfc0474155ba3de3f1af3cd72 Mon Sep 17 00:00:00 2001 From: Noam Bouillet <[email protected]> Date: Thu, 1 Oct 2026 18:28:18 +0200 Subject: [PATCH 3/5] test(format): isolate access indent style cases Keep the plain LLVM style checks focused on the new option. Test the Allman reproduction and Whitesmiths behavior separately. --- clang/unittests/Format/FormatTest.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index e2bb45a7e67d4..358fb03bf4141 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -24960,8 +24960,11 @@ TEST_F(FormatTest, IndentAccessModifiersAfterFirst) { " int last;\n" "};", Style); +} - // Also cover the Allman layout from issue #61631. +TEST_F(FormatTest, IndentAccessModifiersAfterFirstAllman) { + FormatStyle Style = getLLVMStyle(); + Style.IndentAccessModifiers = FormatStyle::IAMS_AfterFirstAccessModifier; Style.IndentWidth = 4; Style.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_Never; Style.BreakBeforeBraces = FormatStyle::BS_Allman; @@ -25000,7 +25003,13 @@ TEST_F(FormatTest, IndentAccessModifiersAfterFirst) { " void changed();\n" "};", Style); +} +TEST_F(FormatTest, IndentAccessModifiersAfterFirstWhitesmiths) { + FormatStyle Style = getLLVMStyle(); + Style.IndentAccessModifiers = FormatStyle::IAMS_AfterFirstAccessModifier; + Style.IndentWidth = 4; + Style.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_Never; Style.BreakBeforeBraces = FormatStyle::BS_Whitesmiths; verifyFormat("struct S\n" " {\n" >From 2175d322497f3bf201af6b25b7d3855eac4555f7 Mon Sep 17 00:00:00 2001 From: Noam Bouillet <[email protected]> Date: Fri, 2 Oct 2026 00:30:26 +0200 Subject: [PATCH 4/5] refactor(format): address access indent review --- clang/docs/ClangFormatStyleOptions.md | 72 ++++++++++-------------- clang/include/clang/Format/Format.h | 66 +++++++++------------- clang/lib/Format/Format.cpp | 2 + clang/lib/Format/UnwrappedLineParser.cpp | 14 +++-- 4 files changed, 65 insertions(+), 89 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.md b/clang/docs/ClangFormatStyleOptions.md index 5aabda184da0f..e982c26929ccc 100644 --- a/clang/docs/ClangFormatStyleOptions.md +++ b/clang/docs/ClangFormatStyleOptions.md @@ -4748,61 +4748,47 @@ the configuration (without a prefix: `Auto`). : Specify how access modifiers and record members are indented. - `Never` (also `false` in configuration) uses `AccessModifierOffset` for - access modifiers and indents members one level below the record. `Always` - (also `true` in configuration) gives access modifiers their own - indentation level and indents all members two levels below the record, - even if there is no explicit access modifier. - `AfterFirstAccessModifier` gives members one level before the first - explicit access modifier and two levels afterwards. If there is no - explicit access modifier, members stay at one level. This behavior applies - to C, C++, and Objective-C; other languages treat it like `Always`. - `AccessModifierOffset` is ignored by `Always` and - `AfterFirstAccessModifier`. - - ```c++ - Never (false): Always (true): - class C { vs. class C { - class D { class D { - void bar(); void bar(); - protected: protected: - D(); D(); - }; }; - public: public: - C(); C(); - }; }; - void foo() { void foo() { - return 1; return 1; - } } - ``` - - ```yaml - IndentAccessModifiers: AfterFirstAccessModifier - ``` - - ```c++ - struct S { - int before; - - public: - int after; - }; - ``` - Possible values: - `IAMS_Never` (in configuration: `Never`) Use `AccessModifierOffset` for access modifiers and indent members one level below the record. + ```c++ + struct S { + int before; + + public: + int after; + }; + ``` + - `IAMS_Always` (in configuration: `Always`) Give access modifiers their own indentation level and indent all - members two levels below the record. + members two levels below the record. Ignore `AccessModifierOffset`. + + ```c++ + struct S { + int before; + + public: + int after; + }; + ``` - `IAMS_AfterFirstAccessModifier` (in configuration: `AfterFirstAccessModifier`) In C, C++, and Objective-C, indent members one level until the first explicit access modifier, then two levels. Other languages use the - `Always` behavior. Available since clang-format 24. + `Always` behavior. Ignore `AccessModifierOffset`. + + ```c++ + struct S { + int before; + + public: + int after; + }; + ``` diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index e6c8aa1f90604..a67a8596e661c 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3185,55 +3185,41 @@ struct FormatStyle { enum IndentAccessModifierStyle : int8_t { /// Use `AccessModifierOffset` for access modifiers and indent members one /// level below the record. + /// \code + /// struct S { + /// int before; + /// + /// public: + /// int after; + /// }; + /// \endcode IAMS_Never, /// Give access modifiers their own indentation level and indent all - /// members two levels below the record. + /// members two levels below the record. Ignore `AccessModifierOffset`. + /// \code + /// struct S { + /// int before; + /// + /// public: + /// int after; + /// }; + /// \endcode IAMS_Always, /// In C, C++, and Objective-C, indent members one level until the first /// explicit access modifier, then two levels. Other languages use the - /// `Always` behavior. Available since clang-format 24. + /// `Always` behavior. Ignore `AccessModifierOffset`. + /// \code + /// struct S { + /// int before; + /// + /// public: + /// int after; + /// }; + /// \endcode IAMS_AfterFirstAccessModifier, }; /// Specify how access modifiers and record members are indented. - /// - /// `Never` (also `false` in configuration) uses `AccessModifierOffset` for - /// access modifiers and indents members one level below the record. `Always` - /// (also `true` in configuration) gives access modifiers their own - /// indentation level and indents all members two levels below the record, - /// even if there is no explicit access modifier. - /// `AfterFirstAccessModifier` gives members one level before the first - /// explicit access modifier and two levels afterwards. If there is no - /// explicit access modifier, members stay at one level. This behavior applies - /// to C, C++, and Objective-C; other languages treat it like `Always`. - /// `AccessModifierOffset` is ignored by `Always` and - /// `AfterFirstAccessModifier`. - /// \code - /// Never (false): Always (true): - /// class C { vs. class C { - /// class D { class D { - /// void bar(); void bar(); - /// protected: protected: - /// D(); D(); - /// }; }; - /// public: public: - /// C(); C(); - /// }; }; - /// void foo() { void foo() { - /// return 1; return 1; - /// } } - /// \endcode - /// \code{.yaml} - /// IndentAccessModifiers: AfterFirstAccessModifier - /// \endcode - /// \code - /// struct S { - /// int before; - /// - /// public: - /// int after; - /// }; - /// \endcode /// \version 13 IndentAccessModifierStyle IndentAccessModifiers; diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index bdb15326a1603..e1b7f7804b5c9 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -485,6 +485,8 @@ struct ScalarEnumerationTraits<FormatStyle::IndentAccessModifierStyle> { IO.enumCase(Value, "Always", FormatStyle::IAMS_Always); IO.enumCase(Value, "AfterFirstAccessModifier", FormatStyle::IAMS_AfterFirstAccessModifier); + + // For backward compatibility. IO.enumCase(Value, "false", FormatStyle::IAMS_Never); IO.enumCase(Value, "true", FormatStyle::IAMS_Always); } diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 11c70db50435e..9e81efc286a5e 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -896,7 +896,7 @@ FormatToken *UnwrappedLineParser::parseBlock( // Munch the closing brace. if (SeenExplicitAccessModifier) ++AddLevels; - nextToken(/*LevelDifference=*/-static_cast<int>(AddLevels)); + nextToken(/*LevelDifference=*/-AddLevels); // When this is a function block and there is an unnecessary semicolon // afterwards then mark it as optional (so the RemoveSemi pass can get rid of @@ -4315,9 +4315,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, bool IsJavaRecord) { addUnwrappedLine(); } - const bool IndentAfterExplicitAccessModifier = - Style.isCpp() && Style.IndentAccessModifiers == - FormatStyle::IAMS_AfterFirstAccessModifier; + bool IndentAfterExplicitAccessModifier = false; unsigned AddLevels = 1u; switch (Style.IndentAccessModifiers) { case FormatStyle::IAMS_Never: @@ -4326,8 +4324,12 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, bool IsJavaRecord) { AddLevels = 2u; break; case FormatStyle::IAMS_AfterFirstAccessModifier: - // Other languages keep the indentation of the old true setting. - AddLevels = IndentAfterExplicitAccessModifier ? 1u : 2u; + if (Style.isCpp()) { + IndentAfterExplicitAccessModifier = true; + } else { + // Other languages use the same indentation as IAMS_Always. + AddLevels = 2u; + } break; } parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/false, >From 58173480d3e9c4bb13d007e06057e33bef2b3d1c Mon Sep 17 00:00:00 2001 From: Noam Bouillet <[email protected]> Date: Sat, 3 Oct 2026 00:02:41 +0200 Subject: [PATCH 5/5] refactor(format): simplify access indent handling --- clang/docs/ClangFormatStyleOptions.md | 5 +++-- clang/include/clang/Format/Format.h | 5 +++-- clang/lib/Format/UnwrappedLineParser.cpp | 13 ++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.md b/clang/docs/ClangFormatStyleOptions.md index e982c26929ccc..6ff29082c8a7a 100644 --- a/clang/docs/ClangFormatStyleOptions.md +++ b/clang/docs/ClangFormatStyleOptions.md @@ -4765,7 +4765,8 @@ the configuration (without a prefix: `Auto`). - `IAMS_Always` (in configuration: `Always`) Give access modifiers their own indentation level and indent all - members two levels below the record. Ignore `AccessModifierOffset`. + members two levels below the record. Value of the `AccessModifierOffset` + is ignored. ```c++ struct S { @@ -4779,7 +4780,7 @@ the configuration (without a prefix: `Auto`). - `IAMS_AfterFirstAccessModifier` (in configuration: `AfterFirstAccessModifier`) In C, C++, and Objective-C, indent members one level until the first explicit access modifier, then two levels. Other languages use the - `Always` behavior. Ignore `AccessModifierOffset`. + `Always` behavior. Value of the `AccessModifierOffset` is ignored. ```c++ struct S { diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index a67a8596e661c..036353752e831 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3195,7 +3195,8 @@ struct FormatStyle { /// \endcode IAMS_Never, /// Give access modifiers their own indentation level and indent all - /// members two levels below the record. Ignore `AccessModifierOffset`. + /// members two levels below the record. Value of the `AccessModifierOffset` + /// is ignored. /// \code /// struct S { /// int before; @@ -3207,7 +3208,7 @@ struct FormatStyle { IAMS_Always, /// In C, C++, and Objective-C, indent members one level until the first /// explicit access modifier, then two levels. Other languages use the - /// `Always` behavior. Ignore `AccessModifierOffset`. + /// `Always` behavior. Value of the `AccessModifierOffset` is ignored. /// \code /// struct S { /// int before; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 9e81efc286a5e..901335950b9fa 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -893,9 +893,9 @@ FormatToken *UnwrappedLineParser::parseBlock( size_t PPEndHash = computePPHash(); - // Munch the closing brace. if (SeenExplicitAccessModifier) ++AddLevels; + // Munch the closing brace. nextToken(/*LevelDifference=*/-AddLevels); // When this is a function block and there is an unnecessary semicolon @@ -4320,16 +4320,15 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, bool IsJavaRecord) { switch (Style.IndentAccessModifiers) { case FormatStyle::IAMS_Never: break; - case FormatStyle::IAMS_Always: - AddLevels = 2u; - break; case FormatStyle::IAMS_AfterFirstAccessModifier: if (Style.isCpp()) { IndentAfterExplicitAccessModifier = true; - } else { - // Other languages use the same indentation as IAMS_Always. - AddLevels = 2u; + break; } + // Other languages use the same indentation as IAMS_Always. + [[fallthrough]]; + case FormatStyle::IAMS_Always: + AddLevels = 2u; break; } parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/false, _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
