diff --git a/package.xml b/package.xml index 9c56817854..27284b1a2e 100644 --- a/package.xml +++ b/package.xml @@ -30,6 +30,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> -- T_FN represents the fn string used for arrow functions -- The token is associated with the opening and closing parenthesis of the statement - File::getMethodParameters() now supports arrow functions + - File::getMethodProperties() now supports arrow functions - Generic.CodeAnalysis.EmptyPhpStatement now reports unnecessary semicolons after control structure closing braces -- Thanks to Vincent Langlet for the patch - Fixed bug #2638 : Squiz.CSS.DuplicateClassDefinitionSniff sees comments as part of the class name diff --git a/src/Files/File.php b/src/Files/File.php index 1ad271ed58..b64352d787 100644 --- a/src/Files/File.php +++ b/src/Files/File.php @@ -1543,14 +1543,15 @@ public function getMethodParameters($stackPtr) * * @return array * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a - * T_FUNCTION token. + * T_FUNCTION, T_CLOSURE, or T_FN token. */ public function getMethodProperties($stackPtr) { if ($this->tokens[$stackPtr]['code'] !== T_FUNCTION && $this->tokens[$stackPtr]['code'] !== T_CLOSURE + && $this->tokens[$stackPtr]['code'] !== T_FN ) { - throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE'); + throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); } if ($this->tokens[$stackPtr]['code'] === T_FUNCTION) { @@ -1650,8 +1651,14 @@ public function getMethodProperties($stackPtr) } } - $end = $this->findNext([T_OPEN_CURLY_BRACKET, T_SEMICOLON], $this->tokens[$stackPtr]['parenthesis_closer']); - $hasBody = $this->tokens[$end]['code'] === T_OPEN_CURLY_BRACKET; + if ($this->tokens[$stackPtr]['code'] === T_FN) { + $bodyToken = T_DOUBLE_ARROW; + } else { + $bodyToken = T_OPEN_CURLY_BRACKET; + } + + $end = $this->findNext([$bodyToken, T_SEMICOLON], $this->tokens[$stackPtr]['parenthesis_closer']); + $hasBody = $this->tokens[$end]['code'] === $bodyToken; }//end if if ($returnType !== '' && $nullableReturnType === true) { diff --git a/tests/Core/File/GetMethodPropertiesTest.inc b/tests/Core/File/GetMethodPropertiesTest.inc index 53a412b7bc..7b6223e6bd 100644 --- a/tests/Core/File/GetMethodPropertiesTest.inc +++ b/tests/Core/File/GetMethodPropertiesTest.inc @@ -60,3 +60,9 @@ interface MyInterface /* testInterfaceMethod */ function myFunction(); } + +$result = array_map( + /* testArrowFunction */ + static fn(int $number) : int => $number + 1, + $numbers +); diff --git a/tests/Core/File/GetMethodPropertiesTest.php b/tests/Core/File/GetMethodPropertiesTest.php index 1699a6db43..b0b2d5e9e2 100644 --- a/tests/Core/File/GetMethodPropertiesTest.php +++ b/tests/Core/File/GetMethodPropertiesTest.php @@ -360,6 +360,29 @@ public function testInterfaceMethod() }//end testInterfaceMethod() + /** + * Test a static arrow function. + * + * @return void + */ + public function testArrowFunction() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int', + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => true, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunction() + + /** * Test helper. * @@ -370,7 +393,7 @@ public function testInterfaceMethod() */ private function getMethodPropertiesTestHelper($commentString, $expected) { - $function = $this->getTargetToken($commentString, [T_FUNCTION, T_CLOSURE]); + $function = $this->getTargetToken($commentString, [T_FUNCTION, T_CLOSURE, T_FN]); $found = self::$phpcsFile->getMethodProperties($function); $this->assertArraySubset($expected, $found, true);