From cac90382a16016b546442e9bbcfedf91a3cc28a5 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 21 May 2024 15:58:39 +0200 Subject: [PATCH] Tokenizer/PHP: efficiency improvement for DNF type handling The PHP::processAdditional()` method walks _back_ from the end of the file to the beginning. With that in mind, and knowing that a type can never end on an open parenthesis, and an open parenthesis can never be seen in a type before the close parenthesis has been seen (at least for valid/non-parse error types), it makes no sense to trigger the type handling logic for open parentheses. This should make the tokenizer slightly more efficient as (open) parentheses are used a lot in code ;-) It also prevents the type handling layer from acting on these type of invalid/parse error types, while it previously would. Includes tests safeguarding the behaviour of the type handling layer for this type of invalid/parse error types. Of these tests, the type for the OO constant and for the property were previously not handled consistently/correctly. The parameter type + the return type were fine. --- src/Tokenizers/PHP.php | 1 - .../Tokenizer/PHP/DNFTypesParseError1Test.inc | 17 +++++ .../Tokenizer/PHP/DNFTypesParseError1Test.php | 69 +++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 tests/Core/Tokenizer/PHP/DNFTypesParseError1Test.inc create mode 100644 tests/Core/Tokenizer/PHP/DNFTypesParseError1Test.php diff --git a/src/Tokenizers/PHP.php b/src/Tokenizers/PHP.php index 23dab0a60e..3e7be371cf 100644 --- a/src/Tokenizers/PHP.php +++ b/src/Tokenizers/PHP.php @@ -3036,7 +3036,6 @@ protected function processAdditional() continue; } else if ($this->tokens[$i]['code'] === T_BITWISE_OR || $this->tokens[$i]['code'] === T_BITWISE_AND - || $this->tokens[$i]['code'] === T_OPEN_PARENTHESIS || $this->tokens[$i]['code'] === T_CLOSE_PARENTHESIS ) { /* diff --git a/tests/Core/Tokenizer/PHP/DNFTypesParseError1Test.inc b/tests/Core/Tokenizer/PHP/DNFTypesParseError1Test.inc new file mode 100644 index 0000000000..a6cf511c2e --- /dev/null +++ b/tests/Core/Tokenizer/PHP/DNFTypesParseError1Test.inc @@ -0,0 +1,17 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizer\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizer\AbstractTokenizerTestCase; + +final class DNFTypesParseError1Test extends AbstractTokenizerTestCase +{ + + + /** + * Document handling for a DNF type / parse error where the last significant type specific token is an open parenthesis. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeCantEndOnOpenParenthesis + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeCantEndOnOpenParenthesis($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS], '('); + $token = $tokens[$openPtr]; + + // Verify that the open parenthesis is tokenized as a normal parenthesis. + $this->assertSame(T_OPEN_PARENTHESIS, $token['code'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $token['type'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (type)'); + + // Verify that the type union is still tokenized as T_BITWISE_OR as the type declaration + // is not recognized as a valid type declaration. + $unionPtr = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION], '|'); + $token = $tokens[$unionPtr]; + + $this->assertSame(T_BITWISE_OR, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (type)'); + + }//end testBrokenDNFTypeCantEndOnOpenParenthesis() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeCantEndOnOpenParenthesis() + * + * @return array> + */ + public static function dataBrokenDNFTypeCantEndOnOpenParenthesis() + { + return [ + 'OO const type' => ['/* testBrokenConstDNFTypeEndOnOpenParenthesis */'], + 'OO property type' => ['/* testBrokenPropertyDNFTypeEndOnOpenParenthesis */'], + 'Parameter type' => ['/* testBrokenParamDNFTypeEndOnOpenParenthesis */'], + 'Return type' => ['/* testBrokenReturnDNFTypeEndOnOpenParenthesis */'], + ]; + + }//end dataBrokenDNFTypeCantEndOnOpenParenthesis() + + +}//end class