diff --git a/composer.json b/composer.json index 9898af99..5d224196 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": "^7.3 || ^8.0", - "squizlabs/php_codesniffer": "^3.7.2" + "squizlabs/php_codesniffer": "^3.10.3" }, "require-dev": { "phpunit/phpunit": "^9.6.15" diff --git a/composer.lock b/composer.lock index 2c813a47..0faeb82e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b680160d9103548d71bd9e20ca49fe72", + "content-hash": "072bfe94487842ec5f19f56f532ac9a3", "packages": [ { "name": "squizlabs/php_codesniffer", - "version": "3.7.2", + "version": "3.10.3", "source": { "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "62d32998e820bddc40f99f8251958aed187a5c9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/62d32998e820bddc40f99f8251958aed187a5c9c", + "reference": "62d32998e820bddc40f99f8251958aed187a5c9c", "shasum": "" }, "require": { @@ -27,11 +27,11 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", "extra": { @@ -46,17 +46,45 @@ "authors": [ { "name": "Greg Sherwood", - "role": "lead" + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", "keywords": [ "phpcs", "standards", "static analysis" ], - "time": "2023-02-22T23:07:41+00:00" + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-09-18T10:38:58+00:00" } ], "packages-dev": [ @@ -1681,12 +1709,12 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { "php": "^7.3 || ^8.0" }, - "platform-dev": [], - "plugin-api-version": "1.1.0" + "platform-dev": {}, + "plugin-api-version": "2.6.0" } diff --git a/src/WebimpressCodingStandard/Sniffs/Formatting/ReturnTypeSniff.php b/src/WebimpressCodingStandard/Sniffs/Formatting/ReturnTypeSniff.php index 6b48db52..b5c0404a 100644 --- a/src/WebimpressCodingStandard/Sniffs/Formatting/ReturnTypeSniff.php +++ b/src/WebimpressCodingStandard/Sniffs/Formatting/ReturnTypeSniff.php @@ -26,13 +26,14 @@ use const T_NULL; use const T_NULLABLE; use const T_OPEN_CURLY_BRACKET; -use const T_OPEN_PARENTHESIS; use const T_PARENT; use const T_SELF; use const T_SEMICOLON; use const T_STRING; use const T_TRUE; +use const T_TYPE_CLOSE_PARENTHESIS; use const T_TYPE_INTERSECTION; +use const T_TYPE_OPEN_PARENTHESIS; use const T_TYPE_UNION; use const T_USE; use const T_WHITESPACE; @@ -116,8 +117,8 @@ public function process(File $phpcsFile, $stackPtr) T_TYPE_UNION, T_PARENT, T_WHITESPACE, - T_OPEN_PARENTHESIS, - T_CLOSE_PARENTHESIS, + T_TYPE_OPEN_PARENTHESIS, + T_TYPE_CLOSE_PARENTHESIS, ], $parenthesisCloser + 1, $eol, @@ -150,8 +151,8 @@ public function process(File $phpcsFile, $stackPtr) } $notTypes = [ - T_OPEN_PARENTHESIS, - T_CLOSE_PARENTHESIS, + T_TYPE_OPEN_PARENTHESIS, + T_TYPE_CLOSE_PARENTHESIS, T_BITWISE_AND, T_BITWISE_OR, T_TYPE_INTERSECTION, diff --git a/src/WebimpressCodingStandard/Sniffs/PHP/DisallowFqnSniff.php b/src/WebimpressCodingStandard/Sniffs/PHP/DisallowFqnSniff.php index 845f86db..5ffc1de3 100644 --- a/src/WebimpressCodingStandard/Sniffs/PHP/DisallowFqnSniff.php +++ b/src/WebimpressCodingStandard/Sniffs/PHP/DisallowFqnSniff.php @@ -38,40 +38,33 @@ use const GLOB_NOSORT; use const T_BITWISE_AND; use const T_BITWISE_OR; -use const T_CASE; use const T_CATCH; use const T_CLOSE_PARENTHESIS; use const T_CLOSURE; use const T_COLON; -use const T_COMMA; use const T_DOC_COMMENT_STRING; use const T_DOC_COMMENT_TAG; use const T_DOC_COMMENT_WHITESPACE; use const T_DOUBLE_COLON; -use const T_ECHO; use const T_ELLIPSIS; use const T_EXTENDS; use const T_FN; use const T_FUNCTION; use const T_IMPLEMENTS; -use const T_INCLUDE; -use const T_INCLUDE_ONCE; use const T_INSTANCEOF; use const T_INSTEADOF; -use const T_LOGICAL_AND; -use const T_LOGICAL_OR; -use const T_LOGICAL_XOR; use const T_NAMESPACE; use const T_NEW; use const T_NS_SEPARATOR; use const T_NULLABLE; +use const T_OPEN_CURLY_BRACKET; use const T_OPEN_PARENTHESIS; -use const T_PRINT; -use const T_REQUIRE; -use const T_REQUIRE_ONCE; -use const T_RETURN; +use const T_SEMICOLON; use const T_STRING; -use const T_THROW; +use const T_TYPE_CLOSE_PARENTHESIS; +use const T_TYPE_INTERSECTION; +use const T_TYPE_OPEN_PARENTHESIS; +use const T_TYPE_UNION; use const T_USE; use const T_VARIABLE; @@ -332,10 +325,23 @@ private function processString( ]; if (in_array($tokens[$prev]['code'], $prevClassTokens, true) - || in_array($tokens[$next]['code'], [T_VARIABLE, T_ELLIPSIS, T_DOUBLE_COLON], true) + || in_array($tokens[$next]['code'], [ + T_VARIABLE, + T_ELLIPSIS, + T_DOUBLE_COLON, + // DNF + T_TYPE_UNION, + T_TYPE_INTERSECTION, + T_TYPE_CLOSE_PARENTHESIS, + T_OPEN_CURLY_BRACKET, + ], true) ) { $type = 'class'; - } elseif ($tokens[$next]['code'] === T_OPEN_PARENTHESIS) { + } elseif ($tokens[$next]['code'] === T_OPEN_PARENTHESIS + // The below condition is temporary due to upstream issue + // @see https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/630 + || $tokens[$next]['code'] === T_TYPE_OPEN_PARENTHESIS + ) { $type = 'function'; } else { $type = 'const'; @@ -362,15 +368,10 @@ private function processString( ) { $type = 'class'; } - } elseif ($tokens[$prev]['code'] === T_COMMA) { - $before = $phpcsFile->findPrevious( - Tokens::$emptyTokens + [T_STRING => T_STRING, T_NS_SEPARATOR => T_NS_SEPARATOR], - $prev - 1, - null, - true - ); - - if ($tokens[$before]['code'] === T_IMPLEMENTS) { + } elseif ($tokens[$next]['code'] === T_SEMICOLON) { + $before = $phpcsFile->findPrevious(Tokens::$emptyTokens, $prev, null, true); + + if (in_array($tokens[$before]['code'], [T_TYPE_UNION, T_TYPE_INTERSECTION], true)) { $type = 'class'; } } @@ -553,29 +554,6 @@ private function fixError(File $phpcsFile, int $stackPtr, string $expected) : vo return; } - if (in_array($tokens[$stackPtr - 1]['code'], [ - T_NEW, - T_USE, - T_EXTENDS, - T_IMPLEMENTS, - T_INSTANCEOF, - T_INSTEADOF, - T_CASE, - T_PRINT, - T_ECHO, - T_REQUIRE, - T_REQUIRE_ONCE, - T_INCLUDE, - T_INCLUDE_ONCE, - T_RETURN, - T_LOGICAL_AND, - T_LOGICAL_OR, - T_LOGICAL_XOR, - T_THROW, - ], true)) { - $expected = ' ' . $expected; - } - $phpcsFile->fixer->replaceToken($stackPtr, $expected); $i = $stackPtr; while (isset($tokens[++$i])) { diff --git a/src/WebimpressCodingStandard/Sniffs/WhiteSpace/OperatorAndKeywordSpacingSniff.php b/src/WebimpressCodingStandard/Sniffs/WhiteSpace/OperatorAndKeywordSpacingSniff.php index 164d3197..3072887c 100644 --- a/src/WebimpressCodingStandard/Sniffs/WhiteSpace/OperatorAndKeywordSpacingSniff.php +++ b/src/WebimpressCodingStandard/Sniffs/WhiteSpace/OperatorAndKeywordSpacingSniff.php @@ -11,6 +11,7 @@ use function in_array; use const T_AS; +use const T_DECLARE; use const T_FN_ARROW; use const T_INSTANCEOF; use const T_INSTEADOF; @@ -40,16 +41,30 @@ public function register() : array $tokens[] = T_INSTEADOF; $tokens[] = T_FN_ARROW; + // Also register the contexts we want to specifically skip over. + $tokens[] = T_DECLARE; + return $tokens; } /** * @param int $stackPtr + * @return null|int */ - public function process(File $phpcsFile, $stackPtr) : void + public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); + // Skip over declare statements as those should be handled by different sniffs. + if ($tokens[$stackPtr]['code'] === T_DECLARE) { + if (isset($tokens[$stackPtr]['parenthesis_closer']) === false) { + // Parse error / live coding. + return $phpcsFile->numTokens; + } + + return $tokens[$stackPtr]['parenthesis_closer']; + } + $originalValue = $this->ignoreNewlines; if (in_array($tokens[$stackPtr]['code'], $this->doNotIgnoreNewLineForTokens, true)) { $this->ignoreNewlines = false; diff --git a/test/Sniffs/PHP/DisallowFqnUnitTest.inc b/test/Sniffs/PHP/DisallowFqnUnitTest.inc index 48b9ead6..a1ad5885 100644 --- a/test/Sniffs/PHP/DisallowFqnUnitTest.inc +++ b/test/Sniffs/PHP/DisallowFqnUnitTest.inc @@ -179,4 +179,17 @@ class TheClass extends \ MyNamespace \ Hello \ ParentClass implements \ArrayAcce new \MyNamespace\Foo1\Bar1\Bar2(); new \Foo\BarBaz\Bar3(); } + + public function method3(): \DNF\Type1|(\DNF\Type2&\DNF\Type3) + { + } + + public function method4(): (\DNF\Type4|\DNF\Type5)&\DNF\Type6 + { + } + + abstract public function method5(): (\DNF\Type7|\DNF\Type8)&\DNF\Type9; + + private \DNF\Type10&(\DNF\Type11|\DNF\Type12) $prop1; + private (\DNF\Type13&\DNF\Type14)|\DNF\Type15 $prop2; } diff --git a/test/Sniffs/PHP/DisallowFqnUnitTest.inc.fixed b/test/Sniffs/PHP/DisallowFqnUnitTest.inc.fixed index 4ec39392..5aa1cbcc 100644 --- a/test/Sniffs/PHP/DisallowFqnUnitTest.inc.fixed +++ b/test/Sniffs/PHP/DisallowFqnUnitTest.inc.fixed @@ -6,7 +6,7 @@ use ArrayAccess; use Countable; use DateTime; use InClosure\Param; -use const InClosure\ReturnType; +use InClosure\ReturnType; use const InClosure\CONST_IN_CLOSURE; use function InClosure\functionInClosure; use RuntimeException; @@ -29,6 +29,21 @@ use B; use InFnClosure\Param1; use InFnClosure\ReturnType1; use MyNamespace\Foo1\Bar1; +use DNF\Type1; +use DNF\Type2; +use DNF\Type3; +use DNF\Type4; +use DNF\Type5; +use DNF\Type6; +use DNF\Type7; +use DNF\Type8; +use DNF\Type9; +use DNF\Type10; +use DNF\Type11; +use DNF\Type12; +use DNF\Type13; +use DNF\Type14; +use DNF\Type15; use \ArrayObject as AO; use Foo\BarBaz; @@ -207,4 +222,17 @@ class TheClass extends ParentClass implements ArrayAccess, Countable new Bar1\Bar2(); new BarBaz\Bar3(); } + + public function method3(): Type1|(Type2&Type3) + { + } + + public function method4(): (Type4|Type5)&Type6 + { + } + + abstract public function method5(): (Type7|Type8)&Type9; + + private Type10&(Type11|Type12) $prop1; + private (Type13&Type14)|Type15 $prop2; } diff --git a/test/Sniffs/PHP/DisallowFqnUnitTest.php b/test/Sniffs/PHP/DisallowFqnUnitTest.php index f6f7164e..74ff9903 100644 --- a/test/Sniffs/PHP/DisallowFqnUnitTest.php +++ b/test/Sniffs/PHP/DisallowFqnUnitTest.php @@ -103,6 +103,11 @@ protected function getErrorList(string $testFile = '') : array 178 => 1, 179 => 1, 180 => 1, + 183 => 3, + 187 => 3, + 191 => 3, + 193 => 3, + 194 => 3, ]; } diff --git a/test/Sniffs/WhiteSpace/OperatorAndKeywordSpacingUnitTest.1.inc b/test/Sniffs/WhiteSpace/OperatorAndKeywordSpacingUnitTest.1.inc new file mode 100644 index 00000000..3a0dbac3 --- /dev/null +++ b/test/Sniffs/WhiteSpace/OperatorAndKeywordSpacingUnitTest.1.inc @@ -0,0 +1,3 @@ + 1, 6 => 1, - 11 => 2, - 12 => 2, - 17 => 2, - 21 => 1, + 8 => 1, + 13 => 2, + 14 => 2, + 19 => 2, 23 => 1, - 27 => 1, - 31 => 1, - 35 => 1, - 39 => 2, + 25 => 1, + 29 => 1, + 33 => 1, + 37 => 1, + 41 => 2, ]; }