This is an archive of the discontinued LLVM Phabricator instance.

Fix bug in clang-format while merging short function (PR19461)
ClosedPublic

Authored by dinesh.d on Apr 21 2014, 6:33 AM.

Details

Summary

if Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All, clang-format tries to join short functions and prints in single line.
This code was not taking care of cases where there is something in between function header and body e.g. attached test cases where
there are preprocessor directives in between function header and body.

Attached patch fixes this issue by checking if we have both header and body and nothing between them while trying to merge functions.

Please let me know if this is ok.

Diff Detail

Event Timeline

dinesh.d added a comment.EditedApr 24 2014, 3:27 AM

Hi Klimek,

Thanks for review.

With this change, I am trying to figure out whether there is a "gap" in the line.
If this gap is just white spaces, that is not an issue and we can still merge
function. But if there are other constructs such as preprocessor directives, we
should not merge this function to single line.

During debugging, I have observed that if there are other constructs, block before
and after the construct (inclusive) are handled separately [Basically, I am trying
to say is I found TheLine->MustBeDeclaration to be false for 'after' block in such
cases]. I assumed, just checking for this case is good enough, as asserted from
test cases too.

If you think this is not correct, I will look in to code and try to find better fix.

Regards

  • updated comment for typos

Hi Klimek,

Thanks for review.

With this change, I am trying to figure out whether there is a "gap" in the line.
If this gap is just white spaces, that is not an issue and we can still merge
function. But if there are other constructs such as preprocessor directives, we
should not merge this function to single line.

During debugging, I have observed that if there are other constructs, block before
and after the construct (inclusive) are handled separately [Basically, I am trying
to say is I found TheLine->MustBeDeclaration to be false for 'after' block in such
cases]. I assumed, just checking for this case is good enough, as asserted from
test cases too.

If you think this is not correct, I will look in to code and try to find better fix.

Regards

dinesh.d updated this revision to Diff 8846.Apr 25 2014, 7:14 AM
dinesh.d edited edge metadata.

Update patch to check First->MustBreakBefore of every line before joining them.

I have updated patch as per you comment. I am checking for MustBreakBefore for
only first token of every line. I was just wondering if AnnotatedLine can have
MustBreakBefore flag set for some internal token and how we honour it while
formatting the line.

Can an AnnotatedLine have MustBreakBefore flag set for internal tokens as well?
If so, then we have to check this flag for all tokens and their children. Will
it be ok to add a 'IsJoinable' flag in AnnotatedLine and set it accordingly
while constructing AnnotatedLine.

djasper added inline comments.Apr 28 2014, 1:05 AM
lib/Format/Format.cpp
641

Why would it be a problem if we need to wrap before the first of the lines we are going to join. I think the test case passes for the wrong reason. Of course MustBreakBefore is set for the first token of:

"void foo().."

But that is not the point. We are actually interested at whether there is any token other than the first where MustBreakBefore is set (the "{" in the case of the test).

664

How about we put this check into "nextTwoLinesFitInto"?

dinesh.d updated this revision to Diff 8886.Apr 28 2014, 7:15 AM

The problem is due to code 'I[1]->First->Type == TT_FunctionLBrace' [Format.cpp:562]
where we assume that I[0] contains something which we can join with rest of the lines.
I have experimented with logic to check flags for all token in lines being merged
except first token for MustBreakBefore flags and they cause other side effects while
solving this problem.

I have re-placed check for First->MustBreakBefore from 'tryMergeSimpleBlock()' to
'tryFitMultipleLinesInOne()' so it will only take effect for above case. I have updated
test cases to check for even more conditions.

djasper edited edge metadata.Apr 28 2014, 7:38 AM

Ah right, this is for styles that break before the braces (I got confused).

Two small comments, otherwise this seems like a strict improvement now.

lib/Format/Format.cpp
562

How about moving the MustBreakBefore check to line 535, i.e.:

if (I + 1 == E || I[1]->Type == LT_Invalid || I[1]->MustBreakBefore)
  return 0;

I think it is trivially correct and much easier to see that I[1] is guaranteed to exist.

unittests/Format/FormatTest.cpp
7365

Can you split these into smaller verifyFormat() calls that test each case (or smaller group of cases)? It has proven to be much easier to figure out what is going wrong if the tests are as small as possible. Otherwise you get a large diff in the test output and can't easily see what is going on. Same below.

dinesh.d updated this revision to Diff 8891.Apr 28 2014, 11:17 AM
dinesh.d edited edge metadata.

Updated as per review comments.

I have moved 'I[1]->First->MustBreakBefore' check to line 535. I agree that this is good as there are other check for I[1] but this check is actually required in context at for block of lines 554:570. For lines between 535:554, it is redundant check as this condition is already being checked in tryMergeSimpleBlock().

djasper accepted this revision.May 5 2014, 2:46 AM
djasper edited edge metadata.

A few indentations aside, this looks good.

unittests/Format/FormatTest.cpp
7477

The indentation here is off. Maybe use clang-format ;-).

7487

Same here.

7628

Same here.

7638

Same here.

This revision is now accepted and ready to land.May 5 2014, 2:46 AM
dinesh.d updated this revision to Diff 9067.May 5 2014, 4:32 AM
dinesh.d edited edge metadata.

updated patch to fix formating

submitted (r207958)

Thanks for review and support

dinesh.d closed this revision.May 5 2014, 4:47 AM