llvm / llvm/llvm-project

[clang-format] `AlignTrailingComments: Kind: Leave` de-indents standalone comments after a comment reaches the column limit

Open
#200,489 2 comments 0 reactions 0 assignees View on GitHub
clang-format
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Summary

With `AlignTrailingComments: Kind: Leave`, a comment whose extent reaches the
configured `ColumnLimit` causes clang-format to **de-indent every subsequent
aligned standalone comment for the rest of the file**. The triggering comment
is itself left unchanged; the damage is to later comment-only lines that were
manually indented to line up under a trailing comment.

The trigger line is within (or exactly at) the column limit, so it is never
reflowed or flagged as too long. The effect persists across blank lines and
function/struct boundaries until end of file. Blocks *before* the trigger are
untouched.

This looks like an off-by-one in the "comment reaches the column limit" check
(using `>=` where `>` is intended), which corrupts the `Leave` alignment
bookkeeping for all following standalone comments.

Not sure if this bug is somehow related to llvm/llvm-project#196663. They both
involve the same `AlignTrailingComments: Kind: Leave` option.

## Environment

- clang-format: `Ubuntu clang-format version 22.1.3`
- Also reproduced with latest `main` branch (`6da24e4022f0cc6e97db939c1ea6df20dbb02ae6`)

## Minimal config

```yaml
# .clang-format
BasedOnStyle: LLVM
ColumnLimit: 40
ReflowComments: IndentOnly
AlignTrailingComments:
Kind: Leave
```

`ColumnLimit: 40` is used only to keep the examples short; the bug is relative
to `ColumnLimit` (verified at 40, 80, 100, 120).

## Reproduction A — standalone comment of length == ColumnLimit

Input (line 1 is exactly 40 columns):

```cpp
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
int x; // first
// second
```

Actual output:

```cpp
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
int x; // first
// second
```

Expected output: unchanged. `// second` should remain aligned under `// first`,
exactly as it does when line 1 is one column shorter (39).

## Reproduction B — trailing comment of length == ColumnLimit - 1

A line that ends in a *trailing* comment triggers the bug one column earlier
(at `ColumnLimit - 1`), because the space before the trailing comment is
counted into the overflow accounting.

Input (line 1 is exactly 39 columns):

```cpp
int v = 1; // xxxxxxxxxxxxxxxxxxxxxxxxx
int x; // first
// second
```

Actual output:

```cpp
int v = 1; // xxxxxxxxxxxxxxxxxxxxxxxxx
int x; // first
// second
```

Expected output: unchanged.

## Non-trigger (control) — code-only line at the limit

A line that ends in code (no trailing comment) never triggers the bug, at any
length:

```cpp
int xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
int x; // first
// second
```

Output: unchanged (`// second` stays aligned).

## Scope — one trigger poisons the rest of the file

Input:

```cpp
int before; // kept
// aligned, BEFORE trigger
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
int a; // x
// after trigger

int b; // y
// across blank line

void f() {
int c; // z
// inside function
}
```

Actual output:

```cpp
int before; // kept
// aligned, BEFORE trigger
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
int a; // x
// after trigger

int b; // y
// across blank line

void f() {
int c; // z
// inside function
}
```

The block before the trigger is preserved. Every aligned standalone comment
after the trigger is de-indented to its enclosing code indentation (column 0 at
file scope, column 2 inside the function), across blank lines and scope
boundaries.

## Trigger conditions (summary)

For a configured `ColumnLimit` of `L`, with line length measured after
trailing-whitespace is stripped:

| Line type | Triggers when |
|--------------------------------------------|---------------|
| Standalone comment (`// ...` whole line) | length `>= L` |
| Code + trailing comment (`code; // ...`) | length `>= L - 1` |
| Code + trailing block comment (`code; /* ... */`) | length `>= L - 1` |
| Code-only line (ends in code) | never |

## Expected behavior

A comment whose length is within `ColumnLimit` is conforming and should have no
effect on the indentation of unrelated comments elsewhere in the file.
`AlignTrailingComments: Kind: Leave` should leave existing comment indentation
as-is regardless of any other line's length.

## Workarounds

- Manually keep every comment strictly under `ColumnLimit` (`<= L - 1` for standalone,
`<= L - 2` for trailing). Removing the over-limit comment removes the trigger.
- This is really annoying because a comment line right on the column limit also triggers
The bug. Makes clang-format almost unusable.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.