Issue 91671
Summary [clang-format] Formatting overflows column limit with `BreakBeforeTernaryOperators: true` and `AlignAfterOpenBracket: AlwaysBreak`
Labels clang-format
Assignees
Reporter JamieStM
    ## Summary

Long brace-initialized values in the true statement of ternary operators results in incorrect formatting, including arbitrarily overflowing the column limit, when:

```yaml
BreakBeforeTernaryOperators: true
```
and
```yaml
AlignAfterOpenBracket: AlwaysBreak
```

## Versions affected

Affects clang-format versions >= 10, but not <= 9. Tested each of 7, 8, 9, 10, 11, 14 and 18 on windows. Tested clang-format-18 on ubuntu.

## Repro case

Invoke `clang-format --style=file` on a folder with the following code (as shown after formatting on clang-format-18):

`.clang-format`:

```yaml
Language: Cpp
BasedOnStyle: LLVM
BreakBeforeTernaryOperators: true
AlignAfterOpenBracket: AlwaysBreak
ColumnLimit: 80
```

`main.cpp`:
```cpp
#include <string>
#include <vector>

int main() {
  auto my_vect =
      true
          ? std::vector<
                std::
 string>{std::string{"long string for demonstration"}, std::string{"long string for demonstration"}, std::string{"long string for demonstration"}}
          : std::vector<std::string>{
 std::string{"long string for demonstration"},
 std::string{"long string for demonstration"},
 std::string{"long string for demonstration"}};
}
```

Expected result:
```cpp
  auto my_vect =
      true
          ? std::vector<std::string>{
                std::string{"long string for demonstration"},
                std::string{"long string for demonstration"},
                std::string{"long string for demonstration"}}
          : std::vector<std::string>{
 std::string{"long string for demonstration"},
 std::string{"long string for demonstration"},
 std::string{"long string for demonstration"}};
// or similar, e.g.
 auto my_vect = true ? std::vector<std::string>{
 std::string{"long string for demonstration"},
 std::string{"long string for demonstration"},
 std::string{"long string for demonstration"}}
                      : std::vector<std::string>{
                            std::string{"long string for demonstration"},
 std::string{"long string for demonstration"},
 std::string{"long string for demonstration"}};
```

Result prior to clang-format 10 (acceptable, but still not quite what is expected):
```cpp
  auto my_vect =
      true ? std::vector<std::string>{std::string{
 "long string for demonstration"},
 std::string{
                                          "long string for demonstration"},
 std::string{
                                          "long string for demonstration"}}
           : std::vector<std::string>{
 std::string{"long string for demonstration"},
 std::string{"long string for demonstration"},
 std::string{"long string for demonstration"}};
```

## Further information

What does affect it:

- If the vector's brace initializer is changed to use a parentheses initializer (including when passing an initializer list as a single parameter), this formats correctly.
- The length of each element of the initializer list. It formats lists of short elements correctly, e.g. `std::vector<int>{1, 2, 3, ...}`. I don't know where the boundary is, but it at least occurs when two elements are too long to fit on a single line (i.e. where, in the false case of the ternary _expression_, the same _expression_ breaks each element onto their own line).
- BOTH `BreakBeforeTernaryOperators: true` and `AlignAfterOpenBracket: AlwaysBreak` must be set
  - `BreakBeforeTernaryOperators: false` and `AlignAfterOpenBracket: AlwaysBreak` formats this correctly (albeit slightly differently)
  - `BreakBeforeTernaryOperators: true` and `AlignAfterOpenBracket: Align` formats this correctly (albeit slightly differently)
  - `BreakBeforeTernaryOperators: false` and `AlignAfterOpenBracket: Align` formats this correctly (albeit slightly differently)

What doesn't affect it:

- The actual type used within the vector or how each is defined (e.g. whether the constructors use parentheses or braces, whether there is a type specified at all, whether there are string literals, etc.), provided that each element of the initializer list is sufficiently long.
- Indentation level
- `Standard`, `IndentWidth`, or `ContinuationIndentWidth`
- Whether the template parameter is there or not (i.e. `std::vector{...}` has the same result as `std::vector<std::string>{...}`)
- Length of predicate _expression_
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to