From f6adf52ba44e9b998c588c2b371fc632e7474955 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 31 May 2022 09:43:46 +0200 Subject: [PATCH 1/6] Whitespace/ControlStructureSpacing: sync with upstream [1] Add metrics for blank line at start/end of control structure as per https://github.com/squizlabs/PHP_CodeSniffer/commit/4fc2515b3c403e970cab90936ee73f4434f35827 (PHPCS 2.5.1). --- .../Sniffs/WhiteSpace/ControlStructureSpacingSniff.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php index 1123a4a1c1..d52b145a29 100644 --- a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php +++ b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php @@ -295,6 +295,9 @@ public function process_token( $stackPtr ) { if ( ! isset( $ignore[ $this->tokens[ $firstContent ]['code'] ] ) && $this->tokens[ $firstContent ]['line'] > ( $this->tokens[ $scopeOpener ]['line'] + 1 ) ) { + $gap = ( $this->tokens[ $firstContent ]['line'] - $this->tokens[ $scopeOpener ]['line'] - 1 ); + $this->phpcsFile->recordMetric( $stackPtr, 'Blank lines at start of control structure', $gap ); + $error = 'Blank line found at start of control structure'; $fix = $this->phpcsFile->addFixableError( $error, $scopeOpener, 'BlankLineAfterStart' ); @@ -311,6 +314,8 @@ public function process_token( $stackPtr ) { $this->phpcsFile->fixer->addNewline( $scopeOpener ); $this->phpcsFile->fixer->endChangeset(); } + } else { + $this->phpcsFile->recordMetric( $stackPtr, 'Blank lines at start of control structure', 0 ); } if ( $firstContent !== $scopeCloser ) { @@ -326,6 +331,9 @@ public function process_token( $stackPtr ) { if ( ! isset( $ignore[ $this->tokens[ $checkToken ]['code'] ] ) && $this->tokens[ $lastContent ]['line'] <= ( $this->tokens[ $scopeCloser ]['line'] - 2 ) ) { + $gap = ( $this->tokens[ $scopeCloser ]['line'] - $this->tokens[ $lastContent ]['line'] - 1 ); + $this->phpcsFile->recordMetric( $stackPtr, 'Blank lines at end of control structure', $gap ); + for ( $i = ( $scopeCloser - 1 ); $i > $lastContent; $i-- ) { if ( $this->tokens[ $i ]['line'] < $this->tokens[ $scopeCloser ]['line'] && \T_OPEN_TAG !== $this->tokens[ $firstContent ]['code'] @@ -359,6 +367,8 @@ public function process_token( $stackPtr ) { break; } } + } else { + $this->phpcsFile->recordMetric( $stackPtr, 'Blank lines at end of control structure', 0 ); } } unset( $ignore ); From e1ae45be69e3a55728c3fc9822cf1270fe1a5247 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 13 Aug 2023 17:59:41 +0200 Subject: [PATCH 2/6] Whitespace/ControlStructureSpacing: sync with upstream [2] Check the spacing after the `finally` keyword as per https://github.com/squizlabs/PHP_CodeSniffer/commit/eefb31c68e4c9e4c390d08859163ca7e587ca46d (PHPCS 3.2.3). Handled in a slightly different way as upstream as the sniffs have diverged, but this should work for the most part (aside from pre-existing issues in the sniff anyway). --- .../ControlStructureSpacingSniff.php | 25 ++++++++++++--- .../ControlStructureSpacingUnitTest.1.inc | 32 +++++++++++++++++++ ...ontrolStructureSpacingUnitTest.1.inc.fixed | 29 +++++++++++++++++ .../ControlStructureSpacingUnitTest.php | 3 ++ 4 files changed, 85 insertions(+), 4 deletions(-) diff --git a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php index d52b145a29..de6b7d484f 100644 --- a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php +++ b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php @@ -53,16 +53,17 @@ final class ControlStructureSpacingSniff extends Sniff { /** * Tokens for which to ignore extra space on the inside of parenthesis. * - * For do / else / try, there are no parenthesis, so skip it. + * For do / else / try / finally, there are no parenthesis, so skip it. * * @since 0.11.0 * * @var array */ private $ignore_extra_space_after_open_paren = array( - \T_DO => true, - \T_ELSE => true, - \T_TRY => true, + \T_DO => true, + \T_ELSE => true, + \T_TRY => true, + \T_FINALLY => true, ); /** @@ -82,6 +83,7 @@ public function register() { \T_ELSEIF, \T_TRY, \T_CATCH, + \T_FINALLY, ); } @@ -415,6 +417,21 @@ public function process_token( $stackPtr ) { return; } + if ( \T_CATCH === $this->tokens[ $trailingContent ]['code'] && \T_TRY === $this->tokens[ $stackPtr ]['code'] ) { + // TRY with CATCH. + return; + } + + if ( \T_FINALLY === $this->tokens[ $trailingContent ]['code'] && \T_CATCH === $this->tokens[ $stackPtr ]['code'] ) { + // CATCH with FINALLY. + return; + } + + if ( \T_FINALLY === $this->tokens[ $trailingContent ]['code'] && \T_TRY === $this->tokens[ $stackPtr ]['code'] ) { + // TRY with FINALLY. + return; + } + if ( \T_CLOSE_TAG === $this->tokens[ $trailingContent ]['code'] ) { // At the end of the script or embedded code. return; diff --git a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc index 1f1b47abf1..7b736e4438 100644 --- a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc +++ b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc @@ -180,3 +180,35 @@ if ( $foo ) { } + +// Handle (try/catch/) finally statements as well. +try { + // Something +} catch ( Exception $e ) { + // Something +} finally { // OK. + // Something +} + +try { + // Something +} finally + +{ // Bad. + // Something +} + +try { + // Something +} finally{ // Bad. + // Something +} + +if ( $condition ) { + try { + // Something + } finally { + // Something + } + +} // Bad: blank line between. diff --git a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc.fixed b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc.fixed index c57462793c..655b6a8a98 100644 --- a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc.fixed +++ b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc.fixed @@ -171,3 +171,32 @@ if ( $foo ) { // Something } // End try/catch <- Bad: "blank line after". } + +// Handle (try/catch/) finally statements as well. +try { + // Something +} catch ( Exception $e ) { + // Something +} finally { // OK. + // Something +} + +try { + // Something +} finally { // Bad. + // Something +} + +try { + // Something +} finally { // Bad. + // Something +} + +if ( $condition ) { + try { + // Something + } finally { + // Something + } +} // Bad: blank line between. diff --git a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php index 5f93452331..6a88e0f654 100644 --- a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php +++ b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php @@ -52,6 +52,9 @@ public function getErrorList( $testFile = '' ) { 159 => 1, 169 => 1, 179 => 1, + 195 => 1, + 203 => 2, + 212 => 1, ); return $ret; From 2b1ba784e2f44604cd04e51835df3d7c787669f1 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 14 Aug 2023 08:21:14 +0200 Subject: [PATCH 3/6] Whitespace/ControlStructureSpacing: sync with upstream [3] Check the spacing for `match` control structures as per https://github.com/squizlabs/PHP_CodeSniffer/commit/549899bb93ebb830e0b2ef5d71ead42941b1e362 (PHPCS 3.6.0). --- .../ControlStructureSpacingSniff.php | 11 +++++++ .../ControlStructureSpacingUnitTest.1.inc | 30 +++++++++++++++++++ ...ontrolStructureSpacingUnitTest.1.inc.fixed | 26 ++++++++++++++++ .../ControlStructureSpacingUnitTest.php | 4 +++ 4 files changed, 71 insertions(+) diff --git a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php index de6b7d484f..a68caa73ef 100644 --- a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php +++ b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php @@ -84,6 +84,7 @@ public function register() { \T_TRY, \T_CATCH, \T_FINALLY, + \T_MATCH, ); } @@ -380,6 +381,16 @@ public function process_token( $stackPtr ) { return; } + if ( \T_MATCH === $this->tokens[ $stackPtr ]['code'] ) { + // Move the scope closer to the semicolon/comma. + $next = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $scopeCloser + 1 ), null, true ); + if ( false !== $next + && ( \T_SEMICOLON === $this->tokens[ $next ]['code'] || \T_COMMA === $this->tokens[ $next ]['code'] ) + ) { + $scopeCloser = $next; + } + } + // {@internal This is just for the blank line check. Only whitespace should be considered, // not "other" empty tokens.}} $trailingContent = $this->phpcsFile->findNext( \T_WHITESPACE, ( $scopeCloser + 1 ), null, true ); diff --git a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc index 7b736e4438..ce5467c1b6 100644 --- a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc +++ b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc @@ -212,3 +212,33 @@ if ( $condition ) { } } // Bad: blank line between. + +// Handle PHP 8.0+ match expressions. +$expr = match ( $foo ) { + 1 => 1, + 2 => 2, +}; + +$expr = match($foo){ + 1 => 1, + 2 => 2, +} ; + +// phpcs:set WordPress.WhiteSpace.ControlStructureSpacing blank_line_check true +$expr = match ( $foo ) { + + 1 => 1, + 2 => 2, + +}; + +// phpcs:set WordPress.WhiteSpace.ControlStructureSpacing blank_line_check false + +if ( $condition ) { + $expr = match ( $foo ) { + 1 => 1, + 2 => 2, + }; + + +} // Bad: blank line between. diff --git a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc.fixed b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc.fixed index 655b6a8a98..f69ea425f5 100644 --- a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc.fixed +++ b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc.fixed @@ -200,3 +200,29 @@ if ( $condition ) { // Something } } // Bad: blank line between. + +// Handle PHP 8.0+ match expressions. +$expr = match ( $foo ) { + 1 => 1, + 2 => 2, +}; + +$expr = match ( $foo ) { + 1 => 1, + 2 => 2, +} ; + +// phpcs:set WordPress.WhiteSpace.ControlStructureSpacing blank_line_check true +$expr = match ( $foo ) { + 1 => 1, + 2 => 2, +}; + +// phpcs:set WordPress.WhiteSpace.ControlStructureSpacing blank_line_check false + +if ( $condition ) { + $expr = match ( $foo ) { + 1 => 1, + 2 => 2, + }; +} // Bad: blank line between. diff --git a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php index 6a88e0f654..d56e56e840 100644 --- a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php +++ b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php @@ -55,6 +55,10 @@ public function getErrorList( $testFile = '' ) { 195 => 1, 203 => 2, 212 => 1, + 222 => 5, + 228 => 1, + 232 => 1, + 241 => 1, ); return $ret; From c355ab9ce36a25da2cff27f26364b934641ea35b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 14 Aug 2023 08:36:11 +0200 Subject: [PATCH 4/6] Whitespace/ControlStructureSpacing: sync with upstream [4] Ignore blank line/spacing rules when the next thing (inside/outside) is an enum as per https://github.com/squizlabs/PHP_CodeSniffer/commit/7f11ffc8222b123c06345afd3261221561c3bb29 and https://github.com/squizlabs/PHP_CodeSniffer/commit/b71b4703912d9ed74393f406c80f072cff4c9cae (PHPCS 3.7.0). --- .../ControlStructureSpacingSniff.php | 2 +- .../ControlStructureSpacingUnitTest.1.inc | 21 +++++++++++++++++++ ...ontrolStructureSpacingUnitTest.1.inc.fixed | 21 +++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php index a68caa73ef..f5b304792a 100644 --- a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php +++ b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php @@ -453,7 +453,7 @@ public function process_token( $stackPtr ) { ) { // Another control structure's closing brace. $owner = $this->tokens[ $trailingContent ]['scope_condition']; - if ( \in_array( $this->tokens[ $owner ]['code'], array( \T_FUNCTION, \T_CLOSURE, \T_CLASS, \T_ANON_CLASS, \T_INTERFACE, \T_TRAIT ), true ) ) { + if ( \in_array( $this->tokens[ $owner ]['code'], array( \T_FUNCTION, \T_CLOSURE, \T_CLASS, \T_ANON_CLASS, \T_INTERFACE, \T_TRAIT, \T_ENUM ), true ) ) { // The next content is the closing brace of a function, class, interface or trait // so normal function/class rules apply and we can ignore it. return; diff --git a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc index ce5467c1b6..73f4b0a00e 100644 --- a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc +++ b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc @@ -242,3 +242,24 @@ if ( $condition ) { } // Bad: blank line between. + +// Ignore spacing rules in combination with enums as they tend to have their own rules. +// phpcs:set WordPress.WhiteSpace.ControlStructureSpacing blank_line_check true +if ( $foo ) { + + + enum MyEnumA { + // Code here + } + + +} +// phpcs:set WordPress.WhiteSpace.ControlStructureSpacing blank_line_check false + +enum MyEnumB { + if ( $foo ) { + // Code here + } + + +} // OK, defer to enum rules. diff --git a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc.fixed b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc.fixed index f69ea425f5..1a2bf8ad3c 100644 --- a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc.fixed +++ b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc.fixed @@ -226,3 +226,24 @@ if ( $condition ) { 2 => 2, }; } // Bad: blank line between. + +// Ignore spacing rules in combination with enums as they tend to have their own rules. +// phpcs:set WordPress.WhiteSpace.ControlStructureSpacing blank_line_check true +if ( $foo ) { + + + enum MyEnumA { + // Code here + } + + +} +// phpcs:set WordPress.WhiteSpace.ControlStructureSpacing blank_line_check false + +enum MyEnumB { + if ( $foo ) { + // Code here + } + + +} // OK, defer to enum rules. From e5d967ea525763e4a11e746eadcf4c17d4812705 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 30 Jun 2020 09:41:48 +0200 Subject: [PATCH 5/6] WhiteSpace/ControlStructureSpacing: implement PHPCSUtils Minor code simplifications by using PHPCSUtils. --- .../Sniffs/WhiteSpace/ControlStructureSpacingSniff.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php index f5b304792a..f5b3fa0456 100644 --- a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php +++ b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php @@ -9,8 +9,9 @@ namespace WordPressCS\WordPress\Sniffs\WhiteSpace; -use WordPressCS\WordPress\Sniff; +use PHPCSUtils\Tokens\Collections; use PHP_CodeSniffer\Util\Tokens; +use WordPressCS\WordPress\Sniff; /** * Enforces spacing around logical operators and assignments, based upon Squiz code. @@ -287,13 +288,11 @@ public function process_token( $stackPtr ) { // We ignore spacing for some structures that tend to have their own rules. $ignore = array( - \T_FUNCTION => true, - \T_CLOSURE => true, \T_DOC_COMMENT_OPEN_TAG => true, \T_CLOSE_TAG => true, \T_COMMENT => true, ); - $ignore += Tokens::$ooScopeTokens; + $ignore += Collections::closedScopes(); if ( ! isset( $ignore[ $this->tokens[ $firstContent ]['code'] ] ) && $this->tokens[ $firstContent ]['line'] > ( $this->tokens[ $scopeOpener ]['line'] + 1 ) @@ -453,7 +452,7 @@ public function process_token( $stackPtr ) { ) { // Another control structure's closing brace. $owner = $this->tokens[ $trailingContent ]['scope_condition']; - if ( \in_array( $this->tokens[ $owner ]['code'], array( \T_FUNCTION, \T_CLOSURE, \T_CLASS, \T_ANON_CLASS, \T_INTERFACE, \T_TRAIT, \T_ENUM ), true ) ) { + if ( isset( Collections::closedScopes()[ $this->tokens[ $owner ]['code'] ] ) === true ) { // The next content is the closing brace of a function, class, interface or trait // so normal function/class rules apply and we can ignore it. return; From 612b5556f62121036418038082861eb28d0dc146 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 31 May 2022 10:06:14 +0200 Subject: [PATCH 6/6] WhiteSpace/ControlStructureSpacing: fix/update class docblock Last update date is based on the last upstream commit to this sniff. --- .../Sniffs/WhiteSpace/ControlStructureSpacingSniff.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php index f5b3fa0456..234afe45dd 100644 --- a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php +++ b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php @@ -14,7 +14,7 @@ use WordPressCS\WordPress\Sniff; /** - * Enforces spacing around logical operators and assignments, based upon Squiz code. + * Checks that control structures have the correct spacing around brackets, based upon Squiz code. * * @since 0.1.0 * @since 2013-06-11 This sniff no longer supports JS. @@ -23,10 +23,10 @@ * @since 0.13.0 Class name changed: this class is now namespaced. * @since 3.0.0 Checks related to function declarations have been removed from this sniff. * - * Last synced with base class 2017-01-15 at commit b024ad84656c37ef5733c6998ebc1e60957b2277. + * Last synced with base class 2021-11-20 at commit 7f11ffc8222b123c06345afd3261221561c3bb29. * Note: This class has diverged quite far from the original. All the same, checking occasionally * to see if there are upstream fixes made from which this sniff can benefit, is warranted. - * @link https://github.com/squizlabs/PHP_CodeSniffer/blob/master/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php + * @link https://github.com/squizlabs/PHP_CodeSniffer/blob/master/src/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php */ final class ControlStructureSpacingSniff extends Sniff {