WordPress-Coding-Standards: Faulty core fixes: switch/case indentation
Summary:
There are a number of places in WP core which use - very large - switch/case constructs which are incorrectly indented.
For these, the current fixer seems to create a worse inconsistency in the indentations for:
break- indentation not corrected- docblocks - indentation of the first line corrected, but not the rest of the docblock.
- escaping out of PHP
Most likely cause: Generic.WhiteSpace.ScopeIndent
I’ve seen other bugs with this sniff before and it may actually be simpler to pre-indent the case statement manually before running phpcbf than to fix this sniff.
Alternatively, turning that particular sniff off for the fixer might also save some grief.
Example:
File: various files across the board src/wp-admin/comment.php to name just one, src/wp-admin/edit-tags.php for another.
Example snippet:
switch ( $a ) {
case 'a':
$b = 1;
break;
case 'b':
$b = 2;
/**
* A comment about a hook.
*/
apply_filter( 'something', $b );
break;
case 'a':
$b = 3;
?>
<input name="something" value=<?php echo $b; ?>
<?php
$b = 4;
break;
default:
$b = 5;
break;
}
Fixed as:
switch ( $a ) {
case 'a':
$b = 1;
break;
case 'b':
$b = 2;
/**
* A comment about a hook.
*/
apply_filter( 'something', $b );
break;
case 'a':
$b = 3;
?>
<input name="something" value=<?php echo $b; ?>
<?php
$b = 4;
break;
default:
$b = 5;
break;
}
Expected fix:
switch ( $a ) {
case 'a':
$b = 1;
break;
case 'b':
$b = 2;
/**
* A comment about a hook.
*/
apply_filter( 'something', $b );
break;
case 'a':
$b = 3;
?>
<input name="something" value=<?php echo $b; ?>
<?php
$b = 4;
break;
default:
$b = 5;
break;
}
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 25 (24 by maintainers)
Commits related to this issue
- Add `PSR2.ControlStructures.SwitchDeclaration` to the `WordPress-Core` ruleset As proposed in https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/issues/982#issuecomment-31260702... — committed to WordPress/WordPress-Coding-Standards by jrfnl 7 years ago
- Add `PSR2.ControlStructures.SwitchDeclaration` to the `WordPress-Core` ruleset As proposed in https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/issues/982#issuecomment-31260702... — committed to WordPress/WordPress-Coding-Standards by jrfnl 7 years ago
Same here, especially as a dyslectic. Whitespace can make a lot of difference in code readability.
Correct.
Practical point: What about leaving the “blank line at top” part out of the handbook as well as the ruleset for now and moving it to another issue to be discussed there ?
It’s a discussion which is unrelated to this particular issue (switch layout not being fixed correctly) - and as far as I can see at this moment - not one which is currently causing fixer conflicts -, so we can leave deciding upon whether to have a soft/hard rule about blank lines and if so, the wording and the sniffs we’d need, for a later point in time.
Hrrm, that’s an excellent point, it can improve readability. It’s really not used very often in Core, though.
Given variations of the following command, here are the stats I got.
It’s not at all common, though it does get slight more use as blocks get longer, which is to be expected.
I’m not really excited about any sort of hard rule depending on number of lines, though. Perhaps the best option is to soften the language a bit.
The first line of a new code block should not be blank, unless it clearly improves readability. The exception to this is the block inside a
casestatement, which must never start with a blank line.I fully agree with the other two additions to the handbook, but I would note that personally I prefer to add a blank line at the start of any control structure block that is more than one or two lines long. I find this more readable. But I do realize that core usually doesn’t follow this pattern, so I’ll understand if core is going to standardize on no blank lines at the start of control structures. (And even I usually omit the blank line at the start of a
caseblock, I only add them for other control structures.) I just thought that I would make my voice heard.Okay, they’ve all been added to the handbook.
Yes.
Yes.
Just to clarify, this would only apply when there’s a body to the case statement? A series of empty cases wouldn’t require a comment for each.
Done 👍
Ok, so I’ve dug into this a bit deeper.
Current practices used in Core
I figured it might make sense to actually see what’s currently used in Core to decide which rules to adopt anyhow. The
SwitchDeclarationsniff does not create any PHPCS metrics, so we can’t see how this has evolved in WP historically. For now, I’ve added some metrics code locally and ran the info report (and opened a related upstream issue https://github.com/squizlabs/PHP_CodeSniffer/issues/1541).The results were both interesting as well as surprising in some aspects:
Updated proposal
Based on this, I believe we should add the sniff:
SpacingAfterCase(99.9% compliance)SpaceBeforeColon(88,3% compliance)BodyOnNextLine(99.2% compliance)BreakIndent: (90.1% compliance)WrongOpener(99.9% compliance)TerminatingComment(86.6% compliance where relevant)and exclude:
NotLower(100% compliance) - duplicate msgBreakNotNewLine(99.6% compliance) - duplicate msgHandbook updates needed
Based on the rules I mentioned above and what’s already covered in a different way by WPCS (and therefore already in the handbook), I believe the only things which would still need to be added to the handbook would be:
casestatement.”casestatement statement does not end in abreak/return, but deliberately falls through to the next case, it must be so documented with a comment.”caseordefaultstatement.” - providing we’d choose to addBodyOnNextLine- this is not a hard rule for other control structures, so we may still need to think about this and/or add the same for other control structures in that case for consistency.Oh - just noticed: the new example which was added to the handbook for the
case/breakindentation actually uses a space before the colon in thecasestatement, so this will need to be adjusted. /cc @ntwbDetailed look at some of the results of the sniff
WrongOpener
WrongOpenerwould IMHO not need to be documented as code like that would mostly cause a parse error, so wouldn’t be acceptable anyway. I’ve investigated the two cases where this was flagged:wp-includes/class-wp-network.phparound line 157 a semi-colon is used, which is clearly a typo and needs to be fixed.wp-includes/date.phparound line 848.I’ve opened a ticket in trac with a patch for these: https://core.trac.wordpress.org/ticket/41234
TerminatingComment
I’ve also looked at the
TerminatingCommentcases - most are legitimately flagged and could use a comment, a few are quite possibly bugs in the code where the fall-through is unintentional, and a few are situations where there is a control structure within thecaseand all possible pathways contain areturnorbreak, but there is noreturnorbreakat the very end of thecase. We could consider turning this into awarningand for the last part (all pathways contain an exit) this should possibly be reported upstream as a bug.Side-note: Adding this sniff and making these rules explicit in the handbook, funnily enough fills a void already pointed out in 2013 in some comments on the handbook https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#comment-9283 and https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#comment-9984 /cc @JDGrimes
Now the standard for
breakindentation inswitchcontrol structures has been added to the handbook, I’ve looked into whether there was an upstream sniff we can use to cover and auto-fix this.The
PSR2.ControlStructures.SwitchDeclarationsniff would cover this, however it does more than we “need”, though the extra checks included aren’t necessarily a bad thing.Error messages in the sniff:
NotLower: switch/case/default keyword must be lowercase => Already covered byGeneric.PHP.LowerCaseKeyword.FoundSpacingAfterCase: CASE keyword must be followed by a single spaceSpaceBeforeColon: There must be no space before the colon in a case/default statementBodyOnNextLine: The case/default body must start on the line following the statementBreakNotNewLine: Terminating statement must be on a line by itself (=break/return) => Already covered byGeneric.Formatting.DisallowMultipleStatementsBreakIndent: Terminating statement must be indented to the same level as the CASE body (=break/return) <= This is the one we need.WrongOpener: Case/default statements must be defined using a colonTerminatingComment: There must be a comment when fall-through is intentional in a non-empty case bodyAside from the The case/default body must start on the line following the statement message, I think they would all be good additions to WPCS.
I propose adding this sniff to
WordPress-Core, excluding error codes which would lead to duplicate messages and possibly excluding theBodyOnNextLineone if others agree and it would not lead to fixer conflicts.The
WrongOpenerandTerminatingCommenterror codes are more best practice/bug prevention kind of checks, but I don’t think it would be a bad thing to leave them enabled in the Core sniffs in this case.Note: Adding this sniff would not (yet) solve the docblock/escaping out of PHP indentation issues. Those are probably issues with the
Generic.WhiteSpace.ScopeIndentsniff and would need to be looked at separately.The alternative would be to add a WPCS native sniff to only check the indentation of
switchcontrol structures. In that case, the docblock/escaping out of PHP indentation issues should be covered by that sniff as well.Opinions ?
/cc @pento