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
  • Restricted Project
Tokens
"Party Time" token, awarded by aminya."Love" token, awarded by saxbophone."Like" token, awarded by jeevcat."Doubloon" token, awarded by mjmaurer."Love" token, awarded by FederAndInk."Like" token, awarded by zvilius."Mountain of Wealth" token, awarded by ruzyysmartt."Love" token, awarded by GuillerLT."Love" token, awarded by orvar.karason."Love" token, awarded by loic-joly-sonarsource."Love" token, awarded by kuznetsss."Love" token, awarded by mgaunard."Love" token, awarded by Qub1."Like" token, awarded by thorbenk."Like" token, awarded by jakar."Love" token, awarded by kring."Like" token, awarded by Weyzu."Love" token, awarded by blandcr."Like" token, awarded by jj."Like" token, awarded by alex1701c."Like" token, awarded by Thyrum."Love" token, awarded by geckyan."Like" token, awarded by houbaron."100" token, awarded by njakob."Like" token, awarded by huyage."Love" token, awarded by Damio."Love" token, awarded by Folling."Love" token, awarded by rdaly525."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

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.

@MyDeveloperDay hey, I am currently working on this, and adding a new option called BreakBeforeClosingBracket. I have some questions to understand the existing code, they might not be directly linked to this change so I am not sure if this the best place to ask those questions. What do you think? e.g. I don't understand what FakeLParens is and have some questions about that.

Folling added a subscriber: Folling.

@MyDeveloperDay hey, I am currently working on this, and adding a new option called BreakBeforeClosingBracket. I have some questions to understand the existing code, they might not be directly linked to this change so I am not sure if this the best place to ask those questions. What do you think? e.g. I don't understand what FakeLParens is and have some questions about that.

@bbassi, you might want to consider starting a new revision if you are going to add a different option. Its probably best to discuss questions about adding that option in its own revision rather than confusing the conversation here. (you can always cross reference with a mention.

@MyDeveloperDay Thanks. This would be my first revision and I have few questions before I start coding. Would you be able to answer those over email? They are mainly about the design of clang-format and some existing options.

@MyDeveloperDay Thanks. This would be my first revision and I have few questions before I start coding. Would you be able to answer those over email? They are mainly about the design of clang-format and some existing options.

ask away

Damio awarded a token.May 22 2020, 3:48 PM
Damio added a subscriber: Damio.
detly added a subscriber: detly.Aug 3 2020, 5:55 PM
huyage added a subscriber: huyage.
njakob added a subscriber: njakob.
houbaron added a subscriber: houbaron.

@MyDeveloperDay I'm going to upload a re-based version of this. Should I rebase it off the top of master? Tip of 11? and/or create a new diff/review for each?

catskul added inline comments.Oct 25 2020, 9:15 PM
include/clang/Format/Format.h
793

@djasper I made the changes to @stringham's diff to implement your request to replace the bool with new item of BracketAlignmentStyle enum, and wondered if it might be backing us into a corner.

As strange as some of these may be I've seen a few similar to:

return_t myfunc(int x,
                int y,
                int z
                );
return_t myfunc(int x,
                int somelongy,
                int z         );
return_t myfunc(
             int x,
             int y,
             int z
         );

and even my least favorite

return_t myfunc(
    int x,
    int y,
    int z
                );

Without advocating for supporting all such styles it would seem desireable to avoid an NxM enum of two, at least theoretically, independent style parameters. With that in mind should I instead create a different parameter AlignClosingBracket with a respective enum which includes AfterFinalParameter by default, and NextLineWhenMultiline to handle the variations this diff was opened for?

On the other hand, I can just stick with adding a new variation to BracketAlignmentStyle and deal with potential variations in the future if they're requested.

jtbandes removed a subscriber: jtbandes.Oct 26 2020, 2:35 PM
Thyrum added a subscriber: Thyrum.
kring added a subscriber: kring.Dec 14 2020, 2:08 AM
jj awarded a token.Jan 17 2021, 9:28 AM
blandcr added a subscriber: blandcr.

Hi, this is a pretty desirable feature for me and I see there hasn't been any work for a few months. Is this still being worked on and/or is there anything I can do to help it along?

kring awarded a token.Mar 2 2021, 2:41 AM

If I understood it correctly there is a BraceWrapping group where BraceWrappingAfterControlStatementStyle AfterControlStatement is quite similar. It has a Never, MultiLine, and Always options. There is also a bool AfterFunction option which is currently only a bool. If it were changed to an enum it could provide this option as the MultiLine option. I do not really understand why there is a different option for control statements and functions though...

jakar awarded a token.Mar 22 2021, 4:17 PM
jakar added a subscriber: jakar.
jakar added a comment.Mar 23 2021, 9:43 AM

@catskul can you share your changes somehow? If you did, sorry, I'm new to Phabricator.

Before I saw @catskul's comment, I rebased @stringham's diff and got the existing unit tests to work. But after some experimentation, I found that it didn't always behave like I expected. It would sometimes do things like this:

someFunction(anotherLongFunctionName(arg1, arg2, "this is a description")
);

void SomeClass::someMemberFunction(const std::string& whatever, int blah
) const {
}

I think it should only break before closing when the matching opening was followed by a new line (with possible whitespace or comment).

And it also didn't handle brace-initialized vars consistently:

LongClassName longVarName1(
  somethingElseThatIsLong(arg1, arg2, arg3, arg4),
  anotherLongVarName
);

LongClassName longVarName2{
  somethingElseThatIsLong(arg1, arg2, arg3, arg4),
  anotherLongVarName};

So I think there is still a bit of work here to be done. And unit tests could definitely help.

I can take my best stab at this, when I get time, but I'm honestly not familiar with any of it. Any suggestions would be great. Please let me know how I can help.

Anyhow, I'm excited about this feature, mostly because I find it more readable, but also because it allows consistency with other languages, like Python (see PEP8):

my_list = [
    1, 2, 3,
    4, 5, 6,
]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)
thorbenk added a subscriber: thorbenk.
wmmc88 added a subscriber: wmmc88.Apr 8 2021, 10:51 AM
Qub1 awarded a token.Apr 20 2021, 4:51 AM
Qub1 added a subscriber: Qub1.

@jakar I did a bit of sleuthing (google catskul github, which I feel a little weird about but whatever) and I think I found their changes in a fork:
https://github.com/catskul/llvm-project/tree/catskul/dangling-parenthesis-as-bracket-alignment
It seems there are a few different branches that might be what you're looking for. I think what probably happened was they never received a response for what to rebase the changes off of so this end up falling by the wayside.

@catskul I'm not sure what the proper etiquette is for this kind of searching but given the easily associated identity I'm going to assume it's probably OK. If you do want me to edit the comment to remove the link to your GH profile just let me know.

catskul added a comment.EditedMay 6 2021, 10:02 AM

@blandcr @jakar It's all good for me. Sorry for slow responses. My time to work on this is few and far between. I'm happy if anyone picks it up or any energy put into this. Would love to see it land.

mgaunard added a subscriber: mgaunard.
seesemichaelj added inline comments.
include/clang/Format/Format.h
793

@catskul, are we waiting for a response from @djasper (or other maintainer) concerning your last question about whether or not to keep BracketAligngmentStyle or to use a new parameter AlignClosingBracket that you proposed? I'm just throwing my hand in the pile seeing what I can do to help push this issue towards landing without creating duplicate work (or just forking your code and compiling it for myself selfishly haha).

From what information I can gather, it sounds like you have a solution @catskul that meets the requested changes by @djasper, and if those changes are still desired provided your last comment here, a revision could be posted for review (after rebase, tests pass, etc).

Am I understanding correctly here?

zvilius added a subscriber: zvilius.
FederAndInk added a subscriber: FederAndInk.
mjmaurer added a subscriber: mjmaurer.
jeevcat added a subscriber: jeevcat.

@catskul yeah, are we waiting for a response, or is this good to go?

Tagging everybody who might know something. @seesemichaelj @djasper @jakar @blandcr @MyDeveloperDay @bbassi

catskul added inline comments.Oct 13 2021, 9:22 AM
include/clang/Format/Format.h
793

@seesemichaelj (@Det87) Yes, though this diff belongs to @stringham I just jumped in to try to respond to @djasper's comments and keep the ball rolling.

I can post my changes that @blandcr and @jakar already found*, but would want to get the answer regarding AlignClosingBracket before putting any more energy into this as it's expensive to get spun back up and build all of this each time (I don't think I still have the build env around).

The second hurdle is that if I post a new diff I'm not sure if I'm adopting this whole thing and/or violating ettiquette, which I don't feel like I have the time & energy to do without some confidence that it will move forward.

Honestly I think the llvm project is leaving a lot of good work and good will on the table by how clumsy the contribution process is (partially because of how clumsy I feel like Phabricator is)

*https://github.com/catskul/llvm-project/commits/catskul/dangling-parenthesis-as-bracket-alignment

MyDeveloperDay added a subscriber: csmulhern.EditedOct 14 2021, 3:14 AM

I understand the frustration (I'm not convinced that its Phabricators fault to be honest, that's our process and plenty of people follow it without issues) , Our incredible original code owners have moved on to do I assume other things (rightly so as their contribution was already massive) and we are trying to hold the fort. But waiting for them to comment might mean you are waiting a long time.

We are tracking this work via D109557: Adds a BlockIndent option to AlignAfterOpenBracket which was an attempt to resuscitate this request. Honestly I'm grateful to @csmulhern for taking it on.

As this current review D33029 is 3 years since the last diff its hideously out of date and won't merge cleanly, It also is completely lacking in unit tests and that was always a massive "no-no"

I recommend we put our efforts into getting D109557 over the line? given that they have addressed those issues (I have given it an "Accept")

I'm was not a massive fan of the term DanglingParenthesis as a technical directive, and think BreakBeforeClosingParen from D109557 is a better name.

I have some reservations about the ) moving too much in my view on an if etc.. but as long as we can get a consensus as to what you all (I say all as this has 87 subscribers!) expect it to do I'm ok (as I won't be using this personally, I don't feel my opinion matters that much other than from a maintenance perspective! but I need those of you that will to comment if you don't like what its trying to do)

A good set of unit tests really helps to flesh this out.

void foo() {
  if (quitelongarg != (alsolongarg - 1)
  ) { // ABC is a very longgggggggggggg comment
    return;
  }
}

Its definitely not about about LLVM leaving good will on the table, its about having people being persistent enough to push it over the line (which believe me I recognize is difficult because lots of us have other jobs and do this in free time)

Contributors need to remain at the table long enough to finish the meal. There is a support burden that has to be considered especially 6 months down the line when the feature gets branched out and exposed to the masses,

But to be honest its not fair on those of us trying to look after it to just rock up every 6 months and ask why we've not pushed your feature over the line for you. You contribution is appreciated, but I would rather people hung out here a little longer.

My 2c worth.

@MyDeveloperDay Great, sounds like this revision, D33029, is stale and being superseded by the work in D109557. It doesn't sound like there is anyone here that is wanting to keep pushing forward this specific implementation at this point. I feel like any debates on naming, and implementation can happen over at D109557 since that is recent and getting pushed forward.

I'm obviously not a maintainer, but I think it's totally fair at this point to just close this revision in favor of D109557, is this something you can do?

fdwr mentioned this in fdwr.Oct 14 2021, 5:07 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 29 2022, 12:09 AM