Page MenuHomePhabricator

[clang-format] add option for dangling parenthesis
Needs ReviewPublic

Authored by stringham on May 9 2017, 9:47 PM.
Tags
  • Restricted Project
  • Restricted Project
Tokens
"Like" token, awarded by budnyjj."Love" token, awarded by Blackhex."Love" token, awarded by iolojz."100" token, awarded by PhilDakinOcient."Love" token, awarded by samwalls."Love" token, awarded by Tiedye."Love" token, awarded by JPMMaia."Love" token, awarded by njaldea."Love" token, awarded by glfmn."Mountain of Wealth" token, awarded by aaptho."Love" token, awarded by teohhanhui."Like" token, awarded by quezak."Love" token, awarded by mdrohmann."Love" token, awarded by mmpestorich."Love" token, awarded by mnemotic."Like" token, awarded by msafi."Like" token, awarded by nyaapa."Love" token, awarded by fdwr."Mountain of Wealth" token, awarded by paulreimer."Like" token, awarded by reupen."Like" token, awarded by hyldmo."Like" token, awarded by Rapatas."Like" token, awarded by fiblit."Like" token, awarded by dmcyk."Like" token, awarded by tadeu."Like" token, awarded by DevAlone."Like" token, awarded by sciencemanx."Like" token, awarded by catskul."Like" token, awarded by kc9jud."Like" token, awarded by zroug."Like" token, awarded by VZ."Like" token, awarded by jtbandes.

Details

Summary

This adds an option to clang-format to support dangling parenthesis.

If you have a parameter list like

Foo(
    param1,
    param2,
    param3,
);

clang-format currently only supports putting the closing paren on the same line as param3:

Foo(
    param1,
    param2,
    param3, );

This makes it difficult to see the change from the function signature to the function body, for example:

class Foo extends Bar {
    constructor(
        param1,
        param2,
        param3, ) {
        super(param1, 'x');
        this.param2 = param2;
    }
}

would now be formatted like:

class Foo extends Bar {
    constructor(
        param1,
        param2,
        param3, 
    ) {
        super(param1, 'x');
        this.param2 = param2;
    }
}

and it is much easier to see the difference between the parameter list and the function body.

Diff Detail

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
VZ added a subscriber: VZ.Oct 13 2018, 8:40 AM
kc9jud awarded a token.Nov 8 2018, 3:40 PM
kc9jud added a subscriber: kc9jud.

@djasper bump -- this feature is also really important to our team.

catskul rescinded a token.
catskul awarded a token.
DevAlone added a subscriber: DevAlone.

So, will it be added?

dmcyk awarded a token.Dec 11 2018, 7:44 AM
dmcyk added a subscriber: dmcyk.
reupen added a subscriber: reupen.Dec 11 2018, 12:31 PM
fiblit added a subscriber: fiblit.
Rapatas added a subscriber: Rapatas.
hyldmo added a subscriber: hyldmo.
paulreimer added a subscriber: paulreimer.

This review lack unit tests, please add some for FormatTest to show its use cases, otherwise someone else will come along and break this later

@MyDeveloperDay I am happy to write unit tests and clean up the change set but I don't want to spend more time on this if it has no chance of being merged.

I am looking for some agreement that this feature is worth adding to clang format and then I'd like to know that my general solution is reasonable and agree on what we should call the option.

Currently, we're just using a fork with this patch applied. It would be nice to get the changes merged upstream, but I don't know how to make that happen.

Adding the unit tests lets us see how this option will work in various cases, it will let us understand that its not breaking anything else.

I personally don't like to see revisions like this sit for 2 years with nothing happening, I don't see anything wrong with this that would prevent it going in so I don't understand whats blocking it?,

if you had some tests and a release note I'd give it a LGTM (but as I've said before I'm not the code owner, but someone wanting to address defects and add capabilities. but I think we need to be able to move forward, people will object soon enough if they don't like it.)

Generally I don't understand why clang-format is so reluctant to change anything, As such we don't have many people involved and getting anything done (even defects) is extremely hard.

It looks like you met the criteria, and reviewers have been given ample opportunity to make an objection. the number of subscribers and like tokens would suggest this is wanted,

Please also add a line the in the release notes to say what you are adding. In the absence of any other constructive input all we can do is follow the guidance on doing a review, for what its worth I notice in the rest of LLVM there seems to be a much larger amount of commits that go in even without a review, I'm not sure what makes this area so strict, so reluctant to change especailly when revisions do seem to be reviewed.

Adding the unit tests lets us see how this option will work in various cases, it will let us understand that its not breaking anything else.

I personally don't like to see revisions like this sit for 2 years with nothing happening, I don't see anything wrong with this that would prevent it going in so I don't understand whats blocking it?,

if you had some tests and a release note I'd give it a LGTM (but as I've said before I'm not the code owner, but someone wanting to address defects and add capabilities. but I think we need to be able to move forward, people will object soon enough if they don't like it.)

Generally I don't understand why clang-format is so reluctant to change anything, As such we don't have many people involved and getting anything done (even defects) is extremely hard.

It looks like you met the criteria, and reviewers have been given ample opportunity to make an objection. the number of subscribers and like tokens would suggest this is wanted,

Please also add a line the in the release notes to say what you are adding. In the absence of any other constructive input all we can do is follow the guidance on doing a review, for what its worth I notice in the rest of LLVM there seems to be a much larger amount of commits that go in even without a review, I'm not sure what makes this area so strict, so reluctant to change especailly when revisions do seem to be reviewed.

I don't have any stake here, but i just want to point out that no tool (including clang-format)
will ever support all the things all the people out there will want it to support. But every
new knob is not just a single knob, it needs to work well with all the other existing knobs
(and all of the combination of knob params), and every new knob after that.

It's a snowball effect. Things can (and likely will, unless there is at least a *very* strict testing/quality policy
(which is https://clang.llvm.org/docs/ClangFormatStyleOptions.html#adding-additional-style-options about))
get out of hand real quickly..

Just 2c.

MyDeveloperDay added a comment.EditedMar 10 2019, 6:23 AM

Adding the unit tests lets us see how this option will work in various cases, it will let us understand that its not breaking anything else.

I personally don't like to see revisions like this sit for 2 years with nothing happening, I don't see anything wrong with this that would prevent it going in so I don't understand whats blocking it?,

if you had some tests and a release note I'd give it a LGTM (but as I've said before I'm not the code owner, but someone wanting to address defects and add capabilities. but I think we need to be able to move forward, people will object soon enough if they don't like it.)

Generally I don't understand why clang-format is so reluctant to change anything, As such we don't have many people involved and getting anything done (even defects) is extremely hard.

It looks like you met the criteria, and reviewers have been given ample opportunity to make an objection. the number of subscribers and like tokens would suggest this is wanted,

Please also add a line the in the release notes to say what you are adding. In the absence of any other constructive input all we can do is follow the guidance on doing a review, for what its worth I notice in the rest of LLVM there seems to be a much larger amount of commits that go in even without a review, I'm not sure what makes this area so strict, so reluctant to change especailly when revisions do seem to be reviewed.

I don't have any stake here, but i just want to point out that no tool (including clang-format)
will ever support all the things all the people out there will want it to support. But every
new knob is not just a single knob, it needs to work well with all the other existing knobs
(and all of the combination of knob params), and every new knob after that.

It's a snowball effect. Things can (and likely will, unless there is at least a *very* strict testing/quality policy
(which is https://clang.llvm.org/docs/ClangFormatStyleOptions.html#adding-additional-style-options about))
get out of hand real quickly..

Just 2c.

Correct we should always be adding tests and show we don't break existing tests... We need to apply the "Beyonce Rule".. "if you liked it you should have put a test on it."

We shouldn't just give up making improvements or fixing defects because something is hard or complex.

Adding the unit tests lets us see how this option will work in various cases, it will let us understand that its not breaking anything else.

I personally don't like to see revisions like this sit for 2 years with nothing happening, I don't see anything wrong with this that would prevent it going in so I don't understand whats blocking it?,

if you had some tests and a release note I'd give it a LGTM (but as I've said before I'm not the code owner, but someone wanting to address defects and add capabilities. but I think we need to be able to move forward, people will object soon enough if they don't like it.)

Generally I don't understand why clang-format is so reluctant to change anything, As such we don't have many people involved and getting anything done (even defects) is extremely hard.

It looks like you met the criteria, and reviewers have been given ample opportunity to make an objection. the number of subscribers and like tokens would suggest this is wanted,

Please also add a line the in the release notes to say what you are adding. In the absence of any other constructive input all we can do is follow the guidance on doing a review, for what its worth I notice in the rest of LLVM there seems to be a much larger amount of commits that go in even without a review, I'm not sure what makes this area so strict, so reluctant to change especailly when revisions do seem to be reviewed.

I don't have any stake here, but i just want to point out that no tool (including clang-format)
will ever support all the things all the people out there will want it to support. But every
new knob is not just a single knob, it needs to work well with all the other existing knobs
(and all of the combination of knob params), and every new knob after that.

It's a snowball effect. Things can (and likely will, unless there is at least a *very* strict testing/quality policy
(which is https://clang.llvm.org/docs/ClangFormatStyleOptions.html#adding-additional-style-options about))
get out of hand real quickly..

Just 2c.

Correct we should always be adding tests and show we don't break existing tests... We need to apply the "Beyonce Rule".. "if you liked it you should have put a test on it."

We shouldn't just give up making improvements or fixing defects because something is hard or complex.

The problem is that clang-format is already at a complexity level where most patches for new things we see are overly complex and will make adding new things *even harder*, reducing the ability to move at all.
As I've written before, I agree that we're in a bad state, and I'm truly sorry for it - we need to get active contributors into a state where they can make changes aligned with the architectural spirit of clang-format, which make clang-format at least not more complex :)

For this specific patch, yes, please change it as djasper suggested to be configurable in the BracketAlignmentStyle.

fdwr added a subscriber: fdwr.Mar 15 2019, 6:34 PM
fdwr awarded a token.Mar 15 2019, 6:37 PM
nyaapa added a subscriber: nyaapa.
saki7 added a subscriber: saki7.Apr 10 2019, 6:50 PM
msafi awarded a token.Apr 25 2019, 6:38 AM
msafi added a subscriber: msafi.
mnemotic added a subscriber: mnemotic.
mdrohmann added a subscriber: mdrohmann.

Will this option also work with dangling braces from initializers?

I have some code that looks like this:

return some_type_with_a_long_name{
    get_param_number_one(),
    get_param_number_two()
};

Clang format will put the brace at the end of the line:

return some_type_with_a_long_name{
    get_param_number_one(),
    get_param_number_two()};

I would like to keep the style of the first snippet.

quezak added a subscriber: quezak.
teohhanhui added a subscriber: teohhanhui.
aaptho added a subscriber: aaptho.Aug 30 2019, 3:26 PM

@stringham you seemingly have marked this revision so that no one else can edit it, so I cannot add it to the clang-format project or reassign reviewers, could you please change it to be public, it also means others cannot request changes or approve it (if they wanted to)

MyDeveloperDay added a project: Restricted Project.Oct 6 2019, 1:30 PM

I'd like to assess where we are at with this revision, despite our concerns over additional complexity of clang-format, I don't think this is adding too much (I've seen far worse patches)

It appears to me that these changes are mainly in mustBreak,canBreak etc... however if you haven't added any unit tests I'm pretty sure things are going to go wrong when we run the other tests.

I'm not sure if you ever rebased with @mprobst changes or if those changes help you in any way

Given the level of likes of this feature, I think its worth at least looking at again, the quickness of your response yesterday suggests this might still be on your radar somewhere? it might be worth rebasing just to ensure it would go in cleanly, I could help by adding some unit tests if this is still of interest

MyDeveloperDay added a comment.EditedOct 8 2019, 10:46 AM

I tried the patch and rebased it locally

(as there were conflicts with the current trunk)

The change caused other tests to fail (which doesn't completely surprise me)

most tests failures look associated with positioning of trailing brace for example

@@ -1,4 +1,4 @@
 void f() {
   bar([]() {} // Did not respect SpacesBeforeTrailingComments
-  );
+ );
 }

Below is a list of the tests that fail

[==========] 700 tests from 21 test cases ran. (6687 ms total)
[  PASSED  ] 692 tests.
[  FAILED  ] 8 tests, listed below:
[  FAILED  ] FormatTest.WrapsTemplateDeclarations
[  FAILED  ] FormatTest.BreaksStringLiteralsWithin_TMacro
[  FAILED  ] FormatTest.FormatsLambdas
[  FAILED  ] FormatTest.WrappedClosingParenthesisIndent
[  FAILED  ] FormatTestJS.FunctionParametersTrailingComma
[  FAILED  ] FormatTestJS.FunctionLiterals
[  FAILED  ] FormatTestJS.ArrowFunctions
[  FAILED  ] FormatTestJS.NestedLiterals

 8 FAILED TESTS
glfmn added a subscriber: glfmn.
njaldea added a subscriber: njaldea.
JPMMaia added a subscriber: JPMMaia.
Tiedye added a subscriber: Tiedye.
iolojz added a subscriber: iolojz.EditedFeb 17 2020, 1:46 AM

Will this option also work with dangling braces from initializers?

I have some code that looks like this:

return some_type_with_a_long_name{
    get_param_number_one(),
    get_param_number_two()
};

Clang format will put the brace at the end of the line:

return some_type_with_a_long_name{
    get_param_number_one(),
    get_param_number_two()};

I would like to keep the style of the first snippet.

I would also love that (y)!

It should also be noted that the CLion formatter also supports this for all kinds of brackets (function declaration/call, template declaration/instantiation parameters, lambda capture lists, for statements, binary expressions as well as initializer lists).

bbassi added a subscriber: bbassi.Thu, Mar 26, 1:42 PM

@MyDeveloperDay Is someone working on fixing the breaking tests and merging it? I need this feature so if someone isn't working on it already, I can take it.

@bbassi, I don't have plans to address this, and am supportive of you finishing it up.

The plan was to move this as one of the options in the BracketAlignmentStyle configuration (value of AlwaysBreakWithDanglingParenthesis) rather than have it be a brand new config property.

So we need to do that switch, and write new tests for this feature.

@MyDeveloperDay Is someone working on fixing the breaking tests and merging it? I need this feature so if someone isn't working on it already, I can take it.

as @stringham isn't working on it feel free to take it. Include me as a reviewer and I'll try and give you a timely response.

@bbassi @MyDeveloperDay I'll buy whoever manages to land this feature a case of their favorite beer/beverage (max $50). Or $50 worth of girlscout cookies. : )

Just ping me when it lands and we can arrange the shipment.

Here's a commit rebased as of yesterday that is still adding DanglingParenthesis option instead of extending the BracketAlignmentStyle configuration.

https://github.com/lucidsoftware/llvm-project/commit/3c04de1feffaa9787234da8fe3cf288eebc979d6

@stringham @MyDeveloperDay I have some questions.

  • As some have pointed out DanglingParenthesis might be a confusing name, so should we try to call it something like BreakBeforeClosingBracket? When this option when is set to true we will always break before closing bracket.
  • My use case is slightly different. I want each argument/parameter on it's own line and always have a break after opening bracket and before closing bracket. In other words, I don't want it to try to bin packing at all. What do you think about incorporating that use-case in current one? or if that should be a separate change.
msafi removed a subscriber: msafi.Fri, Mar 27, 10:58 AM

I think that adding AlwaysBreakWithDanglingParenthesis as an option to BracketAlignmentStyle should not impact any of the binpacking settings - they should be distinct configuration.

I don't think that's quite right. Then you will also have to have a AlignWithDanglingParenthesis for cases when people still want closing parenthesis on new line but want parameters as well as closing parenthesis to be aligned with opening parenthesis. I think we need a separate option, something like BreakBeforeClosingBracket.

@MyDeveloperDay Can you please share your thoughts on my comment above?

I don't think that's quite right. Then you will also have to have a AlignWithDanglingParenthesis for cases when people still want closing parenthesis on new line but want parameters as well as closing parenthesis to be aligned with opening parenthesis. I think we need a separate option, something like BreakBeforeClosingBracket.

I think that's the biggest problem with making changes to Clang-Format, every name does things that the name doesn't imply.

Here it's very similar to the bin packing options, in my case it's BraceWrapping.AfterExternBlock also indenting by default, making adding a IndentExternBlock a real pain.

I personally say fuck backwards compatibility when maintaining it requires ever more workarounds to fix an obviously flawed abstraction, but I'm just some dude and AFAIK the guys in charge support the status quo.

I personally say fuck backwards compatibility when maintaining it requires ever more workarounds to fix an obviously flawed abstraction, but I'm just some dude and AFAIK the guys in charge support the status quo.

When LLVM itself isn't prepared to run clang-format over the the whole project because of the churn and the annoyance it would cause for existing forks and "git blame" (despite their being work around to ignore whitespace change commits), Then I feel we have to keep one eye on ensuring we allow people to incrementally upgrade their clang-format.

Even including a new option to the .clang-format file is a problem because it forces all users of that project to upgrade to a version of clang-format that recognises the option or clang-format will complain. With this in mind it means we need to allow existing users to use new binaries which where possible has zero changes to the code UNLESS they use the option. (even if that means many people delaying in using an option until its been supported for some time)

With Visual Studio and ClangPower tools always lagging behind the current capabilities due to the binaries they ship, we need to understand it may be a year+ before the majority of users are on a version that supports such changes.

Then we can multiply that annoyance to every other project using clang-format (both public and private projects), and so whilst a commit that changes such things are good by their own merit, that goodness might be lost in the noise of the complaints that come from time to time that clang-format causes huge changes version to version (even when those changes are bug fixes, let alone new features)

This is not about supporting the status quo, but about ensuring we aren't fairly/unfairly the brunt of peoples complaints. (https://travisdowns.github.io/blog/2019/11/19/toupper.html, http://lists.llvm.org/pipermail/cfe-dev/2017-June/054342.html)

@MyDeveloperDay Can you please share your thoughts on my comment above?

I'm tempted to agree that perhaps having as an enumeration BreakBeforeClosingBracket with various options might give us greater control

its recently also come to my attention that perhaps we should NEVER use a boolean as an option, as nearly every option that started out as a boolean ended up either needing to add another additional new option or being changed from a boolean to an enumeration later.