[clang-format][PR45816] Add AlignConsecutiveBitFields

Summary:
The following revision follows D80115 since @MyDeveloperDay and I apparently both had the same idea at the same time, for https://bugs.llvm.org/show_bug.cgi?id=45816 and my efforts on tooling support for AMDVLK, respectively.

This option aligns adjacent bitfield separators across lines, in a manner similar to AlignConsecutiveAssignments and friends.

Example:
```
struct RawFloat {
  uint32_t sign : 1;
  uint32_t exponent : 8;
  uint32_t mantissa : 23;
};
```
would become
```
struct RawFloat {
  uint32_t sign     : 1;
  uint32_t exponent : 8;
  uint32_t mantissa : 23;
};
```

This also handles c++2a style bitfield-initializers with AlignConsecutiveAssignments.
```
struct RawFloat {
  uint32_t sign     : 1  = 0;
  uint32_t exponent : 8  = 127;
  uint32_t mantissa : 23 = 0;
}; // defaults to 1.0f
```

Things this change does not do:
 - Align multiple comma-chained bitfield variables. None of the other
   AlignConsecutive* options seem to implement that either.
 - Detect bitfields that have a width specified with something other
   than a numeric literal (ie, `int a : SOME_MACRO;`). That'd be fairly
   difficult to parse and is rare.

Patch By:  JakeMerdichAMD

Reviewed By: MyDeveloperDay

Subscribers: cfe-commits, MyDeveloperDay

Tags: #clang, #clang-format

Differential Revision: https://reviews.llvm.org/D80176
This commit is contained in:
mydeveloperday 2020-05-20 07:42:07 +01:00
parent 6ca54e0114
commit b99bf0e08b
7 changed files with 111 additions and 2 deletions

View File

@ -204,6 +204,18 @@ the configuration (without a prefix: ``Auto``).
int b = 23;
int ccc = 23;
**AlignConsecutiveBitFields** (``bool``)
If ``true``, aligns consecutive bitfield members.
This will align the bitfield separators 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.

View File

@ -297,6 +297,21 @@ clang-format
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
--------

16
clang/include/clang/Format/Format.h Normal file → Executable file
View File

@ -108,6 +108,17 @@ struct FormatStyle {
/// \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
@ -2011,8 +2022,8 @@ struct FormatStyle {
/// \endcode
SBPO_ControlStatements,
/// Same as ``SBPO_ControlStatements`` except this option doesn't apply to
/// ForEach macros. This is useful in projects where ForEach macros are
/// treated as function calls instead of control statements.
/// ForEach macros. This is useful in projects where ForEach macros are
/// treated as function calls instead of control statements.
/// \code
/// void f() {
/// Q_FOREACH(...) {
@ -2218,6 +2229,7 @@ struct FormatStyle {
return AccessModifierOffset == R.AccessModifierOffset &&
AlignAfterOpenBracket == R.AlignAfterOpenBracket &&
AlignConsecutiveAssignments == R.AlignConsecutiveAssignments &&
AlignConsecutiveBitFields == R.AlignConsecutiveBitFields &&
AlignConsecutiveDeclarations == R.AlignConsecutiveDeclarations &&
AlignEscapedNewlines == R.AlignEscapedNewlines &&
AlignOperands == R.AlignOperands &&

View File

@ -403,6 +403,8 @@ template <> struct MappingTraits<FormatStyle> {
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 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AlignOperands = FormatStyle::OAS_Align;
LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AlignConsecutiveAssignments = false;
LLVMStyle.AlignConsecutiveBitFields = false;
LLVMStyle.AlignConsecutiveDeclarations = false;
LLVMStyle.AlignConsecutiveMacros = false;
LLVMStyle.AllowAllArgumentsOnNextLine = true;

View File

@ -95,6 +95,7 @@ const tooling::Replacements &WhitespaceManager::generateReplacements() {
calculateLineBreakInformation();
alignConsecutiveMacros();
alignConsecutiveDeclarations();
alignConsecutiveBitFields();
alignConsecutiveAssignments();
alignChainedConditionals();
alignTrailingComments();
@ -617,6 +618,26 @@ void WhitespaceManager::alignConsecutiveAssignments() {
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;

View File

@ -184,6 +184,9 @@ private:
/// 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();

View File

@ -12022,6 +12022,48 @@ TEST_F(FormatTest, AlignConsecutiveAssignments) {
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;
@ -13436,6 +13478,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
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);