Skip to content

Commit

Permalink
Fixed bug #3324 : PHPCS hangs processing some nested arrow functions …
Browse files Browse the repository at this point in the history
…inside a function call
  • Loading branch information
gsherwood committed Apr 26, 2021
1 parent 62e6e06 commit b84c541
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.xml
Expand Up @@ -36,6 +36,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
- Fixed bug #3316 : Arrow function not tokenized correctly when using null in union type
- Fixed bug #3317 : Problem with how phpcs handles ignored files when running in parallel
-- Thanks to Emil Andersson for the patch
- Fixed bug #3324 : PHPCS hangs processing some nested arrow functions inside a function call
</notes>
<contents>
<dir name="/">
Expand Down
10 changes: 10 additions & 0 deletions src/Tokenizers/PHP.php
Expand Up @@ -2355,6 +2355,16 @@ protected function processAdditional()
break;
}

if ($inTernary === false
&& isset($this->tokens[$scopeCloser]['scope_closer'], $this->tokens[$scopeCloser]['scope_condition']) === true
&& $scopeCloser === $this->tokens[$scopeCloser]['scope_closer']
&& $this->tokens[$this->tokens[$scopeCloser]['scope_condition']]['code'] === T_FN
) {
// Found a nested arrow function that already has the closer set and is in
// the same scope as us, so we can use its closer.
break;
}

if (isset($this->tokens[$scopeCloser]['scope_closer']) === true
&& $this->tokens[$scopeCloser]['code'] !== T_INLINE_ELSE
&& $this->tokens[$scopeCloser]['code'] !== T_END_HEREDOC
Expand Down
3 changes: 3 additions & 0 deletions tests/Core/Tokenizer/BackfillFnTokenTest.inc
Expand Up @@ -23,6 +23,9 @@ function fn() {}
/* testNestedOuter */
$fn = fn($x) => /* testNestedInner */ fn($y) => $x * $y + $z;

/* testNestedSharedCloserOuter */
$foo = foo(fn() => /* testNestedSharedCloserInner */ fn() => bar() === true);

/* testFunctionCall */
$extended = fn($c) => $callable($factory($c), $c);

Expand Down
35 changes: 35 additions & 0 deletions tests/Core/Tokenizer/BackfillFnTokenTest.php
Expand Up @@ -128,6 +128,41 @@ public function testNestedInner()
}//end testNestedInner()


/**
* Test nested arrow functions with a shared closer.
*
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
*
* @return void
*/
public function testNestedSharedCloser()
{
$tokens = self::$phpcsFile->getTokens();

$token = $this->getTargetToken('/* testNestedSharedCloserOuter */', T_FN);
$this->backfillHelper($token);
$this->scopePositionTestHelper($token, 4, 20);

$token = $this->getTargetToken('/* testNestedSharedCloserInner */', T_FN);
$this->backfillHelper($token, true);

$expectedScopeOpener = ($token + 4);
$expectedScopeCloser = ($token + 12);

$this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for "inner" arrow function is not the arrow token');
$this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for "inner" arrow function is not the TRUE token');

$opener = $tokens[$token]['scope_opener'];
$this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for "inner" arrow function is not the arrow token');
$this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for "inner" arrow function is not the semicolon token');

$closer = $tokens[$token]['scope_closer'];
$this->assertSame(($token - 4), $tokens[$closer]['scope_opener'], 'Closer scope opener for "inner" arrow function is not the arrow token of the "outer" arrow function (shared scope closer)');
$this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for "inner" arrow function is not the TRUE token');

}//end testNestedSharedCloser()


/**
* Test arrow functions that call functions.
*
Expand Down

0 comments on commit b84c541

Please sign in to comment.