Skip to content

Commit

Permalink
Merge pull request #421 from PHPCSStandards/feature/getmethodproperti…
Browse files Browse the repository at this point in the history
…es-bugfix-skip-closure-use

File::getMethodProperties(): skip over closure use statements
  • Loading branch information
jrfnl authored Apr 3, 2024
2 parents a6b9bfa + 0dff1a5 commit 82ad715
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/Files/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,20 @@ public function getMethodProperties($stackPtr)
break;
}

if ($this->tokens[$i]['code'] === T_USE) {
// Skip over closure use statements.
for ($j = ($i + 1); $j < $this->numTokens && isset(Tokens::$emptyTokens[$this->tokens[$j]['code']]) === true; $j++);
if ($this->tokens[$j]['code'] === T_OPEN_PARENTHESIS) {
if (isset($this->tokens[$j]['parenthesis_closer']) === false) {
// Live coding/parse error, stop parsing.
break;
}

$i = $this->tokens[$j]['parenthesis_closer'];
continue;
}
}

if ($this->tokens[$i]['code'] === T_NULLABLE) {
$nullableReturnType = true;
}
Expand Down
12 changes: 12 additions & 0 deletions tests/Core/File/GetMethodPropertiesTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,18 @@ $value = $obj->fn(true);
/* testFunctionDeclarationNestedInTernaryPHPCS2975 */
return (!$a ? [ new class { public function b(): c {} } ] : []);

/* testClosureWithUseNoReturnType */
$closure = function () use($a) /*comment*/ {};

/* testClosureWithUseNoReturnTypeIllegalUseProp */
$closure = function () use ($this->prop){};

/* testClosureWithUseWithReturnType */
$closure = function () use /*comment*/ ($a): Type {};

/* testClosureWithUseMultiParamWithReturnType */
$closure = function () use ($a, &$b, $c, $d, $e, $f, $g): ?array {};

/* testArrowFunctionLiveCoding */
// Intentional parse error. This has to be the last test in the file.
$fn = fn
105 changes: 105 additions & 0 deletions tests/Core/File/GetMethodPropertiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1297,6 +1297,111 @@ public function testFunctionDeclarationNestedInTernaryPHPCS2975()
}//end testFunctionDeclarationNestedInTernaryPHPCS2975()


/**
* Test handling of closure declarations with a use variable import without a return type declaration.
*
* @return void
*/
public function testClosureWithUseNoReturnType()
{
// Offsets are relative to the T_CLOSURE token.
$expected = [
'scope' => 'public',
'scope_specified' => false,
'return_type' => '',
'return_type_token' => false,
'return_type_end_token' => false,
'nullable_return_type' => false,
'is_abstract' => false,
'is_final' => false,
'is_static' => false,
'has_body' => true,
];

$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);

}//end testClosureWithUseNoReturnType()


/**
* Test handling of closure declarations with an illegal use variable for a property import (not allowed in PHP)
* without a return type declaration.
*
* @return void
*/
public function testClosureWithUseNoReturnTypeIllegalUseProp()
{
// Offsets are relative to the T_CLOSURE token.
$expected = [
'scope' => 'public',
'scope_specified' => false,
'return_type' => '',
'return_type_token' => false,
'return_type_end_token' => false,
'nullable_return_type' => false,
'is_abstract' => false,
'is_final' => false,
'is_static' => false,
'has_body' => true,
];

$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);

}//end testClosureWithUseNoReturnTypeIllegalUseProp()


/**
* Test handling of closure declarations with a use variable import with a return type declaration.
*
* @return void
*/
public function testClosureWithUseWithReturnType()
{
// Offsets are relative to the T_CLOSURE token.
$expected = [
'scope' => 'public',
'scope_specified' => false,
'return_type' => 'Type',
'return_type_token' => 14,
'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 testClosureWithUseWithReturnType()


/**
* Test handling of closure declarations with a use variable import with a return type declaration.
*
* @return void
*/
public function testClosureWithUseMultiParamWithReturnType()
{
// Offsets are relative to the T_CLOSURE token.
$expected = [
'scope' => 'public',
'scope_specified' => false,
'return_type' => '?array',
'return_type_token' => 32,
'return_type_end_token' => 32,
'nullable_return_type' => true,
'is_abstract' => false,
'is_final' => false,
'is_static' => false,
'has_body' => true,
];

$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);

}//end testClosureWithUseMultiParamWithReturnType()


/**
* Test helper.
*
Expand Down

0 comments on commit 82ad715

Please sign in to comment.