From 2351cc90e43531ead6f40fcabdc51c435401d2f5 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 28 Nov 2020 00:39:46 +0100 Subject: [PATCH] Tokenizer/PHP: bugfix goto tokenization logic The logic could get confused when `goto` would be used in a mixed PHP/HTML file. Includes adding a limited set of unit tests for the `T_GOTO_LABEL` tokenization. --- package.xml | 6 + src/Tokenizers/PHP.php | 1 + tests/Core/Tokenizer/GotoLabelTest.inc | 53 ++++++++ tests/Core/Tokenizer/GotoLabelTest.php | 171 +++++++++++++++++++++++++ 4 files changed, 231 insertions(+) create mode 100644 tests/Core/Tokenizer/GotoLabelTest.inc create mode 100644 tests/Core/Tokenizer/GotoLabelTest.php diff --git a/package.xml b/package.xml index ec5302a08a..71115c0306 100644 --- a/package.xml +++ b/package.xml @@ -157,6 +157,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + @@ -2045,6 +2047,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + @@ -2117,6 +2121,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + diff --git a/src/Tokenizers/PHP.php b/src/Tokenizers/PHP.php index 8459289bae..81db29a59e 100644 --- a/src/Tokenizers/PHP.php +++ b/src/Tokenizers/PHP.php @@ -1572,6 +1572,7 @@ function return types. We want to keep the parenthesis map clean, $stopTokens = [ T_CASE => true, T_SEMICOLON => true, + T_OPEN_TAG => true, T_OPEN_CURLY_BRACKET => true, T_INLINE_THEN => true, ]; diff --git a/tests/Core/Tokenizer/GotoLabelTest.inc b/tests/Core/Tokenizer/GotoLabelTest.inc new file mode 100644 index 0000000000..f6920f54fa --- /dev/null +++ b/tests/Core/Tokenizer/GotoLabelTest.inc @@ -0,0 +1,53 @@ + +
+ +property: + // Do something. + break; +} + +switch (true) { + /* testNotGotoDeclarationGlobalConstantInTernary */ + case $x === ($cond) ? CONST_A : CONST_B: + // Do something. + break; +} diff --git a/tests/Core/Tokenizer/GotoLabelTest.php b/tests/Core/Tokenizer/GotoLabelTest.php new file mode 100644 index 0000000000..fa6f8cfb47 --- /dev/null +++ b/tests/Core/Tokenizer/GotoLabelTest.php @@ -0,0 +1,171 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +class GotoLabelTest extends AbstractMethodUnitTest +{ + + + /** + * Verify that the label in a goto statement is tokenized as T_STRING. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to expect. + * + * @dataProvider dataGotoStatement + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testGotoStatement($testMarker, $testContent) + { + $tokens = self::$phpcsFile->getTokens(); + + $label = $this->getTargetToken($testMarker, T_STRING); + + $this->assertInternalType('int', $label); + $this->assertSame($testContent, $tokens[$label]['content']); + + }//end testGotoStatement() + + + /** + * Data provider. + * + * @see testGotoStatement() + * + * @return array + */ + public function dataGotoStatement() + { + return [ + [ + '/* testGotoStatement */', + 'marker', + ], + [ + '/* testGotoStatementInLoop */', + 'end', + ], + ]; + + }//end dataGotoStatement() + + + /** + * Verify that the label in a goto declaration is tokenized as T_GOTO_LABEL. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to expect. + * + * @dataProvider dataGotoDeclaration + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testGotoDeclaration($testMarker, $testContent) + { + $tokens = self::$phpcsFile->getTokens(); + + $label = $this->getTargetToken($testMarker, T_GOTO_LABEL); + + $this->assertInternalType('int', $label); + $this->assertSame($testContent, $tokens[$label]['content']); + + }//end testGotoDeclaration() + + + /** + * Data provider. + * + * @see testGotoDeclaration() + * + * @return array + */ + public function dataGotoDeclaration() + { + return [ + [ + '/* testGotoDeclaration */', + 'marker:', + ], + [ + '/* testGotoDeclarationOutsideLoop */', + 'end:', + ], + ]; + + }//end dataGotoDeclaration() + + + /** + * Verify that the constant used in a switch - case statement is not confused with a goto label. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to expect. + * + * @dataProvider dataNotAGotoDeclaration + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNotAGotoDeclaration($testMarker, $testContent) + { + $tokens = self::$phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_GOTO_LABEL, T_STRING], $testContent); + + $this->assertSame(T_STRING, $tokens[$target]['code']); + $this->assertSame('T_STRING', $tokens[$target]['type']); + + }//end testNotAGotoDeclaration() + + + /** + * Data provider. + * + * @see testNotAGotoDeclaration() + * + * @return array + */ + public function dataNotAGotoDeclaration() + { + return [ + [ + '/* testNotGotoDeclarationGlobalConstant */', + 'CONSTANT', + ], + [ + '/* testNotGotoDeclarationNamespacedConstant */', + 'CONSTANT', + ], + [ + '/* testNotGotoDeclarationClassConstant */', + 'CONSTANT', + ], + [ + '/* testNotGotoDeclarationClassProperty */', + 'property', + ], + [ + '/* testNotGotoDeclarationGlobalConstantInTernary */', + 'CONST_A', + ], + [ + '/* testNotGotoDeclarationGlobalConstantInTernary */', + 'CONST_B', + ], + ]; + + }//end dataNotAGotoDeclaration() + + +}//end class