diff --git a/src/Files/File.php b/src/Files/File.php index 4d6414251b..6f516c4847 100644 --- a/src/Files/File.php +++ b/src/Files/File.php @@ -1419,7 +1419,9 @@ public function getMethodParameters($stackPtr) // it's likely to be an array which might have arguments in it. This // could cause problems in our parsing below, so lets just skip to the // end of it. - if (isset($this->tokens[$i]['parenthesis_opener']) === true) { + if ($this->tokens[$i]['code'] !== T_TYPE_OPEN_PARENTHESIS + && isset($this->tokens[$i]['parenthesis_opener']) === true + ) { // Don't do this if it's the close parenthesis for the method. if ($i !== $this->tokens[$i]['parenthesis_closer']) { $i = $this->tokens[$i]['parenthesis_closer']; @@ -1513,6 +1515,8 @@ public function getMethodParameters($stackPtr) case T_NS_SEPARATOR: case T_TYPE_UNION: case T_TYPE_INTERSECTION: + case T_TYPE_OPEN_PARENTHESIS: + case T_TYPE_CLOSE_PARENTHESIS: case T_FALSE: case T_TRUE: case T_NULL: diff --git a/tests/Core/File/GetMethodParametersTest.inc b/tests/Core/File/GetMethodParametersTest.inc index f6f3cd9ebf..1f72ccfaae 100644 --- a/tests/Core/File/GetMethodParametersTest.inc +++ b/tests/Core/File/GetMethodParametersTest.inc @@ -280,6 +280,23 @@ function newInInitializers( \Package\TypeB $newToo = new \Package\TypeB(10, 'string'), ) {} +/* testPHP82DNFTypes */ +function dnfTypes( + #[MyAttribute] + false|(Foo&Bar)|true $obj1, + (\Boo&\Pck\Bar)|(Boo&Baz) $obj2 = new Boo() +) {} + +/* testPHP82DNFTypesWithSpreadOperatorAndReference */ +function dnfInGlobalFunctionWithSpreadAndReference((Countable&MeMe)|iterable &$paramA, true|(Foo&Bar) ...$paramB) {} + +/* testPHP82DNFTypesIllegalNullable */ +// Intentional fatal error - nullable operator cannot be combined with DNF. +$dnf_closure = function (? ( MyClassA & /*comment*/ \Package\MyClassB & \Package\MyClassC ) $var): void {}; + +/* testPHP82DNFTypesInArrow */ +$dnf_arrow = fn((Hi&Ho)|FALSE &...$range): string => $a; + /* testFunctionCallFnPHPCS353-354 */ $value = $obj->fn(true); diff --git a/tests/Core/File/GetMethodParametersTest.php b/tests/Core/File/GetMethodParametersTest.php index 83419ddeaa..f8e7b22e27 100644 --- a/tests/Core/File/GetMethodParametersTest.php +++ b/tests/Core/File/GetMethodParametersTest.php @@ -2450,7 +2450,7 @@ public function testPHP8IntersectionTypes() /** - * Verify recognition of PHP8 intersection type declaration when the variable + * Verify recognition of PHP8.1 intersection type declaration when the variable * has either a spread operator or a reference. * * @return void @@ -2702,6 +2702,161 @@ public function testPHP81NewInInitializers() }//end testPHP81NewInInitializers() + /** + * Verify recognition of 8.2 DNF parameter type declarations. + * + * @return void + */ + public function testPHP82DNFTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 21, + 'name' => '$obj1', + 'content' => '#[MyAttribute] + false|(Foo&Bar)|true $obj1', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false|(Foo&Bar)|true', + 'type_hint_token' => 11, + 'type_hint_end_token' => 19, + 'nullable_type' => false, + 'comma_token' => 22, + ]; + $expected[1] = [ + 'token' => 41, + 'name' => '$obj2', + 'content' => '(\Boo&\Pck\Bar)|(Boo&Baz) $obj2 = new Boo()', + 'default' => 'new Boo()', + 'default_token' => 45, + 'default_equal_token' => 43, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '(\Boo&\Pck\Bar)|(Boo&Baz)', + 'type_hint_token' => 25, + 'type_hint_end_token' => 39, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypes() + + + /** + * Verify recognition of PHP 8.2 DNF parameter type declarations when the variable + * has either a spread operator or a reference. + * + * @return void + */ + public function testPHP82DNFTypesWithSpreadOperatorAndReference() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 13, + 'name' => '$paramA', + 'content' => '(Countable&MeMe)|iterable &$paramA', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 12, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '(Countable&MeMe)|iterable', + 'type_hint_token' => 4, + 'type_hint_end_token' => 10, + 'nullable_type' => false, + 'comma_token' => 14, + ]; + $expected[1] = [ + 'token' => 25, + 'name' => '$paramB', + 'content' => 'true|(Foo&Bar) ...$paramB', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 24, + 'type_hint' => 'true|(Foo&Bar)', + 'type_hint_token' => 16, + 'type_hint_end_token' => 22, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypesWithSpreadOperatorAndReference() + + + /** + * Verify recognition of PHP 8.2 DNF parameter type declarations using the nullability operator (not allowed). + * + * @return void + */ + public function testPHP82DNFTypesIllegalNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 27, + 'name' => '$var', + 'content' => '? ( MyClassA & /*comment*/ \Package\MyClassB & \Package\MyClassC ) $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?(MyClassA&\Package\MyClassB&\Package\MyClassC)', + 'type_hint_token' => 5, + 'type_hint_end_token' => 25, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypesIllegalNullable() + + + /** + * Verify recognition of PHP 8.2 DNF parameter type declarations in an arrow function. + * + * @return void + */ + public function testPHP82DNFTypesInArrow() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 12, + 'name' => '$range', + 'content' => '(Hi&Ho)|FALSE &...$range', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 10, + 'variable_length' => true, + 'variadic_token' => 11, + 'type_hint' => '(Hi&Ho)|FALSE', + 'type_hint_token' => 2, + 'type_hint_end_token' => 8, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypesInArrow() + + /** * Verify handling of a closure. *