From 1097f995342203b80a390f12f8e770d45fb9e001 Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 30 Sep 2025 16:52:55 -0400 Subject: [PATCH 1/8] Update linting config --- phpcs.xml.dist | 25 ++++++++-------------- psalm-baseline.xml | 52 ++++++++++++++++++++++++++++++++++++++++++++++ psalm.xml | 1 + 3 files changed, 62 insertions(+), 16 deletions(-) create mode 100644 psalm-baseline.xml diff --git a/phpcs.xml.dist b/phpcs.xml.dist index ff63b21..42482de 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -30,33 +30,26 @@ - + - - - - - - - - - - - - - + + + + + + + diff --git a/psalm-baseline.xml b/psalm-baseline.xml new file mode 100644 index 0000000..bbc93ea --- /dev/null +++ b/psalm-baseline.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/psalm.xml b/psalm.xml index 5223a5e..abd0443 100644 --- a/psalm.xml +++ b/psalm.xml @@ -6,6 +6,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" + errorBaseline="psalm-baseline.xml" > From 18873d575cad8e7963db536e94b66c8a0dd6c89f Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 30 Sep 2025 16:53:38 -0400 Subject: [PATCH 2/8] Update github actions config --- .github/workflows/csqa.yml | 12 ++--- .github/workflows/test.yml | 104 ++++++++++++++++++++++--------------- 2 files changed, 68 insertions(+), 48 deletions(-) diff --git a/.github/workflows/csqa.yml b/.github/workflows/csqa.yml index 6ec8edc..2387332 100644 --- a/.github/workflows/csqa.yml +++ b/.github/workflows/csqa.yml @@ -5,7 +5,7 @@ on: # Prevent the build from running when there are only irrelevant changes. push: paths-ignore: - - '**.md' + - "**.md" pull_request: # Allow manually triggering the workflow. workflow_dispatch: @@ -18,11 +18,11 @@ concurrency: jobs: checkcs: - name: 'Basic CS and QA checks' + name: "Basic CS and QA checks" runs-on: ubuntu-latest env: - XMLLINT_INDENT: ' ' + XMLLINT_INDENT: " " steps: - name: Checkout code @@ -31,13 +31,13 @@ jobs: - name: Install PHP uses: shivammathur/setup-php@v2 with: - php-version: 'latest' + php-version: "latest" coverage: none tools: cs2pr # Using PHPCS `master` as an early detection system for bugs upstream. - - name: 'Composer: adjust dependencies' - run: composer require --no-update squizlabs/php_codesniffer:"dev-master" + - name: "Composer: adjust dependencies" + run: composer require --no-update squizlabs/php_codesniffer:"4.x-dev" # Install dependencies and handle caching in one go. # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 919932e..80c39bb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,40 +34,60 @@ jobs: # - PHP 8.4 needs PHPCS 3.11.0+ to run without errors (though the errors don't affect this package). # # The matrix is set up so as not to duplicate the builds which are run for code coverage. - php: ['5.5', '5.6', '7.0', '7.1', '7.2', '7.3'] - phpcs_version: ['3.5.6', 'dev-master'] + php: ["5.5", "5.6", "7.0", "7.1", "7.2", "7.3"] + phpcs_version: ["3.5.6", "4.0.0", "4.x-dev"] + + exclude: + # PHPCS 4.x requires PHP 7.2+ + - php: "5.5" + phpcs_version: "4.0.0" + - php: "5.5" + phpcs_version: "4.x-dev" + - php: "5.6" + phpcs_version: "4.0.0" + - php: "5.6" + phpcs_version: "4.x-dev" + - php: "7.0" + phpcs_version: "4.0.0" + - php: "7.0" + phpcs_version: "4.x-dev" + - php: "7.1" + phpcs_version: "4.0.0" + - php: "7.1" + phpcs_version: "4.x-dev" include: - # Make the matrix complete without duplicating builds run in code coverage. - - php: '8.4' - phpcs_version: '3.6.1' - - - php: '8.3' - phpcs_version: 'dev-master' - - php: '8.3' - phpcs_version: '3.6.1' - - - php: '8.2' - phpcs_version: 'dev-master' - - php: '8.2' - phpcs_version: '3.6.1' - - - php: '8.1' - phpcs_version: 'dev-master' - - php: '8.1' - phpcs_version: '3.6.1' - - - php: '8.0' - phpcs_version: 'dev-master' - - php: '8.0' - phpcs_version: '3.5.7' - - - php: '7.4' - phpcs_version: 'dev-master' + - php: "8.4" + phpcs_version: "4.0.0" + - php: "8.4" + phpcs_version: "3.6.1" + + - php: "8.3" + phpcs_version: "4.x-dev" + - php: "8.3" + phpcs_version: "3.6.1" + + - php: "8.2" + phpcs_version: "4.x-dev" + - php: "8.2" + phpcs_version: "3.6.1" + + - php: "8.1" + phpcs_version: "4.x-dev" + - php: "8.1" + phpcs_version: "3.6.1" + + - php: "8.0" + phpcs_version: "4.x-dev" + - php: "8.0" + phpcs_version: "3.5.7" + + - php: "7.4" + phpcs_version: "4.x-dev" # Experimental builds. - - php: '8.5' # Nightly. - phpcs_version: 'dev-master' + - php: "8.5" # Nightly. + phpcs_version: "4.x-dev" name: "Test: PHP ${{ matrix.php }} on PHPCS ${{ matrix.phpcs_version }}" @@ -82,7 +102,7 @@ jobs: run: | # On stable PHPCS versions, allow for PHP deprecation notices. # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. - if [ "${{ matrix.phpcs_version }}" != "dev-master" ]; then + if [ "${{ matrix.phpcs_version }}" != "4.x-dev" ]; then echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On, zend.assertions=1' >> $GITHUB_OUTPUT else echo 'PHP_INI=error_reporting=-1, display_errors=On, zend.assertions=1' >> $GITHUB_OUTPUT @@ -95,7 +115,7 @@ jobs: ini-values: ${{ steps.set_ini.outputs.PHP_INI }} coverage: none - - name: 'Composer: adjust dependencies' + - name: "Composer: adjust dependencies" run: | # Remove dev dependencies which are not compatible with all supported PHP versions. composer remove --dev --no-update sirbrillig/phpcs-import-detection phpstan/phpstan @@ -146,15 +166,15 @@ jobs: strategy: matrix: include: - - php: '8.4' - phpcs_version: 'dev-master' - - php: '7.4' - phpcs_version: '3.5.6' + - php: "8.4" + phpcs_version: "4.x-dev" + - php: "7.4" + phpcs_version: "3.5.6" - - php: '5.4' - phpcs_version: 'dev-master' - - php: '5.4' - phpcs_version: '3.5.6' + - php: "7.2" + phpcs_version: "4.x-dev" + - php: "5.4" + phpcs_version: "3.5.6" name: "Coverage: PHP ${{ matrix.php }} on PHPCS ${{ matrix.phpcs_version }}" @@ -167,7 +187,7 @@ jobs: run: | # On stable PHPCS versions, allow for PHP deprecation notices. # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. - if [ "${{ matrix.phpcs_version }}" != "dev-master" ]; then + if [ "${{ matrix.phpcs_version }}" != "4.x-dev" ]; then echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On, zend.assertions=1' >> $GITHUB_OUTPUT else echo 'PHP_INI=error_reporting=-1, display_errors=On, zend.assertions=1' >> $GITHUB_OUTPUT @@ -180,7 +200,7 @@ jobs: ini-values: ${{ steps.set_ini.outputs.PHP_INI }} coverage: xdebug - - name: 'Composer: adjust dependencies' + - name: "Composer: adjust dependencies" run: | # Remove dev dependencies which are not compatible with all supported PHP/PHPCS versions. composer remove --dev --no-update phpcsstandards/phpcsdevcs sirbrillig/phpcs-import-detection phpstan/phpstan From 776da70799c3d99e7a9170fb3fde141e6dcc9cff Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 30 Sep 2025 16:54:09 -0400 Subject: [PATCH 3/8] Update sniff to handle T_NAME... tokens for functions --- VariableAnalysis/Lib/Helpers.php | 68 ++++++++++++++++--- .../CodeAnalysis/VariableAnalysisSniff.php | 29 +++++++- 2 files changed, 88 insertions(+), 9 deletions(-) diff --git a/VariableAnalysis/Lib/Helpers.php b/VariableAnalysis/Lib/Helpers.php index 4a9c162..d050ab5 100644 --- a/VariableAnalysis/Lib/Helpers.php +++ b/VariableAnalysis/Lib/Helpers.php @@ -93,7 +93,7 @@ public static function findContainingOpeningBracket(File $phpcsFile, $stackPtr) $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]['nested_parenthesis'])) { /** - * @var array + * @var list */ $openPtrs = array_keys($tokens[$stackPtr]['nested_parenthesis']); return (int)end($openPtrs); @@ -319,8 +319,22 @@ public static function findFunctionCall(File $phpcsFile, $stackPtr) if (is_int($openPtr)) { // First non-whitespace thing and see if it's a T_STRING function name $functionPtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, $openPtr - 1, null, true, null, true); - if (is_int($functionPtr) && $tokens[$functionPtr]['code'] === T_STRING) { - return $functionPtr; + if (is_int($functionPtr)) { + $functionTokenCode = $tokens[$functionPtr]['code']; + // In PHPCS 4.x, function names can be T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, or T_NAME_RELATIVE + $validFunctionTokens = [T_STRING]; + if (defined('T_NAME_FULLY_QUALIFIED')) { + $validFunctionTokens[] = T_NAME_FULLY_QUALIFIED; + } + if (defined('T_NAME_QUALIFIED')) { + $validFunctionTokens[] = T_NAME_QUALIFIED; + } + if (defined('T_NAME_RELATIVE')) { + $validFunctionTokens[] = T_NAME_RELATIVE; + } + if (in_array($functionTokenCode, $validFunctionTokens, true)) { + return $functionPtr; + } } } return null; @@ -364,9 +378,6 @@ public static function findFunctionCallArguments(File $phpcsFile, $stackPtr) if (self::findContainingOpeningBracket($phpcsFile, $nextPtr) === $openPtr) { // Comma is at our level of brackets, it's an argument delimiter. $range = range($lastArgComma + 1, $nextPtr - 1); - $range = array_filter($range, function ($element) { - return is_int($element); - }); array_push($argPtrs, $range); $lastArgComma = $nextPtr; } @@ -394,7 +405,8 @@ public static function getNextAssignPointer(File $phpcsFile, $stackPtr) // Is the next non-whitespace an assignment? $nextPtr = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true); - if (is_int($nextPtr) + if ( + is_int($nextPtr) && isset(Tokens::$assignmentTokens[$tokens[$nextPtr]['code']]) // Ignore double arrow to prevent triggering on `foreach ( $array as $k => $v )`. && $tokens[$nextPtr]['code'] !== T_DOUBLE_ARROW @@ -549,6 +561,16 @@ public static function findVariableScopeExceptArrowFunctions(File $phpcsFile, $s T_HEREDOC, T_STRING, ]; + // In PHPCS 4.x, function names can be T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, or T_NAME_RELATIVE + if (defined('T_NAME_FULLY_QUALIFIED')) { + $allowedTypes[] = T_NAME_FULLY_QUALIFIED; + } + if (defined('T_NAME_QUALIFIED')) { + $allowedTypes[] = T_NAME_QUALIFIED; + } + if (defined('T_NAME_RELATIVE')) { + $allowedTypes[] = T_NAME_RELATIVE; + } if (! in_array($tokens[$stackPtr]['code'], $allowedTypes, true)) { throw new \Exception("Cannot find variable scope for non-variable {$tokens[$stackPtr]['type']}"); } @@ -1290,7 +1312,7 @@ public static function getFunctionIndexForFunctionCallArgument(File $phpcsFile, return null; } /** - * @var array + * @var list */ $startingParenthesis = array_keys($token['nested_parenthesis']); $startOfArguments = end($startingParenthesis); @@ -1681,9 +1703,30 @@ public static function getFunctionNameWithNamespace(File $phpcsFile, $stackPtr) $startOfScope = self::findVariableScope($phpcsFile, $stackPtr); $functionName = $tokens[$stackPtr]['content']; + // In PHPCS 4.x, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, and T_NAME_RELATIVE + // tokens already contain the full namespaced name, so we can return early. + if (defined('T_NAME_FULLY_QUALIFIED') && $tokens[$stackPtr]['code'] === T_NAME_FULLY_QUALIFIED) { + return $functionName; + } + if (defined('T_NAME_QUALIFIED') && $tokens[$stackPtr]['code'] === T_NAME_QUALIFIED) { + return $functionName; + } + if (defined('T_NAME_RELATIVE') && $tokens[$stackPtr]['code'] === T_NAME_RELATIVE) { + return $functionName; + } + // Move backwards from the token, collecting namespace separators and // strings, until we encounter whitespace or something else. $partOfNamespace = [T_NS_SEPARATOR, T_STRING]; + if (defined('T_NAME_QUALIFIED')) { + $partOfNamespace[] = T_NAME_QUALIFIED; + } + if (defined('T_NAME_RELATIVE')) { + $partOfNamespace[] = T_NAME_RELATIVE; + } + if (defined('T_NAME_FULLY_QUALIFIED')) { + $partOfNamespace[] = T_NAME_FULLY_QUALIFIED; + } for ($i = $stackPtr - 1; $i > $startOfScope; $i--) { if (! in_array($tokens[$i]['code'], $partOfNamespace, true)) { break; @@ -1708,6 +1751,15 @@ private static function isTokenPossiblyPartOfTypehint(File $phpcsFile, $stackPtr if ($token['code'] === 'PHPCS_T_NULLABLE') { return true; } + if (defined('T_NAME_QUALIFIED') && $token['code'] === T_NAME_QUALIFIED) { + return true; + } + if (defined('T_NAME_RELATIVE') && $token['code'] === T_NAME_RELATIVE) { + return true; + } + if (defined('T_NAME_FULLY_QUALIFIED') && $token['code'] === T_NAME_FULLY_QUALIFIED) { + return true; + } if ($token['code'] === T_NS_SEPARATOR) { return true; } diff --git a/VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php b/VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php index b1d7e46..cda95f6 100644 --- a/VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php +++ b/VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php @@ -1503,7 +1503,34 @@ protected function processVariableAsPassByReferenceFunctionCall(File $phpcsFile, // Is our function a known pass-by-reference function? $functionName = $tokens[$functionPtr]['content']; - $refArgs = $this->getPassByReferenceFunction($functionName); + + // In PHPCS 4.x, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, and T_NAME_RELATIVE + // tokens contain the full namespaced name. Extract just the base name for the + // first check so that 'my_function' in the config can match '\My\Namespace\my_function'. + $functionBaseName = $functionName; + if (defined('T_NAME_FULLY_QUALIFIED') && $tokens[$functionPtr]['code'] === T_NAME_FULLY_QUALIFIED) { + $lastBackslashPos = strrpos($functionName, '\\'); + if ($lastBackslashPos !== false) { + $functionBaseName = substr($functionName, $lastBackslashPos + 1); + } + } elseif (defined('T_NAME_QUALIFIED') && $tokens[$functionPtr]['code'] === T_NAME_QUALIFIED) { + $lastBackslashPos = strrpos($functionName, '\\'); + if ($lastBackslashPos !== false) { + $functionBaseName = substr($functionName, $lastBackslashPos + 1); + } + } elseif (defined('T_NAME_RELATIVE') && $tokens[$functionPtr]['code'] === T_NAME_RELATIVE) { + $lastBackslashPos = strrpos($functionName, '\\'); + if ($lastBackslashPos !== false) { + $functionBaseName = substr($functionName, $lastBackslashPos + 1); + } + } + + // Ensure we have a string (should always be true, but helps static analyzers). + if (! is_string($functionBaseName) || $functionBaseName === '') { + return false; + } + + $refArgs = $this->getPassByReferenceFunction($functionBaseName); if (! $refArgs) { // Check again with the fully namespaced function name. $functionName = Helpers::getFunctionNameWithNamespace($phpcsFile, $functionPtr); From 200fe58b2b683346e7a54cdc9be68448ebec6967 Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 30 Sep 2025 16:54:40 -0400 Subject: [PATCH 4/8] Update composer versions --- composer.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index b11fae4..6e8e439 100644 --- a/composer.json +++ b/composer.json @@ -51,13 +51,12 @@ }, "require": { "php": ">=5.4.0", - "squizlabs/php_codesniffer": "^3.5.6" + "squizlabs/php_codesniffer": "^3.5.6 || ^4.0.0" }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0 || ^10.5.32 || ^11.3.3", - "phpcsstandards/phpcsdevcs": "^1.1", - "phpstan/phpstan": "^1.7", + "phpstan/phpstan": "^1.7 || ^2.0", "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.0", - "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0" + "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0 || ^6.0 || ^7.0" } } From 8107636a5f490e3d98b095c970c9126f1d180378 Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 30 Sep 2025 17:57:01 -0400 Subject: [PATCH 5/8] Bump min phpcs version to 3.5.7 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6e8e439..d94d0af 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,7 @@ }, "require": { "php": ">=5.4.0", - "squizlabs/php_codesniffer": "^3.5.6 || ^4.0.0" + "squizlabs/php_codesniffer": "^3.5.7 || ^4.0.0" }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0 || ^10.5.32 || ^11.3.3", From 067e988adbe6b9f68cd2c0a3f25bd5891b5010da Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 30 Sep 2025 18:00:33 -0400 Subject: [PATCH 6/8] Remove defined guards for T_NAME... constants --- VariableAnalysis/Lib/Helpers.php | 58 +++++++------------ .../CodeAnalysis/VariableAnalysisSniff.php | 6 +- 2 files changed, 25 insertions(+), 39 deletions(-) diff --git a/VariableAnalysis/Lib/Helpers.php b/VariableAnalysis/Lib/Helpers.php index d050ab5..5fe99a7 100644 --- a/VariableAnalysis/Lib/Helpers.php +++ b/VariableAnalysis/Lib/Helpers.php @@ -322,16 +322,12 @@ public static function findFunctionCall(File $phpcsFile, $stackPtr) if (is_int($functionPtr)) { $functionTokenCode = $tokens[$functionPtr]['code']; // In PHPCS 4.x, function names can be T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, or T_NAME_RELATIVE - $validFunctionTokens = [T_STRING]; - if (defined('T_NAME_FULLY_QUALIFIED')) { - $validFunctionTokens[] = T_NAME_FULLY_QUALIFIED; - } - if (defined('T_NAME_QUALIFIED')) { - $validFunctionTokens[] = T_NAME_QUALIFIED; - } - if (defined('T_NAME_RELATIVE')) { - $validFunctionTokens[] = T_NAME_RELATIVE; - } + $validFunctionTokens = [ + T_STRING, + T_NAME_FULLY_QUALIFIED, + T_NAME_QUALIFIED, + T_NAME_RELATIVE, + ]; if (in_array($functionTokenCode, $validFunctionTokens, true)) { return $functionPtr; } @@ -560,17 +556,10 @@ public static function findVariableScopeExceptArrowFunctions(File $phpcsFile, $s T_DOUBLE_QUOTED_STRING, T_HEREDOC, T_STRING, + T_NAME_FULLY_QUALIFIED, + T_NAME_QUALIFIED, + T_NAME_RELATIVE, ]; - // In PHPCS 4.x, function names can be T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, or T_NAME_RELATIVE - if (defined('T_NAME_FULLY_QUALIFIED')) { - $allowedTypes[] = T_NAME_FULLY_QUALIFIED; - } - if (defined('T_NAME_QUALIFIED')) { - $allowedTypes[] = T_NAME_QUALIFIED; - } - if (defined('T_NAME_RELATIVE')) { - $allowedTypes[] = T_NAME_RELATIVE; - } if (! in_array($tokens[$stackPtr]['code'], $allowedTypes, true)) { throw new \Exception("Cannot find variable scope for non-variable {$tokens[$stackPtr]['type']}"); } @@ -1705,28 +1694,25 @@ public static function getFunctionNameWithNamespace(File $phpcsFile, $stackPtr) // In PHPCS 4.x, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, and T_NAME_RELATIVE // tokens already contain the full namespaced name, so we can return early. - if (defined('T_NAME_FULLY_QUALIFIED') && $tokens[$stackPtr]['code'] === T_NAME_FULLY_QUALIFIED) { + if ($tokens[$stackPtr]['code'] === T_NAME_FULLY_QUALIFIED) { return $functionName; } - if (defined('T_NAME_QUALIFIED') && $tokens[$stackPtr]['code'] === T_NAME_QUALIFIED) { + if ($tokens[$stackPtr]['code'] === T_NAME_QUALIFIED) { return $functionName; } - if (defined('T_NAME_RELATIVE') && $tokens[$stackPtr]['code'] === T_NAME_RELATIVE) { + if ($tokens[$stackPtr]['code'] === T_NAME_RELATIVE) { return $functionName; } // Move backwards from the token, collecting namespace separators and // strings, until we encounter whitespace or something else. - $partOfNamespace = [T_NS_SEPARATOR, T_STRING]; - if (defined('T_NAME_QUALIFIED')) { - $partOfNamespace[] = T_NAME_QUALIFIED; - } - if (defined('T_NAME_RELATIVE')) { - $partOfNamespace[] = T_NAME_RELATIVE; - } - if (defined('T_NAME_FULLY_QUALIFIED')) { - $partOfNamespace[] = T_NAME_FULLY_QUALIFIED; - } + $partOfNamespace = [ + T_NS_SEPARATOR, + T_STRING, + T_NAME_QUALIFIED, + T_NAME_RELATIVE, + T_NAME_FULLY_QUALIFIED, + ]; for ($i = $stackPtr - 1; $i > $startOfScope; $i--) { if (! in_array($tokens[$i]['code'], $partOfNamespace, true)) { break; @@ -1751,13 +1737,13 @@ private static function isTokenPossiblyPartOfTypehint(File $phpcsFile, $stackPtr if ($token['code'] === 'PHPCS_T_NULLABLE') { return true; } - if (defined('T_NAME_QUALIFIED') && $token['code'] === T_NAME_QUALIFIED) { + if ($token['code'] === T_NAME_QUALIFIED) { return true; } - if (defined('T_NAME_RELATIVE') && $token['code'] === T_NAME_RELATIVE) { + if ($token['code'] === T_NAME_RELATIVE) { return true; } - if (defined('T_NAME_FULLY_QUALIFIED') && $token['code'] === T_NAME_FULLY_QUALIFIED) { + if ($token['code'] === T_NAME_FULLY_QUALIFIED) { return true; } if ($token['code'] === T_NS_SEPARATOR) { diff --git a/VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php b/VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php index cda95f6..b464c26 100644 --- a/VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php +++ b/VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php @@ -1508,17 +1508,17 @@ protected function processVariableAsPassByReferenceFunctionCall(File $phpcsFile, // tokens contain the full namespaced name. Extract just the base name for the // first check so that 'my_function' in the config can match '\My\Namespace\my_function'. $functionBaseName = $functionName; - if (defined('T_NAME_FULLY_QUALIFIED') && $tokens[$functionPtr]['code'] === T_NAME_FULLY_QUALIFIED) { + if ($tokens[$functionPtr]['code'] === T_NAME_FULLY_QUALIFIED) { $lastBackslashPos = strrpos($functionName, '\\'); if ($lastBackslashPos !== false) { $functionBaseName = substr($functionName, $lastBackslashPos + 1); } - } elseif (defined('T_NAME_QUALIFIED') && $tokens[$functionPtr]['code'] === T_NAME_QUALIFIED) { + } elseif ($tokens[$functionPtr]['code'] === T_NAME_QUALIFIED) { $lastBackslashPos = strrpos($functionName, '\\'); if ($lastBackslashPos !== false) { $functionBaseName = substr($functionName, $lastBackslashPos + 1); } - } elseif (defined('T_NAME_RELATIVE') && $tokens[$functionPtr]['code'] === T_NAME_RELATIVE) { + } elseif ($tokens[$functionPtr]['code'] === T_NAME_RELATIVE) { $lastBackslashPos = strrpos($functionName, '\\'); if ($lastBackslashPos !== false) { $functionBaseName = substr($functionName, $lastBackslashPos + 1); From 3f57187e7d2460d89df92c370afe7435d8d6315a Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 30 Sep 2025 18:05:03 -0400 Subject: [PATCH 7/8] Update github actions to raise min phpcs version to 3.5.7 --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 80c39bb..e625782 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,7 +35,7 @@ jobs: # # The matrix is set up so as not to duplicate the builds which are run for code coverage. php: ["5.5", "5.6", "7.0", "7.1", "7.2", "7.3"] - phpcs_version: ["3.5.6", "4.0.0", "4.x-dev"] + phpcs_version: ["3.5.7", "4.0.0", "4.x-dev"] exclude: # PHPCS 4.x requires PHP 7.2+ @@ -169,12 +169,12 @@ jobs: - php: "8.4" phpcs_version: "4.x-dev" - php: "7.4" - phpcs_version: "3.5.6" + phpcs_version: "3.5.7" - php: "7.2" phpcs_version: "4.x-dev" - php: "5.4" - phpcs_version: "3.5.6" + phpcs_version: "3.5.7" name: "Coverage: PHP ${{ matrix.php }} on PHPCS ${{ matrix.phpcs_version }}" From 5852a850593e3616447a748f52fc0094ca10bcae Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Tue, 30 Sep 2025 18:14:08 -0400 Subject: [PATCH 8/8] Remove unused isTokenInsideArrowFunctionDefinition --- VariableAnalysis/Lib/Helpers.php | 18 ------------------ psalm-baseline.xml | 3 --- 2 files changed, 21 deletions(-) diff --git a/VariableAnalysis/Lib/Helpers.php b/VariableAnalysis/Lib/Helpers.php index 5fe99a7..8b67f11 100644 --- a/VariableAnalysis/Lib/Helpers.php +++ b/VariableAnalysis/Lib/Helpers.php @@ -629,24 +629,6 @@ private static function getStartOfTokenScope(File $phpcsFile, $stackPtr) return 0; } - /** - * @param File $phpcsFile - * @param int $stackPtr - * - * @return bool - */ - public static function isTokenInsideArrowFunctionDefinition(File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $token = $tokens[$stackPtr]; - $openParenIndices = isset($token['nested_parenthesis']) ? $token['nested_parenthesis'] : []; - if (empty($openParenIndices)) { - return false; - } - $openParenPtr = $openParenIndices[0]; - return self::isArrowFunction($phpcsFile, $openParenPtr - 1); - } - /** * @param File $phpcsFile * @param int $stackPtr diff --git a/psalm-baseline.xml b/psalm-baseline.xml index bbc93ea..3bf1ba8 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -28,9 +28,6 @@ - - -