Skip to content

[clang-format] unexpected break after binOp '<<' #69859

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

s1Sharp
Copy link

@s1Sharp s1Sharp commented Oct 21, 2023

the problem occurred while checking for the correctness of the break after binary operators. The output statement 'tok::lessless' is then break line every possible time, which is not expected with the BreakBeforeBinaryOperators: None

Fixes #59797
Fixes #44363

@s1Sharp
Copy link
Author

s1Sharp commented Oct 22, 2023

I have no way to link the issues related to the PR issue. I don't know why, but add a link to issue to this comment #44363 .
So, I want to start a little discussion about the solution.

I'll start with the problem - when using the BreakBeforeBinaryOperators: None option, I expect that the code

std::cout << "hello " << "world!";

with binary output operation to stream via token "<<" (tok::lessless)
clang-format output is:

std::cout << "hello "
                     << "world!";

This was unexpected for me and unnecessary, as well as for other users who have already created issues.
The token '<<' is a binary operator that have link to the "BreakBeforeBinaryOperators" option.

1th solution is: Apply the break of the binary operator '<<' only if BreakBeforeBinaryOperators is [All | NonAssignment]. And not break if BreakBeforeBinaryOperators is None. This solution is very simple, but, in my opinion, violates the user api and the user's expectations of the clang-format program.

2th solution is: Add new option that allowing specific behaviour, such as "BreakAfterStreamOperator" or "BreakAfterLessLessOperator" with options [ Leave | NoFitLine | All ].

I am open to discussions

the problem occurred while checking for the correctness of the break after binary operators.
The output statement 'tok::lessless' is then break line every possible time,
which is not expected with the BreakBeforeBinaryOperators: None

Fixes llvm#59797
Fixes llvm#44363
@owenca
Copy link
Contributor

owenca commented Oct 23, 2023

Please add unit tests in clang/unittests/Format/.

@owenca
Copy link
Contributor

owenca commented Oct 23, 2023

2th solution is: Add new option that allowing specific behaviour, such as "BreakAfterStreamOperator" or "BreakAfterLessLessOperator" with options [ Leave | NoFitLine | All ].

We need a comprehensive solution to cover the following:

  • when to break
  • before or after the operator
  • indenting or aligning
  • binpack or one per line
  • whether to break after a newline (\n, endl, etc.)

@HazardyKnusperkeks
Copy link
Contributor

What Owen says. And given that the modified lines were removed, maybe the issue(s) are also gone?

To the review unrelated, why didn't it get the @llvm/pr-subscribers-clang-format thing?

@s1Sharp
Copy link
Author

s1Sharp commented Oct 24, 2023

yes, issue with breaking after << is gone. I want to get your point about functionality clang-format and implementing new option such as "BreakAfterStreamOperator". As i can see, @HazardyKnusperkeks you agree with "owenca" point?

May be i can do something with this feature

@HazardyKnusperkeks
Copy link
Contributor

yes, issue with breaking after << is gone. I want to get your point about functionality clang-format and implementing new option such as "BreakAfterStreamOperator". As i can see, @HazardyKnusperkeks you agree with "owenca" point?

May be i can do something with this feature

You are welcome to try. I'd go with the name BreakAfterOperatorLessLess. You need:

  • The definition in FormatStyle.h.
  • The documentation. (Run clang/doc/tools/dump_format_style.py)
  • The parsing.
  • The default value for LLVMStyle which does not change any current behavior.
  • Tests which show various combinations of the option, with comments, and long lines.
  • Consider the interaction with BreakBeforeBinaryOperators.

You can of course start with documentation and/or tests to show how you think it will work, even if you did not try to implement it.

@kadircet
Copy link
Member

kadircet commented Jan 3, 2024

@s1Sharp are there any conclusions here? our code also incidentally relied on having new lines between string literals, mostly for the sake of having a line break after string literals that end with \n.

what do people think about restoring the functionality to break after string literals that end with \n?
https://github.com/search?q=%2F%5C%5Cn%5C%22%5Cn%5Cs*%3C%3C%5C+%5C%22%2F+language%3AC%2B%2B+&type=code&ref=advsearch shows a lot of examples of such pattern, so i feel like having that without an option initially easy relatively easy and likely to preserve clang-format's behavior for a lot of existing code for the next release. afterwards we can discuss introducing more options again.

@kadircet
Copy link
Member

kadircet commented Jan 3, 2024

sent out #76795 for implementation

@s1Sharp
Copy link
Author

s1Sharp commented Jan 3, 2024

@s1Sharp are there any conclusions here? our code also incidentally relied on having new lines between string literals, mostly for the sake of having a line break after string literals that end with \n.

what do people think about restoring the functionality to break after string literals that end with \n? https://github.com/search?q=%2F%5C%5Cn%5C%22%5Cn%5Cs*%3C%3C%5C+%5C%22%2F+language%3AC%2B%2B+&type=code&ref=advsearch shows a lot of examples of such pattern, so i feel like having that without an option initially easy relatively easy and likely to preserve clang-format's behavior for a lot of existing code for the next release. afterwards we can discuss introducing more options again.

First, I want to show how this works with the current code.
As an example, here are a couple of output statements.

.clang-format:

Language: Cpp
BasedOnStyle: Google

IndentWidth: 4

ColumnLimit: 70

before clang-format:

  cout << "hello\n" << "World\n" << "HELLO" << "world" << "hello" << "World" << "HELLO" << "world" << "hello" << "World" << "HELLO" << "world";

  cout << "hello" << std::endl << "World" << "hello" << '\n' << "another hello" << "world";

  cout << "hello\n"
       << "World" << std::endl
       << "HELLO" << "world";

after clang-format:

    cout << "hello\n"
         << "World\n"
         << "HELLO" << "world" << "hello" << "World" << "HELLO"
         << "world" << "hello" << "World" << "HELLO" << "world";

    cout << "hello" << std::endl
         << "World" << "hello" << '\n'
         << "another hello" << "world";

    cout << "hello\n" << "World" << std::endl << "HELLO" << "world";

A bit unexpected results, right? Formatting applies to single-line expressions and breaks to another line after the \n and std::endl characters. And if the code has already been manually formatted (as in 3rd cout), then clang-format groups this code into a single-line expression.

I agree with your suggestion that to maintain compatibility with the old behavior of clang-format.

kadircet added a commit to kadircet/llvm-project that referenced this pull request Jan 4, 2024
This restores a subset of functionality that was forego in
d68826d.

Streaming multiple string literals is rare enough in practice, hence
that change makes sense in general. But it seems people were
incidentally relying on this for having line breaks after string
literals that ended with `\n`.

This patch tries to restore that behavior to prevent regressions in the
upcoming LLVM release, until we can implement some configuration based
approach as proposed in llvm#69859.
kadircet added a commit that referenced this pull request Jan 8, 2024
…76795)

This restores a subset of functionality that was forego in
d68826d.

Streaming multiple string literals is rare enough in practice, hence
that change makes sense in general. But it seems people were
incidentally relying on this for having line breaks after string
literals that ended with `\n`.

This patch tries to restore that behavior to prevent regressions in the
upcoming LLVM release, until we can implement some configuration based
approach as proposed in #69859.
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
…lvm#76795)

This restores a subset of functionality that was forego in
d68826d.

Streaming multiple string literals is rare enough in practice, hence
that change makes sense in general. But it seems people were
incidentally relying on this for having line breaks after string
literals that ended with `\n`.

This patch tries to restore that behavior to prevent regressions in the
upcoming LLVM release, until we can implement some configuration based
approach as proposed in llvm#69859.
@mydeveloperday
Copy link
Contributor

closed due to inactivity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants