[clang-format] New option value for operand alignment
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
### What `AlignOperands = Align` brought to the table in the first place
According to the documentation, the purpose of the `AlignOperands = Align` is to "horizontally align operands of binary and ternary expressions" in the sense that it "aligns operands of a single expression that needs to be split over multiple lines".
Here is the given example :
```
int aaa = bbbbbbbbbbbbbbb +
ccccccccccccccc;
```
If you combine several operators, you can get things like
```
int aaa = bbbbbbbbbbbbbbb +
ccccccccccccccc +
ddddddddddddddddddd *
eeeeeeeeeeeeeeeeeee +
fffffffffffffff;
```
It's pretty clear why a programmer may want to choose to align operands like this : in the same way that they may write something like this
```
foo(
wwwwwwwwwwwwwww,
bar(
xxxxxxxxxxxxxxx,
yyyyyyyyyyyyyyy
),
zzzzzzzzzzzzzzz
);
```
the formatting makes it clear that things that are aligned are operands on the same level, and indentation shows where there are inner operations (and since many operations have associativity, knowing that operands are on the same level often allows to reason about them as if they were all operands of a single operation)
Two limitations are plain to see in the example :
- while it's clear that there are 4 operands to the outer operations, it is much less clear that there are 2 operands to the inner operation because `ddddddddddddddddddd` and `eeeeeeeeeeeeeeeeeee` are not aligned
- operators are at the end of the line and not aligned, so a glance is not enough to know what the operations are and check that all outer operators are the same
### What `BreakBeforeBinaryOperators` brings to the table
With `BreakBeforeBinaryOperators`, operators can be aligned :
```
int aaa = bbbbbbbbbbbbbbb
+ ccccccccccccccc
+ ddddddddddddddddddd
* eeeeeeeeeeeeeeeeeee
+ fffffffffffffff;
```
Now it's still easy to see that there are inner and outer operations, and that all outer operators are the same.
The remaining issue is that of symmetry (i.e. the actual alignment of operands of the same level) :
- `ddddddddddddddddddd` and `eeeeeeeeeeeeeeeeeee` are still not aligned, despite being operands of the same inner operation
- `bbbbbbbbbbbbbbb` is not aligned with operands of the same level either (it's only aligned with the operators)
### What `AlignOperands = AlignAfterOperator` brings to the table
`AlignOperands = AlignAfterOperator` is meant to align the operands even when the operator comes first, by removing some spaces before the operators :
```
int aaa = bbbbbbbbbbbbbbb
+ ccccccccccccccc
+ ddddddddddddddddddd
* eeeeeeeeeeeeeeeeeee
+ fffffffffffffff;
```
It does manage to align `bbbbbbbbbbbbbbb` with operands of the same level, but :
- `ddddddddddddddddddd` and `eeeeeeeeeeeeeeeeeee` are still not aligned, despite being operands of the same inner operation
- it doesn't work when there is a break before the first operand :
```
int aaa =
bbbbbbbbbbbbbbb
+ ccccccccccccccc
+ ddddddddddddddddddd
* eeeeeeeeeeeeeeeeeee
+ fffffffffffffff;
```
- more generally, it doesn't work if it's not directly after an assignment operator
```
if (firstCondition
&& secondCondition
&& (thirdCondition
|| fourthCondition))
```
### What I suggest
I propose that a new possible value should be added for `AlignOperands` that actually aligns the operands as promised, relying on padding instead.
It would look like this :
```
int aaa = bbbbbbbbbbbbbbb
+ ccccccccccccccc
+ ddddddddddddddddddd
* eeeeeeeeeeeeeeeeeee
+ fffffffffffffff;
```
would still work with a line break before the first operand :
```
int aaa =
bbbbbbbbbbbbbbb
+ ccccccccccccccc
+ ddddddddddddddddddd
* eeeeeeeeeeeeeeeeeee
+ fffffffffffffff;
```
or with parentheses :
```
int aaa =
bbbbbbbbbbbbbbb
+ ccccccccccccccc
+ ( ddddddddddddddddddd
* eeeeeeeeeeeeeeeeeee)
+ fffffffffffffff;
```
or outside an assignment :
```
if ( firstCondition
&& secondCondition
&& ( thirdCondition
|| fourthCondition))
```
Contributor guide
Research direction
Start by tracing clang-format's AlignOperands and BreakBeforeBinaryOperators options and compare their documented behavior with the examples in this issue. The work is complete when a new AlignOperands value provides the proposed padding-based alignment for nested expressions, line breaks before the first operand, parentheses, and conditions outside assignments.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100