Skip to content

Commit 4289bfc

Browse files
committed
WIP ContextHelper::is_token_namespaced(): update for PHPCS 4.0
The tokenization of (namespaced) "names" has changed in PHP 8.0, and this new tokenization will come into effect for PHP_CodeSniffer as of version 4.0.0. This commit adds handling for the new tokenization when determining if a token is namespaced or not. Since the tokenization of namespaced names changed between PHPCS 3 and 4, it was necessary to use different logic depending on the PHPCS version. TODO check if the approach to support both PHPCS 3 and 4 is good.
1 parent 73fc40f commit 4289bfc

File tree

2 files changed

+65
-8
lines changed

2 files changed

+65
-8
lines changed

WordPress/Helpers/ContextHelper.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
use PHP_CodeSniffer\Files\File;
1313
use PHP_CodeSniffer\Util\Tokens;
14+
use PHPCSUtils\BackCompat\Helper;
1415
use PHPCSUtils\Tokens\Collections;
1516
use PHPCSUtils\Utils\Parentheses;
1617
use PHPCSUtils\Utils\PassedParameters;
@@ -176,6 +177,28 @@ public static function is_token_namespaced( File $phpcsFile, $stackPtr ) {
176177
return false;
177178
}
178179

180+
$isPhpcs3 = version_compare( Helper::getVersion(), '3.99.99', '<=' );
181+
182+
if ( true === $isPhpcs3 ) {
183+
return self::is_token_namespaced_phpcs3( $phpcsFile, $stackPtr );
184+
} else {
185+
return self::is_token_namespaced_phpcs4( $phpcsFile, $stackPtr );
186+
}
187+
}
188+
189+
/**
190+
* Check if a particular token is prefixed with a namespace when running PHPCS <= 3. Different
191+
* methods are necessary because, the tokenization of namespaced names changed between PHPCS 3
192+
* and 4.
193+
*
194+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
195+
* @param int $stackPtr The index of the token in the stack.
196+
*
197+
* @return bool
198+
*/
199+
private static function is_token_namespaced_phpcs3( File $phpcsFile, $stackPtr ) {
200+
$tokens = $phpcsFile->getTokens();
201+
179202
$prev = $phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true );
180203

181204
if ( \T_NS_SEPARATOR !== $tokens[ $prev ]['code'] ) {
@@ -192,6 +215,35 @@ public static function is_token_namespaced( File $phpcsFile, $stackPtr ) {
192215
return true;
193216
}
194217

218+
/**
219+
* Check if a particular token is prefixed with a namespace when running PHPCS <= 4. Different
220+
* methods are necessary because, the tokenization of namespaced names changed between PHPCS 3
221+
* and 4.
222+
*
223+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
224+
* @param int $stackPtr The index of the token in the stack.
225+
*
226+
* @return bool
227+
*/
228+
private static function is_token_namespaced_phpcs4( File $phpcsFile, $stackPtr ) {
229+
$tokens = $phpcsFile->getTokens();
230+
231+
if ( \T_NAME_QUALIFIED === $tokens[ $stackPtr ]['code']
232+
|| \T_NAME_RELATIVE === $tokens[ $stackPtr ]['code']
233+
) {
234+
return true;
235+
}
236+
237+
// If the token is a fully qualified name, this methods consider it as namespaced if it
238+
// contains more than one namespace separator (i.e., not in the global namespace).
239+
if ( \T_NAME_FULLY_QUALIFIED === $tokens[ $stackPtr ]['code']
240+
&& \substr_count( $tokens[ $stackPtr ]['content'], '\\' ) > 1 ) {
241+
return true;
242+
}
243+
244+
return false;
245+
}
246+
195247
/**
196248
* Check if a token is (part of) a parameter for a function call to a select list of functions.
197249
*

WordPress/Util/Tests/Helpers/ContextHelper/IsTokenNamespacedUnitTest.php

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
namespace WordPressCS\WordPress\Util\Tests\Helpers\ContextHelper;
1111

12+
use PHPCSUtils\BackCompat\Helper;
1213
use PHPCSUtils\Tokens\Collections;
1314
use WordPressCS\WordPress\Helpers\ContextHelper;
1415
use PHPCSUtils\TestUtils\UtilityMethodTestCase;
@@ -53,13 +54,15 @@ public function testIsTokenNamespacedShouldReturnFalse( $commentString, $tokenCo
5354
* @see testIsTokenNamespacedShouldReturnFalse()
5455
*/
5556
public static function dataIsTokenNamespacedShouldReturnFalse() {
57+
$isPhpcs3 = version_compare( Helper::getVersion(), '3.99.99', '<=' );
58+
5659
return array(
5760
array( '/* test return false 1 */', 'my_function' ),
58-
array( '/* test return false 2 */', 'my_function' ),
61+
array( '/* test return false 2 */', ( $isPhpcs3 ? 'my_function' : '\my_function' ) ),
5962
array( '/* test return false 3 */', 'MyClass' ),
60-
array( '/* test return false 4 */', 'MyClass' ),
63+
array( '/* test return false 4 */', ( $isPhpcs3 ? 'MyClass' : '\MyClass' ) ),
6164
array( '/* test return false 5 */', 'MY_CONSTANT' ),
62-
array( '/* test return false 6 */', 'MY_CONSTANT' ),
65+
array( '/* test return false 6 */', ( $isPhpcs3 ? 'MY_CONSTANT' : '\MY_CONSTANT' ) ),
6366
);
6467
}
6568

@@ -85,12 +88,14 @@ public function testIsTokenNamespacedShouldReturnTrue( $commentString, $tokenCon
8588
* @see testIsTokenNamespacedShouldReturnTrue()
8689
*/
8790
public static function dataIsTokenNamespacedShouldReturnTrue() {
91+
$isPhpcs3 = version_compare( Helper::getVersion(), '3.99.99', '<=' );
92+
8893
return array(
89-
array( '/* test return true 1 */', 'my_function' ),
90-
array( '/* test return true 2 */', 'my_function' ),
91-
array( '/* test return true 3 */', 'my_function' ),
92-
array( '/* test return true 4 */', 'MyClass' ),
93-
array( '/* test return true 5 */', 'MY_CONSTANT' ),
94+
array( '/* test return true 1 */', ( $isPhpcs3 ? 'my_function' : 'MyNamespace\my_function' ) ),
95+
array( '/* test return true 2 */', ( $isPhpcs3 ? 'my_function' : '\MyNamespace\my_function' ) ),
96+
array( '/* test return true 3 */', ( $isPhpcs3 ? 'my_function' : 'namespace\my_function' ) ),
97+
array( '/* test return true 4 */', ( $isPhpcs3 ? 'MyClass' : 'MyNamespace\MyClass' ) ),
98+
array( '/* test return true 5 */', ( $isPhpcs3 ? 'MY_CONSTANT' : 'MyNamespace\MY_CONSTANT' ) ),
9499
);
95100
}
96101
}

0 commit comments

Comments
 (0)