-
-
Notifications
You must be signed in to change notification settings - Fork 73
Generic/InlineControlStructure: bail early for control structures without body #880
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
2f44e16
to
3f9b441
Compare
We discussed this PR in a call and as PHPCS 4.0 is coming closer and will drop JS support, it might well be better to leave this PR until the renewed 4.0 branch is public (and rebase the PR on that). Should also make reviewing easier as it reduces cognitive load as JS would no longer need to be considered. |
…hout body The sniff now consistently handles all supported control structures without a body by bailing early. Extending the existing behavior for `while` and `for` to also include `do while`, `else`, `elseif`, `if`, and `foreach`. Previously, the sniff would incorrectly flag these empty control structures as inline control structures that needed curly braces. For `else`, `elseif`, `if`, and `foreach`, the fixer would remove the semicolon and add the curly braces. For `do while`, the fixer would add the curly braces and keep the semicolon in between the braces. In all the cases, the resulting code was syntactically correct. Consider the following example: ``` do ; while ($foo < 5); ``` Previously, PHPCS would flag this as an inline control structure and PHPCBF would fix it to: ``` do { ; } while ($foo < 5); ``` Now an empty `do while` is ignored by the sniff (no warnings and no fixes). Here is a link showing that control structures without a body are valid in PHP: https://3v4l.org/slnYL And here is a link showing that the way that they were being fixed by PHPCBF was resulting in valid code (`while` and `for` are not included below as they were already ignored before this commit): https://3v4l.org/8k1N3
d4e5d28 changed the sniff to bail early for all control structures without body, so the code will never reach the fixer if `$closer + 1` is `T_SEMICOLON` and thus the removed condition is not necessary anymore.
The original version of this part of the code that is now being removed was added in the early days by the commit that enabled this sniff to fix errors: squizlabs/PHP_CodeSniffer@a54c619#diff-4b3945c2100b0a92a56509de1b797bf58ad804cf36233c95c492479b665655dcR148-R154 The only two tests that were added with the commit mentioned above that trigger the removed condition are tests using `while` loops without body: squizlabs/PHP_CodeSniffer@a54c619#diff-116c49a7b0b31f724fc25409e31ba119d7f023146818bcb63edbe8f4071422e2R42-R43 Control structures without a body are the only cases where `$next` would be equal to `$end`. Thus, these are the only cases where the removed condition would be executed. But two previous commits, changed the sniff to bail early and not get to the fixer part when handling control structures without a body. 13c803b changed the sniff to ignore `while`/`for` without a body and updated the existing tests (squizlabs/PHP_CodeSniffer@13c803b#diff-2f069f3fe33bacdfc80485b97303aec66c98c451d07e6d86e41982b81ab1a294L49-R50). d4e5d28 expanded the same approach for `do while`/`else`/`elseif`/`if`/`foreach` control structures. After the removal of the `$next !== $end` check, the `$next` variable became unused allowing for further simplification of the code by removing the place where it was being defined. Note for reviewers: this commit is easier to evaluate when ignoring whitespaces.
3f9b441
to
d8bc30b
Compare
Just documenting here that since this PR will be reviewed after the release of PHPCS 4.0, I went ahead and updated its commits and PR description to consider only PHP. Before the changes also included tests for JS. I also improved the PR description by adding links to 3v4l.org showing that empty control structures are valid in PHP and that the way that PHPCBF was fixing those empty control structures is also valid (thus PHPCBF was not introducing syntax errors in the fixed files). |
Description
As discussed in #482 (review) (see "Commit 6" and "Commit 7" sections),
Generic.ControlStructures.InlineControlStructure
now consistently handles all control structures without a body by bailing early. This PR extends the existing behavior forwhile
andfor
to also includedo while
,else
,elseif
,if
, andforeach
. Note that in #482, I did not includedo while
, but I believe it should be included, and it is now part of this PR.Previously, the sniff would incorrectly flag these empty control structures as inline control structures that needed curly braces. This change makes the behavior consistent across all control structures. For
else
,elseif
,if
, andforeach
, the fixer would remove the semicolon and add the curly braces. Fordo while
, the fixer would add the curly braces and keep the semicolon in between the braces. In all the cases, the resulting code was syntactically correct.Consider the following example:
Previously, PHPCS would flag this as an inline control structure, and PHPCBF would fix it to:
Now, an empty
do while
is ignored by the sniff (no warnings and no fixes).Here is a link showing that control structures without a body are valid in PHP:
https://3v4l.org/slnYL
And here is a link showing that the way that PHPCBF was fixing them was resulting in valid code (
while
andfor
are not included below as they were already ignored before this commit):https://3v4l.org/8k1N3
Additionally, this PR removes two code blocks from the fixer that became unnecessary. They are removed in separate commits to hopefully make it easier to review this PR. I suggest combining all the commits in this PR into a single commit before merging.
First removed block
The sniff now bails early for all control structures without body, so the code will never reach the fixer if
$closer + 1
isT_SEMICOLON
.Second removed block
The original version of this now removed condition was added in the early days by the commit that enabled this sniff to fix errors:
squizlabs/PHP_CodeSniffer@a54c619#diff-4b3945c2100b0a92a56509de1b797bf58ad804cf36233c95c492479b665655dcR148-R154
The only two tests that were added with the commit mentioned above that trigger the removed condition are tests using
while
loops without body:squizlabs/PHP_CodeSniffer@a54c619#diff-116c49a7b0b31f724fc25409e31ba119d7f023146818bcb63edbe8f4071422e2R42-R43
Control structures without a body are the only cases where
$next
would be equal to$end
. Thus, these are the only cases where the removed condition would be executed. But two previous commits, changed the sniff to bail early and not get to the fixer part when handling control structures without a body:while
/for
without a body and updated the existing tests (squizlabs/PHP_CodeSniffer@13c803b#diff-2f069f3fe33bacdfc80485b97303aec66c98c451d07e6d86e41982b81ab1a294L49-R50).do while
/else
/elseif
/if
/foreach
control structures.After the removal of the
$next !== $end
check, the$next
variable became unused, allowing for further simplification of the code by removing the place where it was being defined.Regarding what was commented in #482 (review):
I was not able to create a test case that would make
findNext()
returnfalse
on that particular line. Please let me know if you can. Despite that, after further checking the changes I proposed on the original commit back in #482, I noticed that the variable$next
was not used anymore and could be removed. So, in the changes I'm proposing here, thefindNext()
call has also been removed.Note for reviewers: the third commit is easier to evaluate when ignoring whitespace.
Suggested changelog entry
Generic.ControlStructures.InlineControlStructure: bail early when encountering
do while
,else
,elseif
,if
, andforeach
control structures without a body.Related issues/external references
Initially suggested in #482.
Types of changes
I'm not sure if this should be considered a bug fix or an enhancement. So, I'm not selecting the type of change.
PR checklist