diff --git a/src/Files/File.php b/src/Files/File.php index 4d6414251b..b19738abf0 100644 --- a/src/Files/File.php +++ b/src/Files/File.php @@ -1735,18 +1735,20 @@ public function getMethodProperties($stackPtr) } $valid = [ - T_STRING => T_STRING, - T_CALLABLE => T_CALLABLE, - T_SELF => T_SELF, - T_PARENT => T_PARENT, - T_STATIC => T_STATIC, - T_FALSE => T_FALSE, - T_TRUE => T_TRUE, - T_NULL => T_NULL, - T_NAMESPACE => T_NAMESPACE, - T_NS_SEPARATOR => T_NS_SEPARATOR, - T_TYPE_UNION => T_TYPE_UNION, - T_TYPE_INTERSECTION => T_TYPE_INTERSECTION, + T_STRING => T_STRING, + T_CALLABLE => T_CALLABLE, + T_SELF => T_SELF, + T_PARENT => T_PARENT, + T_STATIC => T_STATIC, + T_FALSE => T_FALSE, + T_TRUE => T_TRUE, + T_NULL => T_NULL, + T_NAMESPACE => T_NAMESPACE, + T_NS_SEPARATOR => T_NS_SEPARATOR, + T_TYPE_UNION => T_TYPE_UNION, + T_TYPE_INTERSECTION => T_TYPE_INTERSECTION, + T_TYPE_OPEN_PARENTHESIS => T_TYPE_OPEN_PARENTHESIS, + T_TYPE_CLOSE_PARENTHESIS => T_TYPE_CLOSE_PARENTHESIS, ]; for ($i = $this->tokens[$stackPtr]['parenthesis_closer']; $i < $this->numTokens; $i++) { diff --git a/tests/Core/File/GetMethodPropertiesTest.inc b/tests/Core/File/GetMethodPropertiesTest.inc index 1bc2c4bd8d..7f572f66c5 100644 --- a/tests/Core/File/GetMethodPropertiesTest.inc +++ b/tests/Core/File/GetMethodPropertiesTest.inc @@ -170,6 +170,25 @@ function pseudoTypeTrue(): ?true {} // Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. function pseudoTypeFalseAndTrue(): true|false {} +/* testPHP82DNFType */ +function hasDNFType() : bool|(Foo&Bar)|string {} + +abstract class AbstractClass { + /* testPHP82DNFTypeAbstractMethod */ + abstract protected function abstractMethodDNFType() : float|(Foo&Bar); +} + +/* testPHP82DNFTypeIllegalNullable */ +// Intentional fatal error - nullable operator cannot be combined with DNF. +function illegalNullableDNF(): ?(A&\Pck\B)|bool {} + +/* testPHP82DNFTypeClosure */ +$closure = function() : object|(namespace\Foo&Countable) {}; + +/* testPHP82DNFTypeFn */ +// Intentional fatal error - void type cannot be combined with DNF. +$arrow = fn() : null|(Partially\Qualified&Traversable)|void => do_something(); + /* testNotAFunction */ return true; diff --git a/tests/Core/File/GetMethodPropertiesTest.php b/tests/Core/File/GetMethodPropertiesTest.php index 42649bc14e..273ff4b288 100644 --- a/tests/Core/File/GetMethodPropertiesTest.php +++ b/tests/Core/File/GetMethodPropertiesTest.php @@ -1187,6 +1187,136 @@ public function testPHP82PseudoTypeFalseAndTrue() }//end testPHP82PseudoTypeFalseAndTrue() + /** + * Verify recognition of PHP 8.2 DNF return type declaration. + * + * @return void + */ + public function testPHP82DNFType() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'bool|(Foo&Bar)|string', + 'return_type_token' => 8, + 'return_type_end_token' => 16, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFType() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration on an abstract method. + * + * @return void + */ + public function testPHP82DNFTypeAbstractMethod() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'protected', + 'scope_specified' => true, + 'return_type' => 'float|(Foo&Bar)', + 'return_type_token' => 8, + 'return_type_end_token' => 14, + 'nullable_return_type' => false, + 'is_abstract' => true, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeAbstractMethod() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration with illegal nullability. + * + * @return void + */ + public function testPHP82DNFTypeIllegalNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?(A&\Pck\B)|bool', + 'return_type_token' => 8, + 'return_type_end_token' => 17, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeIllegalNullable() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration on a closure. + * + * @return void + */ + public function testPHP82DNFTypeClosure() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'object|(namespace\Foo&Countable)', + 'return_type_token' => 6, + 'return_type_end_token' => 14, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeClosure() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration on an arrow function. + * + * @return void + */ + public function testPHP82DNFTypeFn() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'null|(Partially\Qualified&Traversable)|void', + 'return_type_token' => 6, + 'return_type_end_token' => 16, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeFn() + + /** * Test for incorrect tokenization of array return type declarations in PHPCS < 2.8.0. *