This is an archive of the discontinued LLVM Phabricator instance.

[clang-format] Add an experimental option to remove optional control statement braces in LLVM C++ code
ClosedPublic

Authored by owenpan on Dec 27 2021, 9:44 AM.

Details

Summary

See the LLVM style examples. This option can be expanded/configured to support other styles.

Diff Detail

Event Timeline

owenpan requested review of this revision.Dec 27 2021, 9:44 AM
owenpan created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptDec 27 2021, 9:45 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript

Could you have a look at preceding reviews and see if there wasn't a similar patch before?
I think that this option is a bit too limited.
Only removing braces doesn't seem enough.
Also, one should probably be able to decide when to add/remove them by e.g. setting the number of lines in what's considered short blocks.

clang/docs/ClangFormatStyleOptions.rst
3405

I don't think it's a good idea to make this option dependent on a particular style. Even if it works for LLVM style only for the moment.

3426

I'm not sure if the braces on the right should be removed in the for loop.
There should probably be an option to set the minimum number of lines/statements inside a control statement to control adding/removing braces.

Could you have a look at preceding reviews and see if there wasn't a similar patch before?
I think that this option is a bit too limited.
Only removing braces doesn't seem enough.
Also, one should probably be able to decide when to add/remove them by e.g. setting the number of lines in what's considered short blocks.

There is D95168.

clang/lib/Format/UnwrappedLineParser.cpp
500

This is very confusing a variable with the same name as the function.

2217

constexpr or configurable?

2410

I think it is worth to create a RAII type for that.

3019

I would like it better if you insert both arguments.
I don't really like default arguments.

clang/lib/Format/UnwrappedLineParser.h
199

I find it nicely if the order of functions in the cpp is the same as in the hpp.

200
owenpan added inline comments.Dec 28 2021, 2:09 PM
clang/docs/ClangFormatStyleOptions.rst
3426

I'm not sure if the braces on the right should be removed in the for loop.

This is the LLVM style. See also line 23086 in FormatTest.cpp below.

There should probably be an option to set the minimum number of lines/statements inside a control statement to control adding/removing braces.

If you have more than one statement inside a control statement block, the braces must stay.

owenpan updated this revision to Diff 396493.Dec 29 2021, 12:01 AM

Addresses review comments.

owenpan marked 4 inline comments as done.Dec 29 2021, 12:20 AM
owenpan added inline comments.
clang/lib/Format/UnwrappedLineParser.cpp
2217

It will be configurable when we expand removing braces to other styles.

2410

Can you explain why an RAII type would be beneficial here?

3019

I'm the opposite, and parseBlock()is a good example. However, I restored the previously non-default argument.

clang/lib/Format/UnwrappedLineParser.h
199

Me too although some of the functions (e.g. parseCSharpGenericTypeConstraint and parseCSharpAttribute) were already out of order.

owenpan marked 2 inline comments as done.Dec 29 2021, 12:48 AM

Could you have a look at preceding reviews and see if there wasn't a similar patch before?

I conversed with @MyDeveloperDay in D95168. In fact, that was one of the main reasons that I put in extra effort to get this patch done.

I think that this option is a bit too limited.
Only removing braces doesn't seem enough.

I wanted to implement as many features as possible using the limited parser of clang-format, and the LLVM style would be a very high bar to clear. Only focusing on LLVM now will actually make this option less limited if and when we are ready to support other styles. It would be mostly configuring/packaging what have already worked for LLVM.

Also, one should probably be able to decide when to add/remove them by e.g. setting the number of lines in what's considered short blocks.

Agreed, but if clang-format can't do insertion well independent of removal and vice versa, we probably will never get there.

So far, this patch has successfully applied to clang/lib/Format, i.e., it builds successfully and passes FormatTests.

MyDeveloperDay added inline comments.Dec 29 2021, 6:15 AM
clang/docs/ClangFormatStyleOptions.rst
3405

Can we agree on one set of options that can be used for both insertion and removal even if this patch only does removal

clang/unittests/Format/FormatTest.cpp
23529

any reason these can't be verifyFormats?

clang/lib/Format/UnwrappedLineParser.cpp
2410

You have a lot of push/pop pairs. There is the risk someone (in the future) may misuse it.

owenpan updated this revision to Diff 396573.Dec 29 2021, 2:37 PM

Fixed a bug and added a test case.

clang/lib/Format/UnwrappedLineParser.cpp
2356

Why null that?

owenpan added inline comments.Dec 29 2021, 4:50 PM
clang/docs/ClangFormatStyleOptions.rst
3405

I don't think it's a good idea to make this option dependent on a particular style. Even if it works for LLVM style only for the moment.

As @MyDeveloperDay said before, eliding braces was (by far?) the most frequent review comments, and the community would appreciate something like this. So it's likely that this option will get used and experimented, and we will get bug reports and other feedback to improve the functionalities. Once we think it's ready, we can easily configure/package the functionalities for other styles.

3405

Can we agree on one set of options that can be used for both insertion and removal even if this patch only does removal

One idea is to run insertion for all missing braces and then this option to remove the optional ones for LLVM, i.e., an AutomaticBraces if you will.

clang/lib/Format/UnwrappedLineParser.cpp
2410

I see. I will think about it.

clang/unittests/Format/FormatTest.cpp
23529

Did you mean to add the expected part as a separate case? I don't think it would add any value if there are no braces to remove in the first place?

owenpan added inline comments.Dec 29 2021, 5:07 PM
clang/lib/Format/UnwrappedLineParser.cpp
2356

MatchingParen is used to flag braces that may be optional. If it turns out that they should not be removed, we must reset it. Otherwise, the test case on line 23314 in FormatTest.cpp below would fail.

owenpan added inline comments.Dec 29 2021, 10:39 PM
clang/unittests/Format/FormatTest.cpp
23529

Did you mean to add the expected part as a separate case? I don't think it would add any value if there are no braces to remove in the first place?

Nvm. I think you wanted something like verifyFormat(PostformatCode, PreformatCode, Style)? Yes, I could do that, but I would have to relax the restriction to calling BracesRemover() in Format.cpp, i.e. checking isCpp() instead.

clang/lib/Format/UnwrappedLineParser.cpp
2356

Is MatchingParen for (if) braces null before this patch? Because I would expect that always to be set, if there is a matching brace and maybe base patches on that assumption.

owenpan added inline comments.Dec 30 2021, 3:31 PM
clang/lib/Format/UnwrappedLineParser.cpp
2356

Yes, it's not set until it's in the token annotator. That's why I added the assertion in the annotator.

owenpan updated this revision to Diff 397184.Jan 3 2022, 7:27 PM
  • Fixed a bug found by applying the patch on the entire clang source tree.
  • Added an exception: the braces are not removed if the right one is followed by a comment on the same line.
  • Updated an existing test case and added a new one.
owenpan updated this revision to Diff 397783.Jan 5 2022, 8:49 PM

Fixing a couple of major bugs found by running check-clang plus minor bug fixes and cleanup:

  • In parseLevel(), HasOpeningBrace and case tok::r_brace: don't necessarily mean the tokens are { and }, respectively.
  • A pair of braces may be subject to removal even if the } is followed by a non-trailing comment.
  • The newline before a wrapped { should be deleted when removing the braces.
  • precededByCommentOrPPDirective() should be a const member function.
  • The assertion that a { of a control statement block is not parsed more than once is false.

Now this patch not only successfully builds clang but also passes check-clang (by not failing more tests than the current clang-format).

MyDeveloperDay accepted this revision.Jan 6 2022, 1:32 AM

Owen I think we should push ahead with this rather than D95168: [clang-format] Add Insert/Remove Braces option as I've looked at what you've done here I'm reminded that the removal and insertion are likely mutually exclusive operations.

There is no doubt that insertion is desired (so I'd like to see us do that afterwards) but I now think that could be in a completely separate pass as you originally suggested.

LGTM

This revision is now accepted and ready to land.Jan 6 2022, 1:32 AM

Owen I think we should push ahead with this rather than D95168: [clang-format] Add Insert/Remove Braces option as I've looked at what you've done here I'm reminded that the removal and insertion are likely mutually exclusive operations.

There is no doubt that insertion is desired (so I'd like to see us do that afterwards) but I now think that could be in a completely separate pass as you originally suggested.

LGTM

Thanks! I will wait a couple of days in case other reviewers have some final requests.

curdeius accepted this revision.Jan 6 2022, 3:10 AM

LGTM with some nits.

clang/lib/Format/UnwrappedLineParser.cpp
433–474

Please remove unused code.

501

Please remove unused code.

clang/unittests/Format/FormatTest.cpp
23529

👍 you should be able to use the 2-argument version of verifyFormat, no?

owenpan added inline comments.Jan 7 2022, 1:14 AM
clang/lib/Format/UnwrappedLineParser.cpp
433–474

Will do pending D116318.

501

Will do.

clang/unittests/Format/FormatTest.cpp
23529

Will replace all EXPECT_EQs with verifyFormats. Question: when is the former preferred to the latter? It seems EXPECT_EQ is frequently used in FormatTest.cpp.

owenpan updated this revision to Diff 398231.Jan 7 2022, 1:59 PM
  • Use verifyFormat instead of EXPECT_EQ.
  • Make this option have less impact on the unwrapped line parser by checking Style.RemoveBracesLLVM.
  • Remove some unused code.
owenpan marked 3 inline comments as done.Jan 7 2022, 2:03 PM
owenpan updated this revision to Diff 398308.Jan 7 2022, 10:17 PM
  • Rebased to main.
  • Removed unused code.
  • Updated release notes.
owenpan marked an inline comment as done.Jan 7 2022, 10:22 PM
owenpan updated this revision to Diff 398415.Jan 9 2022, 4:41 AM
  • Braces should not be removed if the single-statement block might wrap or is already wrapped.
  • Added test cases.
  • Did a final round of cleanup.
owenpan updated this revision to Diff 398419.Jan 9 2022, 5:12 AM

Fixed a bug and added a test case.

owenpan planned changes to this revision.Jan 9 2022, 2:51 PM
owenpan updated this revision to Diff 398860.Jan 11 2022, 12:20 AM
  • Removed unnecessary code and cleaned up.
  • Tested on clang and check-clang again.
This revision is now accepted and ready to land.Jan 11 2022, 12:20 AM
owenpan requested review of this revision.Jan 11 2022, 2:49 AM
clang/include/clang/Format/Format.h
3054

This should be two warning blocks.

clang/lib/Format/UnwrappedLineParser.cpp
466

This should be an enum, a bool suggests that the return value is a failure/success indicator.

owenpan added inline comments.Jan 12 2022, 9:13 PM
clang/include/clang/Format/Format.h
3054

Can you elaborate? I simply copied the format of the existing warning block. The alignment of the \code block below is off by 1 though.

clang/lib/Format/UnwrappedLineParser.cpp
466

Most of the parse...() functions return void with no indication of pass/fail. Some of them return bool, e.g. parseObjCProtocol(), which doesn't indicate pass/fail according to the function header comment. I will add a similar comment.

HazardyKnusperkeks resigned from this revision.Jan 13 2022, 12:18 AM
HazardyKnusperkeks added inline comments.
clang/include/clang/Format/Format.h
3054

One Warning that the option is going to be renamed.

The other warning regarding the code changes.

clang/lib/Format/UnwrappedLineParser.cpp
466

Yeah I'm out here.

owenpan updated this revision to Diff 399632.Jan 13 2022, 4:24 AM
  • Rebased to main.
  • Addressed review comments.
owenpan marked 2 inline comments as done.Jan 13 2022, 4:26 AM
owenpan updated this revision to Diff 399869.Jan 13 2022, 7:29 PM
  • Fixed a bug that missed braces in nested blocks.
  • Added a test case.

@MyDeveloperDay @curdeius I will land this patch if you have no more comments. :)

curdeius accepted this revision.Jan 14 2022, 3:21 AM

LGTM.

clang/docs/ClangFormatStyleOptions.rst
3405

Have you agreed upon this?

This revision is now accepted and ready to land.Jan 14 2022, 3:21 AM
owenpan added inline comments.Jan 14 2022, 3:28 AM
clang/docs/ClangFormatStyleOptions.rst
3405

Not yet. We probably want to test inserting braces Always on check-clang if it's not already been done.

MyDeveloperDay accepted this revision.Jan 14 2022, 8:40 AM

LGTM go for it.