This is an archive of the discontinued LLVM Phabricator instance.

[clang-format] Fix formatting of the code that follows C# Lambda Expressions
ClosedPublic

Authored by peterstys on Dec 14 2021, 8:52 AM.

Details

Summary

The alignment fix introduced by https://reviews.llvm.org/D104388 caused a regression whereby formatting of code that follows the lambda block is incorrect i.e. separate expressions are put on the same line.

For example:

public void Test() {
  while (true) {
    preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());
    CodeThatFollowsLambda();
    IsWellAligned(); 
}

will be formatted as:

public void Test() {
  while (true) {
    preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());
    CodeThatFollowsLambda(); IsWellAligned(); 
}

The problem is that the "Fat arrow" token parsing inside the parseParens() function uses parseStructuralElement() which does not like to be called inside the parenthesis. It seems that code that follows is considered part of the parenthesis block.

As a fix, parseStructuralElement parser inside the parseParens() was replaced with parseChildBlock() if the following token was a "left brace" and nextToken() otherwise. Added few new unit tests to demonstrate the regressions.

Diff Detail

Event Timeline

peterstys requested review of this revision.Dec 14 2021, 8:52 AM
peterstys created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptDec 14 2021, 8:52 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
jbcoe added a reviewer: jbcoe.Dec 14 2021, 8:57 AM
jbcoe accepted this revision.Dec 14 2021, 9:55 AM
This revision is now accepted and ready to land.Dec 14 2021, 9:55 AM

Applied clang-formatting.

I tested this on the original code that made me make the original change, and I like your fix much better ;-)

Thank you for this patch, interested on working on other C# clang-format issues?

MyDeveloperDay set the repository for this revision to rG LLVM Github Monorepo.
MyDeveloperDay added a project: Restricted Project.
owenpan added inline comments.
clang/lib/Format/UnwrappedLineParser.cpp
2101

You already tested for C# on line 2004.

2103

Remove braces.

2106

Add braces after else to match if.

jbcoe added inline comments.Dec 14 2021, 2:43 PM
clang/lib/Format/UnwrappedLineParser.cpp
2100

I think this check for Style.isCSharp() is redundant as it's already checked above.

owenpan added inline comments.Dec 14 2021, 3:26 PM
clang/lib/Format/UnwrappedLineParser.cpp
2101

Actually, if (Style.BraceWrapping.AfterFunction) will do, i.e., == true is redundant.

peterstys retitled this revision from [clang-format] Code following C# Lambda Expressions has wrong formatting to [clang-format] Fix formatting of the code that follows C# Lambda Expressions .Dec 15 2021, 1:51 AM
peterstys updated this revision to Diff 394503.Dec 15 2021, 3:00 AM

Applied fixes suggested by the reviewers.

peterstys updated this revision to Diff 394505.Dec 15 2021, 3:03 AM
peterstys marked 4 inline comments as done.

Removed braces.

peterstys updated this revision to Diff 394506.Dec 15 2021, 3:05 AM
peterstys marked an inline comment as done.

I tested this on the original code that made me make the original change, and I like your fix much better ;-)

Thank you for this patch, interested on working on other C# clang-format issues?

Happy to help. My team is using clang-format to format our C# codebase and we have few more issues that we'd like to help fixing.

owenpan added inline comments.Dec 15 2021, 4:15 AM
clang/lib/Format/UnwrappedLineParser.cpp
1967–1968

Let's fix this too while we are at it. In the future, we may want to factor lines 1862-1874 and 2004-2009.

2102

Remove trailing whitespaces.

MyDeveloperDay added inline comments.Dec 15 2021, 4:20 AM
clang/lib/Format/UnwrappedLineParser.cpp
1967–1968

part of me thinks the MustBreakBefore should be handled separately in TokenAnnotator::mustBreakBefore() and let it do its stuff.

MyDeveloperDay added inline comments.Dec 15 2021, 4:22 AM
clang/unittests/Format/FormatTestCSharp.cpp
766

Nit: (only my preference) but I don't like the use of RawStrings in these tests (I know others have let them creep in) but I find them more unreadable because we lose the indentation.. I think I'm just so used to the other style that this just crates a little.

Just my personal preference (you can ignore)

peterstys marked 2 inline comments as done.

Created tryParseCSharpLambda function to avoid code duplication.

Thanks for factoring the code.

clang/lib/Format/UnwrappedLineParser.cpp
1949

Early return.

1967–1968

Yes, but we can take care of it in a separate patch.

clang/lib/Format/UnwrappedLineParser.h
141

To keep the naming consistent.

peterstys updated this revision to Diff 394802.Dec 16 2021, 2:57 AM
peterstys marked 4 inline comments as done.
peterstys added inline comments.
clang/lib/Format/UnwrappedLineParser.cpp
1967–1968

I used MustBreakBefore = true because the same method was used for the FatArrow processing on the lines 1862-1874 and it did the right thing i.e. added a new line before the block.

If you want me to change the code to use TokenAnnotator::mustBreakBefore() please provide more details on how to do it, or point me to some examples. I failed to find any good references, I'm afraid.

1967–1968

I extracted the C# lambda parsing block into a separate function to avoid repeating the same logic twice. Hope that is alright.

1967–1968

ACK

clang/unittests/Format/FormatTestCSharp.cpp
766

I used the RawStrings as it was very easy to copy snippet of code to a separate file so I could run clang-format on it to check all was working well. I also copied snippets to my local IDE to check if the file was building, or at least structurally okay (which I appreciate is not a requirements as clang-format does not build a complete AST of the code).

For example, I was surprised to see some sample code in unit tests missing braces after catch (Exception) statement (line 694) (which may have been intended). I find it slightly more difficult to read those code snippets if they are decorated with \n.

On the other hand, you're right, raw string break the indentation which is not great. Also, I'd rather follow the leading preferences (and wasn't sure which ones where they before your comment). I'm happy to update this to your style if that is the preference.

peterstys marked an inline comment as done.Dec 16 2021, 3:23 AM
peterstys added inline comments.
clang/unittests/Format/FormatTestCSharp.cpp
766

I tried to apply your preferred style but after running clang-format on the test file, many files were split which made it look much less readable, in my opinion. Here's an example:

verifyFormat(
    "public class Test\n"
    "{\n"
    "    private static void ComplexLambda(BuildReport protoReport)\n"
    "    {\n"
    "        allSelectedScenes =\n"
    "            "
    "veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds.Where("
    "scene => scene.enabled)\n"
    "                .Select(scene => scene.path)\n"
    "                .ToArray();\n"
    "        if (allSelectedScenes.Count == 0)\n"
    "        {\n"
    "            return;\n"
    "        }\n"
    "        Functions();\n"
    "        AreWell();\n"
    "        Aligned();\n"
    "        AfterLambdaBlock();\n"
    "    }\n"
    "}",
    MicrosoftStyle);

I think it makes it look cleaner and more readable if we stick to the raw string literals for my tests. WDYT?

peterstys added inline comments.Dec 16 2021, 3:25 AM
clang/unittests/Format/FormatTestCSharp.cpp
766

by "many files" I meant "many code snippets".

owenpan accepted this revision.EditedDec 16 2021, 3:32 AM

Thanks! LGTM other than the extraneous braces on lines 1859-1861. (See here.)

clang/lib/Format/UnwrappedLineParser.cpp
1949

Remove braces.

peterstys updated this revision to Diff 394814.Dec 16 2021, 3:54 AM
peterstys marked an inline comment as done.
MyDeveloperDay accepted this revision.Dec 16 2021, 7:30 AM
peterstys marked an inline comment as done.Dec 17 2021, 7:04 AM

This is my first PR into this repo. I'd like to learn more about the process of submitting patches, specifically about:

  • Do I need to get LGTM from all the reviewers before I can submit it?
  • There are some build failures on the CI, but look unrelated, do I force submit passed them?

Could someone help me with these questions or point me to the relevant documentation. Thanks.

This is my first PR into this repo. I'd like to learn more about the process of submitting patches, specifically about:

  • Do I need to get LGTM from all the reviewers before I can submit it?
No, one is likely enough, but employ some level of respect for others if they are commenting (they may not explicitly say LGTM but may accept)
  • There are some build failures on the CI, but look unrelated, do I force submit passed them?
They CI doesn't block commit. just check to ensure its not you, (there is some odd Go issue ATM which I've seen reported elsewhere)

Could someone help me with these questions or point me to the relevant documentation. Thanks.

https://llvm.org/docs/Contributing.html
https://llvm.org/docs/Phabricator.html

This is my first PR into this repo. I'd like to learn more about the process of submitting patches, specifically about:

  • Do I need to get LGTM from all the reviewers before I can submit it?
No, one is likely enough, but employ some level of respect for others if they are commenting (they may not explicitly say LGTM but may accept)
  • There are some build failures on the CI, but look unrelated, do I force submit passed them?
They CI doesn't block commit. just check to ensure its not you, (there is some odd Go issue ATM which I've seen reported elsewhere)

Could someone help me with these questions or point me to the relevant documentation. Thanks.

https://llvm.org/docs/Contributing.html
https://llvm.org/docs/Phabricator.html

Great. Thank you. Very helpful.

Regarding failing CI: it seems that the LLVM_ALL_PROJECTS in CMakeLists.txt miss "bolt" setting (line 67): set(LLVM_ALL_PROJECTS "clang;clang-tools-extra;compiler-rt;cross-project-tests;libc;libclc;libcxx;libcxxabi;libunwind;lld;lldb;mlir;openmp;polly;pstl")

Regarding committing the change: I won't have commit rights. Could someone do it for me?

Thank you for the patch We'll need your name and email address for that, but yes we'll be happy to commit it for you.

If you think you'd like to play some more, then you can apply for commit access. (not sure of the process for that now, but its probably in the documentation somewhere)

Thank you for the patch We'll need your name and email address for that, but yes we'll be happy to commit it for you.

If you think you'd like to play some more, then you can apply for commit access. (not sure of the process for that now, but its probably in the documentation somewhere)

Peter Stys
peterstys@google.com

Thank you!

This revision was landed with ongoing or failed builds.Dec 17 2021, 10:42 AM
This revision was automatically updated to reflect the committed changes.