[BUG] ClangFormat behaves strangely if it believes a code block is inactive
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
```c
#if 0
struct my_struct {
int a: 1;
int long_c: 1;
int b;
};
int * a ;
char* foo( ) {
int b = 4 * 9;
}
#define MACRO( ) "blabla"
//comment
#define LONG_LONG_LONG_MACRO( ) "blabla"
#endif
```
Practically almost nothing gets formatted, the only things that get formatted are the 2 macros, which by the way are formatted incorrectly since they have been aligned even though they shouldn't be, as the [`AlignConsecutiveMacros: Consecutive`](https://clang.llvm.org/docs/ClangFormatStyleOptions.html#alignconsecutivemacros) option should only align them if they are consecutive
```c
#if 0
struct my_struct {
int a: 1;
int long_c: 1;
int b;
};
int * a ;
char* foo( ) {
int b = 4 * 9;
}
#define MACRO() "blabla"
//comment
#define LONG_LONG_LONG_MACRO() "blabla"
#endif
```
The same behavior also occurs if I change the condition from `#if 0` to `#if 0 == MY_CONDITION`
```c
#if 0 == MY_CONDITION
struct my_struct {
int a: 1;
int long_c: 1;
int b;
};
int * a ;
char* foo( ) {
int b = 4 * 9;
}
#define MACRO() "blabla"
//comment
#define LONG_LONG_LONG_MACRO() "blabla"
#endif
```
By enabling the `#if 1` block or strangely by inverting the condition to `#if MY_CONDITION == 0`, or by using the parentheses like `#if (0 == MY_CONDITION)` or `#if (0)` the code gets formatted correctly
```c
#if MY_CONDITION == 0 // Same behaviour with #if 1, #if (0 == MY_CONDITION) or #if (0)
struct my_struct
{
int a : 1;
int long_c : 1;
int b;
};
int *a;
char *foo()
{
int b = 4 * 9;
}
#define MACRO() "blabla"
// comment
#define LONG_LONG_LONG_MACRO() "blabla"
#endif
```
My `.clang-format` file:
```yaml
BreakBeforeBraces: Allman # Allman indentation style
SortIncludes: false # Avoid sorting `#include` directives alphabetically
ColumnLimit: 100 # Max 100 characters per line
UseTab: Never # Use spaces instead tabulation
IndentWidth: 4 # Use 4 spaces for indentations
IndentCaseLabels: true # Use indentation on switch-case labels
AlignConsecutiveMacros: Consecutive # Align consecutive `#define` values
AlignConsecutiveAssignments: Consecutive # Align consecutive assignment values
AlignConsecutiveBitFields: Consecutive # Align consecutive bit-field values
AllowShortFunctionsOnASingleLine: None # Avoid single line function: `int f() { return 0; }`
AllowShortIfStatementsOnASingleLine: Never # Avoid single line: `if (a) return;`
SeparateDefinitionBlocks: Always # Add empty line between one definition and the next
PenaltyBreakAssignment: 21 # Prefer starting rvalue of assignment on same line
PenaltyReturnTypeOnItsOwnLine: 100 # Keeps return type and function name on same line
QualifierAlignment: Custom # Enforce qualifier order
QualifierOrder: [static, inline, const, volatile, type]
KeepEmptyLines: # Empty lines options:
AtStartOfFile: false # No empty lines at start of file
AtEndOfFile: false # No empty lines at end of file
AtStartOfBlock: false # No empty lines before open curly brace
LineEnding: LF # Use `\n` character for new lines instead of `\r\n`
InsertBraces: true # Add {} after `if`, `else`, `for`, `do`, and `while`
InsertNewlineAtEOF: true # Add blank line at EOF for C standard compliance
```
Contributor guide
Research direction
Reproduce the issue with the provided C snippets, .clang-format settings, and clang-format entry point, comparing inactive preprocessor branches and macro alignment. Trace how #if conditions are classified and formatted; done when code in inactive branches is formatted consistently and AlignConsecutiveMacros respects non-consecutive definitions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100