Issue 203046
Summary [clang-format] Under `AlignTrailingComments: Leave`, a wedged comment's column depends on the width of an unrelated earlier comment
Labels clang-format
Assignees
Reporter yfguo
    ## Summary

With `AlignTrailingComments: Kind: Leave`, a standalone (own-line) comment wedged between
the branches of a ternary chain is normally left at its input column (the branch column the
developer wrote it at). The bug is that the rendered width of a different, lexically
unrelated comment earlier in the same function changes where the wedged comment ends up:
once the earlier comment is long enough, `Leave` stops preserving the wedged comment's input
column and relocates it to the operand column.

Changing only the length of the earlier comment thus flips the wedged comment between the
branch column and the operand column, even though nothing about the ternary or the wedged
comment changed.

## Environment

Reproduced on the following:

- clang-format version: Ubuntu clang-format version 22.1.3
- clang-format version 23.0.0git, built from `main` at commit
  `3443243ded167229ddc37e64b7e754854ae1ba2c`.
- clang-format version 23.0.0git, built from PR #196760
  ("[clang-format] Update comment indentation, even with Leave") at commit
  `6bd02e810b8e5608e29e51762052ce4f20d33d4c`. The PR does not change this behavior; both
  builds produce identical output.

## Config (`.clang-format`)

```yaml
BasedOnStyle: LLVM
ColumnLimit: 80
BreakBeforeTernaryOperators: false
AlignTrailingComments:
  Kind: Leave
```

## Reproduction

The two inputs below are identical except for the length of the **first** comment, tuned to
straddle the trigger threshold by a single column. At `ColumnLimit: 80` the threshold for
this input is end-column 78 (see [Threshold](#threshold)). Both wedged comments are written
on their own line at the branch column, aligned with the `(a == N)` conditions.

### Input 1 — first comment ends at column 78 (at the threshold)

```cpp
void f(int a) {
  // explanatory comment whose end column is tuned to the trigger thresholdxxx
  int x = (a == 1) ? 11 :
          (a == 2) ? 22 :
          // wedged comment
          (a == 3) ? 33 :
                     44;
}
```

clang-format relocates the wedged comment to the operand column:

```cpp
void f(int a) {
  // explanatory comment whose end column is tuned to the trigger thresholdxxx
  int x = (a == 1) ? 11 :
          (a == 2) ? 22 :
                     // wedged comment
              (a == 3) ? 33 :
                         44;
}
```

### Input 2 — first comment ends at column 77 (one column shorter)

```cpp
void f(int a) {
  // explanatory comment whose end column is tuned to the trigger thresholdxx
  int x = (a == 1) ? 11 :
          (a == 2) ? 22 :
          // wedged comment
          (a == 3) ? 33 :
                     44;
}
```

clang-format leaves the wedged comment at the branch column:

```cpp
void f(int a) {
  // explanatory comment whose end column is tuned to the trigger thresholdxx
  int x = (a == 1) ? 11 :
          (a == 2) ? 22 :
          // wedged comment
              (a == 3) ? 33 :
                         44;
}
```

The two inputs differ only by one column in the first comment, which is on its own line and
has no syntactic relationship to the wedged comment, yet the wedged comment's column flips
between the operand column and the branch column.

The alignment change after the wedged comment is not related and reported separated in Github Issue #203044.

## Threshold

The relocation fires as a function of the earlier comment's end column **relative to
`ColumnLimit`**, not an absolute length: once the earlier comment's end column reaches
`ColumnLimit - 2` the wedged comment is relocated. The `- 2` offset is consistent across
`ColumnLimit` values:

| `ColumnLimit` | first triggering end-column |
| ------------- | --------------------------- |
| 40            | 38                          |
| 50            | 48                          |
| 60            | 58                          |
| 80            | 78                          |
| 100           | 98                          |
| 120           | 118                         |

The offset also depends on the **wedged** comment's width (the `- 2` is for the
`// wedged comment` used here; a shorter wedged comment lowers the threshold further, e.g.
`// w` triggers at `ColumnLimit - 8`). Because the threshold scales with `ColumnLimit`, a
large limit (e.g. `ColumnLimit: 200`) is never reached by an ordinary comment, so the bug
does not fire there.

## Expected behavior

Under `Kind: Leave`, the wedged comment's indentation should be preserved at its input
column (the branch column, aligned with the `(a == N)` conditions) and must not depend on
the width of an unrelated earlier comment. Both inputs above should keep the wedged
comment at the branch column.

_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to