Skip to content

Commit b0d2d61

Browse files
authored
Merge pull request #453 from PHPCSStandards/feature/tokenizer-php-fix-bug-arrow-functions-true-false-type
Tokenizer/PHP: arrow function tokenization broken when true/false used in return type
2 parents 5f38ce0 + bd6356c commit b0d2d61

File tree

3 files changed

+124
-34
lines changed

3 files changed

+124
-34
lines changed

src/Tokenizers/PHP.php

+2
Original file line numberDiff line numberDiff line change
@@ -2718,6 +2718,8 @@ protected function processAdditional()
27182718
T_NAMESPACE => T_NAMESPACE,
27192719
T_NS_SEPARATOR => T_NS_SEPARATOR,
27202720
T_NULL => T_NULL,
2721+
T_TRUE => T_TRUE,
2722+
T_FALSE => T_FALSE,
27212723
T_NULLABLE => T_NULLABLE,
27222724
T_PARENT => T_PARENT,
27232725
T_SELF => T_SELF,

tests/Core/Tokenizer/BackfillFnTokenTest.inc

+15
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,27 @@ fn(array $a) : array => $a;
9292
/* testStaticReturnType */
9393
fn(array $a) : static => $a;
9494

95+
/* testFalseReturnType */
96+
fn(array $a) : false => $a;
97+
98+
/* testTrueReturnType */
99+
fn(array $a) : True => $a;
100+
101+
/* testNullReturnType */
102+
fn(array $a) : null => $a;
103+
95104
/* testUnionParamType */
96105
$arrowWithUnionParam = fn(int|float $param) : SomeClass => new SomeClass($param);
97106

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

110+
/* testUnionReturnTypeWithTrue */
111+
$arrowWithUnionReturn = fn($param) : int|true => $param | 10;
112+
113+
/* testUnionReturnTypeWithFalse */
114+
$arrowWithUnionReturn = fn($param) : string|FALSE => $param | 10;
115+
101116
/* testTernary */
102117
$fn = fn($a) => $a ? /* testTernaryThen */ fn() : string => 'a' : /* testTernaryElse */ fn() : string => 'b';
103118

tests/Core/Tokenizer/BackfillFnTokenTest.php

+107-34
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,43 @@ final class BackfillFnTokenTest extends AbstractTokenizerTestCase
1616
/**
1717
* Test simple arrow functions.
1818
*
19-
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
19+
* @param string $testMarker The comment prefacing the target token.
20+
*
21+
* @dataProvider dataSimple
22+
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
2023
*
2124
* @return void
2225
*/
23-
public function testSimple()
26+
public function testSimple($testMarker)
2427
{
25-
foreach (['/* testStandard */', '/* testMixedCase */'] as $comment) {
26-
$token = $this->getTargetToken($comment, T_FN);
27-
$this->backfillHelper($token);
28-
$this->scopePositionTestHelper($token, 5, 12);
29-
}
28+
$token = $this->getTargetToken($testMarker, T_FN);
29+
$this->backfillHelper($token);
30+
$this->scopePositionTestHelper($token, 5, 12);
3031

3132
}//end testSimple()
3233

3334

35+
/**
36+
* Data provider.
37+
*
38+
* @see testSimple()
39+
*
40+
* @return array<string, array<string, string>>
41+
*/
42+
public static function dataSimple()
43+
{
44+
return [
45+
'standard' => [
46+
'testMarker' => '/* testStandard */',
47+
],
48+
'mixed case' => [
49+
'testMarker' => '/* testMixedCase */',
50+
],
51+
];
52+
53+
}//end dataSimple()
54+
55+
3456
/**
3557
* Test whitespace inside arrow function definitions.
3658
*
@@ -370,44 +392,63 @@ public function testNamespaceOperatorInTypes()
370392

371393

372394
/**
373-
* Test arrow functions that use self/parent/callable/array/static return types.
395+
* Test arrow functions that use keyword return types.
374396
*
375-
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
397+
* @param string $testMarker The comment prefacing the target token.
398+
*
399+
* @dataProvider dataKeywordReturnTypes
400+
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
376401
*
377402
* @return void
378403
*/
379-
public function testKeywordReturnTypes()
404+
public function testKeywordReturnTypes($testMarker)
380405
{
381406
$tokens = $this->phpcsFile->getTokens();
382407

383-
$testMarkers = [
384-
'Self',
385-
'Parent',
386-
'Callable',
387-
'Array',
388-
'Static',
389-
];
390-
391-
foreach ($testMarkers as $marker) {
392-
$token = $this->getTargetToken('/* test'.$marker.'ReturnType */', T_FN);
393-
$this->backfillHelper($token);
394-
395-
$expectedScopeOpener = ($token + 11);
396-
$expectedScopeCloser = ($token + 14);
408+
$token = $this->getTargetToken($testMarker, T_FN);
409+
$this->backfillHelper($token);
410+
$this->scopePositionTestHelper($token, 11, 14);
397411

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

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

405-
$closer = $tokens[$token]['scope_closer'];
406-
$this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], "Closer scope opener is not the arrow token(for $marker)");
407-
$this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], "Closer scope closer is not the semicolon token(for $marker)");
408-
}
415+
/**
416+
* Data provider.
417+
*
418+
* @see testKeywordReturnTypes()
419+
*
420+
* @return array<string, array<string, string>>
421+
*/
422+
public static function dataKeywordReturnTypes()
423+
{
424+
return [
425+
'self' => [
426+
'testMarker' => '/* testSelfReturnType */',
427+
],
428+
'parent' => [
429+
'testMarker' => '/* testParentReturnType */',
430+
],
431+
'callable' => [
432+
'testMarker' => '/* testCallableReturnType */',
433+
],
434+
'array' => [
435+
'testMarker' => '/* testArrayReturnType */',
436+
],
437+
'static' => [
438+
'testMarker' => '/* testStaticReturnType */',
439+
],
440+
'false' => [
441+
'testMarker' => '/* testFalseReturnType */',
442+
],
443+
'true' => [
444+
'testMarker' => '/* testTrueReturnType */',
445+
],
446+
'null' => [
447+
'testMarker' => '/* testNullReturnType */',
448+
],
449+
];
409450

410-
}//end testKeywordReturnTypes()
451+
}//end dataKeywordReturnTypes()
411452

412453

413454
/**
@@ -442,6 +483,38 @@ public function testUnionReturnType()
442483
}//end testUnionReturnType()
443484

444485

486+
/**
487+
* Test arrow function with a union return type.
488+
*
489+
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
490+
*
491+
* @return void
492+
*/
493+
public function testUnionReturnTypeWithTrue()
494+
{
495+
$token = $this->getTargetToken('/* testUnionReturnTypeWithTrue */', T_FN);
496+
$this->backfillHelper($token);
497+
$this->scopePositionTestHelper($token, 11, 18);
498+
499+
}//end testUnionReturnTypeWithTrue()
500+
501+
502+
/**
503+
* Test arrow function with a union return type.
504+
*
505+
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
506+
*
507+
* @return void
508+
*/
509+
public function testUnionReturnTypeWithFalse()
510+
{
511+
$token = $this->getTargetToken('/* testUnionReturnTypeWithFalse */', T_FN);
512+
$this->backfillHelper($token);
513+
$this->scopePositionTestHelper($token, 11, 18);
514+
515+
}//end testUnionReturnTypeWithFalse()
516+
517+
445518
/**
446519
* Test arrow functions used in ternary operators.
447520
*

0 commit comments

Comments
 (0)