Skip to content

Commit

Permalink
Fixed detection of scope closers when arrow functions used in ternary…
Browse files Browse the repository at this point in the history
… (ref #2715)
  • Loading branch information
gsherwood committed Nov 20, 2019
1 parent 7ee537f commit 04ab5a0
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 1 deletion.
20 changes: 19 additions & 1 deletion src/Tokenizers/PHP.php
Original file line number Diff line number Diff line change
Expand Up @@ -1737,12 +1737,16 @@ protected function processAdditional()
T_CLOSE_TAG => true,
];

$inTernary = false;

for ($scopeCloser = ($arrow + 1); $scopeCloser < $numTokens; $scopeCloser++) {
if (isset($endTokens[$this->tokens[$scopeCloser]['code']]) === true) {
break;
}

if (isset($this->tokens[$scopeCloser]['scope_closer']) === true) {
if (isset($this->tokens[$scopeCloser]['scope_closer']) === true
&& $this->tokens[$scopeCloser]['code'] !== T_INLINE_ELSE
) {
// We minus 1 here in case the closer can be shared with us.
$scopeCloser = ($this->tokens[$scopeCloser]['scope_closer'] - 1);
continue;
Expand All @@ -1757,6 +1761,20 @@ protected function processAdditional()
$scopeCloser = $this->tokens[$scopeCloser]['bracket_closer'];
continue;
}

if ($this->tokens[$scopeCloser]['code'] === T_INLINE_THEN) {
$inTernary = true;
continue;
}

if ($this->tokens[$scopeCloser]['code'] === T_INLINE_ELSE) {
if ($inTernary === false) {
break;
}

$inTernary = false;
continue;
}
}//end for

if ($scopeCloser !== $numTokens) {
Expand Down
3 changes: 3 additions & 0 deletions tests/Core/Tokenizer/BackfillFnTokenTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,6 @@ fn(parent $a) : parent => $a;

/* testCallableReturnType */
fn(callable $a) : callable => $a;

/* testTernary */
$fn = fn($a) => $a ? /* testTernaryThen */ fn() : string => 'a' : /* testTernaryElse */ fn() : string => 'b';
56 changes: 56 additions & 0 deletions tests/Core/Tokenizer/BackfillFnTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,62 @@ public function testKeywordReturnTypes()
}//end testKeywordReturnTypes()


/**
* Test arrow functions used in ternary operators.
*
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
*
* @return void
*/
public function testTernary()
{
$tokens = self::$phpcsFile->getTokens();

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

$this->assertSame($tokens[$token]['scope_opener'], ($token + 5), 'Scope opener is not the arrow token');
$this->assertSame($tokens[$token]['scope_closer'], ($token + 40), 'Scope closer is not the semicolon token');

$opener = $tokens[$token]['scope_opener'];
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 5), 'Opener scope opener is not the arrow token');
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 40), 'Opener scope closer is not the semicolon token');

$closer = $tokens[$token]['scope_opener'];
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 5), 'Closer scope opener is not the arrow token');
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 40), 'Closer scope closer is not the semicolon token');

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

$this->assertSame($tokens[$token]['scope_opener'], ($token + 8), 'Scope opener for THEN is not the arrow token');
$this->assertSame($tokens[$token]['scope_closer'], ($token + 12), 'Scope closer for THEN is not the semicolon token');

$opener = $tokens[$token]['scope_opener'];
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 8), 'Opener scope opener for THEN is not the arrow token');
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 12), 'Opener scope closer for THEN is not the semicolon token');

$closer = $tokens[$token]['scope_opener'];
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 8), 'Closer scope opener for THEN is not the arrow token');
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 12), 'Closer scope closer for THEN is not the semicolon token');

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

$this->assertSame($tokens[$token]['scope_opener'], ($token + 8), 'Scope opener for ELSE is not the arrow token');
$this->assertSame($tokens[$token]['scope_closer'], ($token + 11), 'Scope closer for ELSE is not the semicolon token');

$opener = $tokens[$token]['scope_opener'];
$this->assertSame($tokens[$opener]['scope_opener'], ($token + 8), 'Opener scope opener for ELSE is not the arrow token');
$this->assertSame($tokens[$opener]['scope_closer'], ($token + 11), 'Opener scope closer for ELSE is not the semicolon token');

$closer = $tokens[$token]['scope_opener'];
$this->assertSame($tokens[$closer]['scope_opener'], ($token + 8), 'Closer scope opener for ELSE is not the arrow token');
$this->assertSame($tokens[$closer]['scope_closer'], ($token + 11), 'Closer scope closer for ELSE is not the semicolon token');

}//end testTernary()


/**
* Test that anonymous class tokens without parenthesis do not get assigned a parenthesis owner.
*
Expand Down

0 comments on commit 04ab5a0

Please sign in to comment.