Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tokenizer/PHP: arrow function tokenization broken when true/false used in return type #453

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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