From 73e80893e783be9d88e274a1926b182f017e37a4 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 10 Jan 2025 09:33:05 +0100 Subject: [PATCH] Tokenizer/PHP: prevent an "Undefined array key" notice during live coding During live coding or for code containing a parse error, it was possible for the tokenizer to run into an `Undefined array key "parenthesis_closer"` error when trying to verify arrow functions. As this error happens during the tokenization, this resulted in PHPCS silently not scanning the file - without even showing the error notice. Fixed now. Includes tests. --- src/Tokenizers/PHP.php | 7 ++- .../PHP/BackfillFnTokenParseErrorTest.inc | 5 +++ .../PHP/BackfillFnTokenParseErrorTest.php | 44 +++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc create mode 100644 tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.php diff --git a/src/Tokenizers/PHP.php b/src/Tokenizers/PHP.php index 9c6c11e4c3..c6b8e29065 100644 --- a/src/Tokenizers/PHP.php +++ b/src/Tokenizers/PHP.php @@ -2817,7 +2817,10 @@ protected function processAdditional() } } - if (isset($this->tokens[$x]) === true && $this->tokens[$x]['code'] === T_OPEN_PARENTHESIS) { + if (isset($this->tokens[$x]) === true + && $this->tokens[$x]['code'] === T_OPEN_PARENTHESIS + && isset($this->tokens[$x]['parenthesis_closer']) === true + ) { $ignore = Tokens::$emptyTokens; $ignore += [ T_ARRAY => T_ARRAY, @@ -2995,7 +2998,7 @@ protected function processAdditional() }//end if }//end if - // If after all that, the extra tokens are not set, this is not an arrow function. + // If after all that, the extra tokens are not set, this is not a (valid) arrow function. if (isset($this->tokens[$i]['scope_closer']) === false) { if (PHP_CODESNIFFER_VERBOSITY > 1) { $line = $this->tokens[$i]['line']; diff --git a/tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc b/tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc new file mode 100644 index 0000000000..ce247e991b --- /dev/null +++ b/tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc @@ -0,0 +1,5 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BackfillFnTokenParseErrorTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that un unfinished arrow function during live coding doesn't cause a "Undefined array key "parenthesis_closer"" error. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnfinishedArrowFunction() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testLiveCoding */', [T_STRING, T_FN], 'fn'); + $tokenArray = $tokens[$token]; + + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + }//end testUnfinishedArrowFunction() + + +}//end class