diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -204,6 +204,18 @@ int b = 23; int ccc = 23; +**AlignConsecutiveBitFields** (``bool``) + If ``true``, aligns consecutive bitfield members. + + This will align the bitfield separator of consecutive lines. This + will result in formattings like + + .. code-block:: c++ + + int aaaa : 1; + int b : 12; + int ccc : 8; + **AlignConsecutiveDeclarations** (``bool``) If ``true``, aligns consecutive declarations. diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -297,6 +297,21 @@ bar(); }); +- Option ``AlignConsecutiveBitFields`` has been added to align bit field + declarations across multiple adjacent lines + + .. code-block:: c++ + + true: + bool aaa : 1; + bool a : 1; + bool bb : 1; + + false: + bool aaa : 1; + bool a : 1; + bool bb : 1; + libclang -------- diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -108,6 +108,17 @@ /// \endcode bool AlignConsecutiveAssignments; + /// If ``true``, aligns consecutive bitfield members. + /// + /// This will align the bitfield separators of consecutive lines. This + /// will result in formattings like + /// \code + /// int aaaa : 1; + /// int b : 12; + /// int ccc : 8; + /// \endcode + bool AlignConsecutiveBitFields; + /// If ``true``, aligns consecutive declarations. /// /// This will align the declaration names of consecutive lines. This @@ -2218,6 +2229,7 @@ return AccessModifierOffset == R.AccessModifierOffset && AlignAfterOpenBracket == R.AlignAfterOpenBracket && AlignConsecutiveAssignments == R.AlignConsecutiveAssignments && + AlignConsecutiveBitFields == R.AlignConsecutiveBitFields && AlignConsecutiveDeclarations == R.AlignConsecutiveDeclarations && AlignEscapedNewlines == R.AlignEscapedNewlines && AlignOperands == R.AlignOperands && diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -403,6 +403,8 @@ IO.mapOptional("AlignConsecutiveMacros", Style.AlignConsecutiveMacros); IO.mapOptional("AlignConsecutiveAssignments", Style.AlignConsecutiveAssignments); + IO.mapOptional("AlignConsecutiveBitFields", + Style.AlignConsecutiveBitFields); IO.mapOptional("AlignConsecutiveDeclarations", Style.AlignConsecutiveDeclarations); IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines); @@ -766,6 +768,7 @@ LLVMStyle.AlignOperands = FormatStyle::OAS_Align; LLVMStyle.AlignTrailingComments = true; LLVMStyle.AlignConsecutiveAssignments = false; + LLVMStyle.AlignConsecutiveBitFields = false; LLVMStyle.AlignConsecutiveDeclarations = false; LLVMStyle.AlignConsecutiveMacros = false; LLVMStyle.AllowAllArgumentsOnNextLine = true; diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h --- a/clang/lib/Format/WhitespaceManager.h +++ b/clang/lib/Format/WhitespaceManager.h @@ -184,6 +184,9 @@ /// Align consecutive assignments over all \c Changes. void alignConsecutiveAssignments(); + /// Align consecutive bitfields over all \c Changes. + void alignConsecutiveBitFields(); + /// Align consecutive declarations over all \c Changes. void alignConsecutiveDeclarations(); diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -95,6 +95,7 @@ calculateLineBreakInformation(); alignConsecutiveMacros(); alignConsecutiveDeclarations(); + alignConsecutiveBitFields(); alignConsecutiveAssignments(); alignChainedConditionals(); alignTrailingComments(); @@ -609,6 +610,26 @@ Changes, /*StartAt=*/0); } +void WhitespaceManager::alignConsecutiveBitFields() { + if (!Style.AlignConsecutiveBitFields) + return; + + AlignTokens( + Style, + [&](Change const &C) { + // Do not align on ':' that is first on a line. + if (C.NewlinesBefore > 0) + return false; + + // Do not align on ':' that is last on a line. + if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0) + return false; + + return C.Tok->is(TT_BitFieldColon); + }, + Changes, /*StartAt=*/0); +} + void WhitespaceManager::alignConsecutiveDeclarations() { if (!Style.AlignConsecutiveDeclarations) return; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -11955,6 +11955,48 @@ Alignment); } +TEST_F(FormatTest, AlignConsecutiveBitFields) { + FormatStyle Alignment = getLLVMStyle(); + Alignment.AlignConsecutiveBitFields = true; + verifyFormat("int const a : 5;\n" + "int oneTwoThree : 23;", + Alignment); + + // Initializers are allowed starting with c++2a + verifyFormat("int const a : 5 = 1;\n" + "int oneTwoThree : 23 = 0;", + Alignment); + + Alignment.AlignConsecutiveDeclarations = true; + verifyFormat("int const a : 5;\n" + "int oneTwoThree : 23;", + Alignment); + + verifyFormat("int const a : 5; // comment\n" + "int oneTwoThree : 23; // comment", + Alignment); + + verifyFormat("int const a : 5 = 1;\n" + "int oneTwoThree : 23 = 0;", + Alignment); + + Alignment.AlignConsecutiveAssignments = true; + verifyFormat("int const a : 5 = 1;\n" + "int oneTwoThree : 23 = 0;", + Alignment); + verifyFormat("int const a : 5 = {1};\n" + "int oneTwoThree : 23 = 0;", + Alignment); + + // Known limitations: ':' is only recognized as a bitfield colon when + // followed by a number. + /* + verifyFormat("int oneTwoThree : SOME_CONSTANT;\n" + "int a : 5;", + Alignment); + */ +} + TEST_F(FormatTest, AlignConsecutiveDeclarations) { FormatStyle Alignment = getLLVMStyle(); Alignment.AlignConsecutiveMacros = true; @@ -13369,6 +13411,7 @@ Style.Language = FormatStyle::LK_Cpp; CHECK_PARSE_BOOL(AlignTrailingComments); CHECK_PARSE_BOOL(AlignConsecutiveAssignments); + CHECK_PARSE_BOOL(AlignConsecutiveBitFields); CHECK_PARSE_BOOL(AlignConsecutiveDeclarations); CHECK_PARSE_BOOL(AlignConsecutiveMacros); CHECK_PARSE_BOOL(AllowAllArgumentsOnNextLine);