Skip to content

Commit 3f5e10a

Browse files
committed
Tokenizer/PHP: arrow function tokenization broken when true/false used in return type
Since PHP 8.0, `false` and `null` can be included in a union return type. As of PHP 8.2, both `true`, `false` and `null` can be used as a stand-alone return type. The tokenizer layer handling arrow functions did not take this into account correctly. While `null` was handled correctly, `true` and `false` was not and would result in the arrow function `fn` keyword being tokenized as `T_STRING` across all PHP versions. As a result of that, the other typical tokenizer changes related to arrow functions (`=>` as `T_FN_ARROW`, scope/parenthesis owners etc) would also not be executed correctly. In practice, I suspect few people will have run into this bug as, after all, what's the point of declaring an arrow function which will only ever return `true` or `false` ? so in practice, it is likely to only have come into play for people using `true` or `false` as part of an arrow function union type. All the same, PHPCS should handle this correctly. Includes unit tests proving the bug and safeguarding the fix.
1 parent b38847b commit 3f5e10a

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
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

+41
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,15 @@ public static function dataKeywordReturnTypes()
437437
'static' => [
438438
'testMarker' => '/* testStaticReturnType */',
439439
],
440+
'false' => [
441+
'testMarker' => '/* testFalseReturnType */',
442+
],
443+
'true' => [
444+
'testMarker' => '/* testTrueReturnType */',
445+
],
446+
'null' => [
447+
'testMarker' => '/* testNullReturnType */',
448+
],
440449
];
441450

442451
}//end dataKeywordReturnTypes()
@@ -474,6 +483,38 @@ public function testUnionReturnType()
474483
}//end testUnionReturnType()
475484

476485

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+
477518
/**
478519
* Test arrow functions used in ternary operators.
479520
*

0 commit comments

Comments
 (0)