Skip to content

Commit c58e746

Browse files
committed
Fixed detection of T_NULLABLE for arrow functions (ref #2708)
1 parent 0b498ad commit c58e746

File tree

4 files changed

+43
-2
lines changed

4 files changed

+43
-2
lines changed

src/Standards/Squiz/Tests/PHP/DisallowInlineIfUnitTest.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ function foo(string $bar, array $baz, ?MyClass $object) : MyClass {}
1212
class Example {
1313
public ?int $scalarType;
1414
}
15+
16+
$a = fn(?\DateTime $x) : ?\DateTime => $x;

src/Tokenizers/PHP.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,7 @@ protected function tokenize($string)
10731073
}
10741074

10751075
if ($tokenType === T_FUNCTION
1076+
|| $tokenType === T_FN
10761077
|| isset(Util\Tokens::$methodPrefixes[$tokenType]) === true
10771078
) {
10781079
if (PHP_CODESNIFFER_VERBOSITY > 1) {
@@ -1285,6 +1286,11 @@ function return types. We want to keep the parenthesis map clean,
12851286
&& $token[0] === T_STRING
12861287
&& strtolower($token[1]) === 'fn'
12871288
) {
1289+
// Modify the original token stack so that
1290+
// future checks (like looking for T_NULLABLE) can
1291+
// detect the T_FN token more easily.
1292+
$tokens[$stackPtr][0] = T_FN;
1293+
12881294
$finalTokens[$newStackPtr] = [
12891295
'content' => $token[1],
12901296
'code' => T_FN,
@@ -1702,8 +1708,10 @@ protected function processAdditional()
17021708
if ($this->tokens[$x]['code'] === T_OPEN_PARENTHESIS) {
17031709
$ignore = Util\Tokens::$emptyTokens;
17041710
$ignore += [
1705-
T_STRING => T_STRING,
1706-
T_COLON => T_COLON,
1711+
T_STRING => T_STRING,
1712+
T_COLON => T_COLON,
1713+
T_NS_SEPARATOR => T_COLON,
1714+
T_NULLABLE => T_COLON,
17071715
];
17081716

17091717
$closer = $this->tokens[$x]['parenthesis_closer'];

tests/Core/Tokenizer/BackfillFnTokenTest.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,6 @@ $a = [
5454

5555
/* testYield */
5656
$a = fn($x) => yield 'k' => $x;
57+
58+
/* testNullableNamespace */
59+
$a = fn(?\DateTime $x) : ?\DateTime => $x;

tests/Core/Tokenizer/BackfillFnTokenTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,34 @@ public function testYield()
431431
}//end testYield()
432432

433433

434+
/**
435+
* Test arrow functions that use nullable namespace types.
436+
*
437+
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
438+
*
439+
* @return void
440+
*/
441+
public function testNullableNamespace()
442+
{
443+
$tokens = self::$phpcsFile->getTokens();
444+
445+
$token = $this->getTargetToken('/* testNullableNamespace */', T_FN);
446+
$this->backfillHelper($token);
447+
448+
$this->assertSame($tokens[$token]['scope_opener'], ($token + 15), 'Scope opener is not the arrow token');
449+
$this->assertSame($tokens[$token]['scope_closer'], ($token + 18), 'Scope closer is not the semicolon token');
450+
451+
$opener = $tokens[$token]['scope_opener'];
452+
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 15), 'Opener scope opener is not the arrow token');
453+
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 18), 'Opener scope closer is not the semicolon token');
454+
455+
$closer = $tokens[$token]['scope_opener'];
456+
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 15), 'Closer scope opener is not the arrow token');
457+
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 18), 'Closer scope closer is not the semicolon token');
458+
459+
}//end testNullableNamespace()
460+
461+
434462
/**
435463
* Test that anonymous class tokens without parenthesis do not get assigned a parenthesis owner.
436464
*

0 commit comments

Comments
 (0)