-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Tokenizer/PHP: support PHP8 magic constant dereferencing
As of PHP 8, magic constants can be dereferenced, however, the square brackets are incorrectly tokenized as _short array_ brackets instead of as "normal" square brackets. Fixed by: * Adding a new `$magicConstants` array to the `Util\Tokens` calls. * Adding the `$magicConstants` to the allowed tokens for leaving the brackets alone in the PHP Tokenizer class. Includes adding unit tests for this section of the `PHP::processAdditional()` method. I've added as many relevant syntaxes as I could come up with, but won't claim that the unit test case file covers every possible scenario. Should be a good start though. Ref: https://wiki.php.net/rfc/variable_syntax_tweaks#constants_and_magic_constants
- Loading branch information
Showing
5 changed files
with
247 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
<?php | ||
|
||
/* | ||
* Square brackets. | ||
*/ | ||
|
||
/* testArrayAccess1 */ | ||
$var = $array[10]; | ||
|
||
$var = $array[++$y]/* testArrayAccess2 */[$x]; | ||
|
||
/* testArrayAssignment */ | ||
$array[] = $var; | ||
|
||
/* testFunctionCallDereferencing */ | ||
$var = function_call()[$x]; | ||
|
||
/* testMethodCallDereferencing */ | ||
$var = $obj->function_call()[$x]; | ||
|
||
/* testStaticMethodCallDereferencing */ | ||
$var = ClassName::function_call()[$x]; | ||
|
||
/* testPropertyDereferencing */ | ||
$var = $obj->property[2]; | ||
|
||
/* testPropertyDereferencingWithInaccessibleName */ | ||
$var = $ref->{'ref-type'}[1]; | ||
|
||
/* testStaticPropertyDereferencing */ | ||
$var ClassName::$property[2]; | ||
|
||
/* testStringDereferencing */ | ||
$var = 'PHP'[1]; | ||
|
||
/* testStringDereferencingDoubleQuoted */ | ||
$var = "PHP"[$y]; | ||
|
||
/* testConstantDereferencing */ | ||
$var = MY_CONSTANT[1]; | ||
|
||
/* testClassConstantDereferencing */ | ||
$var ClassName::CONSTANT_NAME[2]; | ||
|
||
/* testMagicConstantDereferencing */ | ||
$var = __FILE__[0]; | ||
|
||
/* testArrayAccessCurlyBraces */ | ||
$var = $array{'key'}['key']; | ||
|
||
/* testArrayLiteralDereferencing */ | ||
echo array(1, 2, 3)[0]; | ||
|
||
echo [1, 2, 3]/* testShortArrayLiteralDereferencing */[0]; | ||
|
||
/* testClassMemberDereferencingOnInstantiation1 */ | ||
(new foo)[0]; | ||
|
||
/* testClassMemberDereferencingOnInstantiation2 */ | ||
$a = (new Foo( array(1, array(4, 5), 3) ))[1][0]; | ||
|
||
/* testClassMemberDereferencingOnClone */ | ||
echo (clone $iterable)[20]; | ||
|
||
|
||
/* | ||
* Short array brackets. | ||
*/ | ||
|
||
/* testShortArrayDeclarationEmpty */ | ||
$array = []; | ||
|
||
/* testShortArrayDeclarationWithOneValue */ | ||
$array = [1]; | ||
|
||
/* testShortArrayDeclarationWithMultipleValues */ | ||
$array = [1, 2, 3]; | ||
|
||
/* testShortArrayDeclarationWithDereferencing */ | ||
echo [1, 2, 3][0]; | ||
|
||
/* testShortListDeclaration */ | ||
[ $a, $b ] = $array; | ||
|
||
[ $a, $b, /* testNestedListDeclaration */, [$c, $d]] = $array; | ||
|
||
/* testArrayWithinFunctionCall */ | ||
$var = functionCall([$x, $y]); | ||
|
||
/* testLiveCoding */ | ||
// Intentional parse error. This has to be the last test in the file. | ||
$array = [ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
<?php | ||
/** | ||
* Tests the conversion of square bracket tokens to short array tokens. | ||
* | ||
* @author Juliette Reinders Folmer <[email protected]> | ||
* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) | ||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence | ||
*/ | ||
|
||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer; | ||
|
||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; | ||
|
||
class ShortArrayTest extends AbstractMethodUnitTest | ||
{ | ||
|
||
|
||
/** | ||
* Test that real square brackets are still tokenized as square brackets. | ||
* | ||
* @param string $testMarker The comment which prefaces the target token in the test file. | ||
* | ||
* @dataProvider dataSquareBrackets | ||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional | ||
* | ||
* @return void | ||
*/ | ||
public function testSquareBrackets($testMarker) | ||
{ | ||
$tokens = self::$phpcsFile->getTokens(); | ||
|
||
$opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]); | ||
$this->assertSame(T_OPEN_SQUARE_BRACKET, $tokens[$opener]['code']); | ||
$this->assertSame('T_OPEN_SQUARE_BRACKET', $tokens[$opener]['type']); | ||
|
||
if (isset($tokens[$opener]['bracket_closer']) === true) { | ||
$closer = $tokens[$opener]['bracket_closer']; | ||
$this->assertSame(T_CLOSE_SQUARE_BRACKET, $tokens[$closer]['code']); | ||
$this->assertSame('T_CLOSE_SQUARE_BRACKET', $tokens[$closer]['type']); | ||
} | ||
|
||
}//end testSquareBrackets() | ||
|
||
|
||
/** | ||
* Data provider. | ||
* | ||
* @see testSquareBrackets() | ||
* | ||
* @return array | ||
*/ | ||
public function dataSquareBrackets() | ||
{ | ||
return [ | ||
['/* testArrayAccess1 */'], | ||
['/* testArrayAccess2 */'], | ||
['/* testArrayAssignment */'], | ||
['/* testFunctionCallDereferencing */'], | ||
['/* testMethodCallDereferencing */'], | ||
['/* testStaticMethodCallDereferencing */'], | ||
['/* testPropertyDereferencing */'], | ||
['/* testPropertyDereferencingWithInaccessibleName */'], | ||
['/* testStaticPropertyDereferencing */'], | ||
['/* testStringDereferencing */'], | ||
['/* testStringDereferencingDoubleQuoted */'], | ||
['/* testConstantDereferencing */'], | ||
['/* testClassConstantDereferencing */'], | ||
['/* testMagicConstantDereferencing */'], | ||
['/* testArrayAccessCurlyBraces */'], | ||
['/* testArrayLiteralDereferencing */'], | ||
['/* testShortArrayLiteralDereferencing */'], | ||
['/* testClassMemberDereferencingOnInstantiation1 */'], | ||
['/* testClassMemberDereferencingOnInstantiation2 */'], | ||
['/* testClassMemberDereferencingOnClone */'], | ||
['/* testLiveCoding */'], | ||
]; | ||
|
||
}//end dataSquareBrackets() | ||
|
||
|
||
/** | ||
* Test that short arrays and short lists are still tokenized as short arrays. | ||
* | ||
* @param string $testMarker The comment which prefaces the target token in the test file. | ||
* | ||
* @dataProvider dataShortArrays | ||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional | ||
* | ||
* @return void | ||
*/ | ||
public function testShortArrays($testMarker) | ||
{ | ||
$tokens = self::$phpcsFile->getTokens(); | ||
|
||
$opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]); | ||
$this->assertSame(T_OPEN_SHORT_ARRAY, $tokens[$opener]['code']); | ||
$this->assertSame('T_OPEN_SHORT_ARRAY', $tokens[$opener]['type']); | ||
|
||
if (isset($tokens[$opener]['bracket_closer']) === true) { | ||
$closer = $tokens[$opener]['bracket_closer']; | ||
$this->assertSame(T_CLOSE_SHORT_ARRAY, $tokens[$closer]['code']); | ||
$this->assertSame('T_CLOSE_SHORT_ARRAY', $tokens[$closer]['type']); | ||
} | ||
|
||
}//end testShortArrays() | ||
|
||
|
||
/** | ||
* Data provider. | ||
* | ||
* @see testShortArrays() | ||
* | ||
* @return array | ||
*/ | ||
public function dataShortArrays() | ||
{ | ||
return [ | ||
['/* testShortArrayDeclarationEmpty */'], | ||
['/* testShortArrayDeclarationWithOneValue */'], | ||
['/* testShortArrayDeclarationWithMultipleValues */'], | ||
['/* testShortArrayDeclarationWithDereferencing */'], | ||
['/* testShortListDeclaration */'], | ||
['/* testNestedListDeclaration */'], | ||
['/* testArrayWithinFunctionCall */'], | ||
]; | ||
|
||
}//end dataShortArrays() | ||
|
||
|
||
}//end class |