Skip to content

Commit

Permalink
Merge pull request #453 from PHPCSStandards/feature/tokenizer-php-fix…
Browse files Browse the repository at this point in the history
…-bug-arrow-functions-true-false-type

Tokenizer/PHP: arrow function tokenization broken when true/false used in return type
  • Loading branch information
jrfnl authored Apr 22, 2024
2 parents 5f38ce0 + bd6356c commit b0d2d61
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 34 deletions.
2 changes: 2 additions & 0 deletions src/Tokenizers/PHP.php
Original file line number Diff line number Diff line change
Expand Up @@ -2718,6 +2718,8 @@ protected function processAdditional()
T_NAMESPACE => T_NAMESPACE,
T_NS_SEPARATOR => T_NS_SEPARATOR,
T_NULL => T_NULL,
T_TRUE => T_TRUE,
T_FALSE => T_FALSE,
T_NULLABLE => T_NULLABLE,
T_PARENT => T_PARENT,
T_SELF => T_SELF,
Expand Down
15 changes: 15 additions & 0 deletions tests/Core/Tokenizer/BackfillFnTokenTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,27 @@ fn(array $a) : array => $a;
/* testStaticReturnType */
fn(array $a) : static => $a;

/* testFalseReturnType */
fn(array $a) : false => $a;

/* testTrueReturnType */
fn(array $a) : True => $a;

/* testNullReturnType */
fn(array $a) : null => $a;

/* testUnionParamType */
$arrowWithUnionParam = fn(int|float $param) : SomeClass => new SomeClass($param);

/* testUnionReturnType */
$arrowWithUnionReturn = fn($param) : int|float => $param | 10;

/* testUnionReturnTypeWithTrue */
$arrowWithUnionReturn = fn($param) : int|true => $param | 10;

/* testUnionReturnTypeWithFalse */
$arrowWithUnionReturn = fn($param) : string|FALSE => $param | 10;

/* testTernary */
$fn = fn($a) => $a ? /* testTernaryThen */ fn() : string => 'a' : /* testTernaryElse */ fn() : string => 'b';

Expand Down
141 changes: 107 additions & 34 deletions tests/Core/Tokenizer/BackfillFnTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,43 @@ final class BackfillFnTokenTest extends AbstractTokenizerTestCase
/**
* Test simple arrow functions.
*
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
* @param string $testMarker The comment prefacing the target token.
*
* @dataProvider dataSimple
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
*
* @return void
*/
public function testSimple()
public function testSimple($testMarker)
{
foreach (['/* testStandard */', '/* testMixedCase */'] as $comment) {
$token = $this->getTargetToken($comment, T_FN);
$this->backfillHelper($token);
$this->scopePositionTestHelper($token, 5, 12);
}
$token = $this->getTargetToken($testMarker, T_FN);
$this->backfillHelper($token);
$this->scopePositionTestHelper($token, 5, 12);

}//end testSimple()


/**
* Data provider.
*
* @see testSimple()
*
* @return array<string, array<string, string>>
*/
public static function dataSimple()
{
return [
'standard' => [
'testMarker' => '/* testStandard */',
],
'mixed case' => [
'testMarker' => '/* testMixedCase */',
],
];

}//end dataSimple()


/**
* Test whitespace inside arrow function definitions.
*
Expand Down Expand Up @@ -370,44 +392,63 @@ public function testNamespaceOperatorInTypes()


/**
* Test arrow functions that use self/parent/callable/array/static return types.
* Test arrow functions that use keyword return types.
*
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
* @param string $testMarker The comment prefacing the target token.
*
* @dataProvider dataKeywordReturnTypes
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
*
* @return void
*/
public function testKeywordReturnTypes()
public function testKeywordReturnTypes($testMarker)
{
$tokens = $this->phpcsFile->getTokens();

$testMarkers = [
'Self',
'Parent',
'Callable',
'Array',
'Static',
];

foreach ($testMarkers as $marker) {
$token = $this->getTargetToken('/* test'.$marker.'ReturnType */', T_FN);
$this->backfillHelper($token);

$expectedScopeOpener = ($token + 11);
$expectedScopeCloser = ($token + 14);
$token = $this->getTargetToken($testMarker, T_FN);
$this->backfillHelper($token);
$this->scopePositionTestHelper($token, 11, 14);

$this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], "Scope opener is not the arrow token (for $marker)");
$this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], "Scope closer is not the semicolon token(for $marker)");
}//end testKeywordReturnTypes()

$opener = $tokens[$token]['scope_opener'];
$this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], "Opener scope opener is not the arrow token(for $marker)");
$this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], "Opener scope closer is not the semicolon token(for $marker)");

$closer = $tokens[$token]['scope_closer'];
$this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], "Closer scope opener is not the arrow token(for $marker)");
$this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], "Closer scope closer is not the semicolon token(for $marker)");
}
/**
* Data provider.
*
* @see testKeywordReturnTypes()
*
* @return array<string, array<string, string>>
*/
public static function dataKeywordReturnTypes()
{
return [
'self' => [
'testMarker' => '/* testSelfReturnType */',
],
'parent' => [
'testMarker' => '/* testParentReturnType */',
],
'callable' => [
'testMarker' => '/* testCallableReturnType */',
],
'array' => [
'testMarker' => '/* testArrayReturnType */',
],
'static' => [
'testMarker' => '/* testStaticReturnType */',
],
'false' => [
'testMarker' => '/* testFalseReturnType */',
],
'true' => [
'testMarker' => '/* testTrueReturnType */',
],
'null' => [
'testMarker' => '/* testNullReturnType */',
],
];

}//end testKeywordReturnTypes()
}//end dataKeywordReturnTypes()


/**
Expand Down Expand Up @@ -442,6 +483,38 @@ public function testUnionReturnType()
}//end testUnionReturnType()


/**
* Test arrow function with a union return type.
*
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
*
* @return void
*/
public function testUnionReturnTypeWithTrue()
{
$token = $this->getTargetToken('/* testUnionReturnTypeWithTrue */', T_FN);
$this->backfillHelper($token);
$this->scopePositionTestHelper($token, 11, 18);

}//end testUnionReturnTypeWithTrue()


/**
* Test arrow function with a union return type.
*
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
*
* @return void
*/
public function testUnionReturnTypeWithFalse()
{
$token = $this->getTargetToken('/* testUnionReturnTypeWithFalse */', T_FN);
$this->backfillHelper($token);
$this->scopePositionTestHelper($token, 11, 18);

}//end testUnionReturnTypeWithFalse()


/**
* Test arrow functions used in ternary operators.
*
Expand Down

0 comments on commit b0d2d61

Please sign in to comment.