Skip to content

Commit

Permalink
Tokenizer/PHP: stabilize T_FINALLY backfill
Browse files Browse the repository at this point in the history
Make the backfill for T_FINALLY a little more stable by preventing re-tokenizing non-keyword `finally` strings to `T_FINALLY`.

Includes unit tests.
  • Loading branch information
jrfnl committed May 11, 2021
1 parent fde816c commit 118891d
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 0 deletions.
6 changes: 6 additions & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file baseinstalldir="" name="DefaultKeywordTest.php" role="test" />
<file baseinstalldir="" name="DoubleArrowTest.inc" role="test" />
<file baseinstalldir="" name="DoubleArrowTest.php" role="test" />
<file baseinstalldir="" name="FinallyTest.inc" role="test" />
<file baseinstalldir="" name="FinallyTest.php" role="test" />
<file baseinstalldir="" name="GotoLabelTest.inc" role="test" />
<file baseinstalldir="" name="GotoLabelTest.php" role="test" />
<file baseinstalldir="" name="NamedFunctionCallArgumentsTest.inc" role="test" />
Expand Down Expand Up @@ -2054,6 +2056,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<install as="CodeSniffer/Core/Tokenizer/DefaultKeywordTest.inc" name="tests/Core/Tokenizer/DefaultKeywordTest.inc" />
<install as="CodeSniffer/Core/Tokenizer/DoubleArrowTest.php" name="tests/Core/Tokenizer/DoubleArrowTest.php" />
<install as="CodeSniffer/Core/Tokenizer/DoubleArrowTest.inc" name="tests/Core/Tokenizer/DoubleArrowTest.inc" />
<install as="CodeSniffer/Core/Tokenizer/FinallyTest.php" name="tests/Core/Tokenizer/FinallyTest.php" />
<install as="CodeSniffer/Core/Tokenizer/FinallyTest.inc" name="tests/Core/Tokenizer/FinallyTest.inc" />
<install as="CodeSniffer/Core/Tokenizer/GotoLabelTest.php" name="tests/Core/Tokenizer/GotoLabelTest.php" />
<install as="CodeSniffer/Core/Tokenizer/GotoLabelTest.inc" name="tests/Core/Tokenizer/GotoLabelTest.inc" />
<install as="CodeSniffer/Core/Tokenizer/NamedFunctionCallArgumentsTest.php" name="tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php" />
Expand Down Expand Up @@ -2140,6 +2144,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<install as="CodeSniffer/Core/Tokenizer/DefaultKeywordTest.inc" name="tests/Core/Tokenizer/DefaultKeywordTest.inc" />
<install as="CodeSniffer/Core/Tokenizer/DoubleArrowTest.php" name="tests/Core/Tokenizer/DoubleArrowTest.php" />
<install as="CodeSniffer/Core/Tokenizer/DoubleArrowTest.inc" name="tests/Core/Tokenizer/DoubleArrowTest.inc" />
<install as="CodeSniffer/Core/Tokenizer/FinallyTest.php" name="tests/Core/Tokenizer/FinallyTest.php" />
<install as="CodeSniffer/Core/Tokenizer/FinallyTest.inc" name="tests/Core/Tokenizer/FinallyTest.inc" />
<install as="CodeSniffer/Core/Tokenizer/GotoLabelTest.php" name="tests/Core/Tokenizer/GotoLabelTest.php" />
<install as="CodeSniffer/Core/Tokenizer/GotoLabelTest.inc" name="tests/Core/Tokenizer/GotoLabelTest.inc" />
<install as="CodeSniffer/Core/Tokenizer/NamedFunctionCallArgumentsTest.php" name="tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php" />
Expand Down
1 change: 1 addition & 0 deletions src/Tokenizers/PHP.php
Original file line number Diff line number Diff line change
Expand Up @@ -2084,6 +2084,7 @@ function return types. We want to keep the parenthesis map clean,
// where "finally" should be T_FINALLY instead of T_STRING.
if ($newToken['code'] === T_STRING
&& strtolower($newToken['content']) === 'finally'
&& $finalTokens[$lastNotEmptyToken]['code'] === T_CLOSE_CURLY_BRACKET
) {
$newToken['code'] = T_FINALLY;
$newToken['type'] = 'T_FINALLY';
Expand Down
40 changes: 40 additions & 0 deletions tests/Core/Tokenizer/FinallyTest.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

try {
// Do something.
} catch(Exception $e) {
// Do something.
}
/* testTryCatchFinally */
finally {
// Do something.
}

/* testTryFinallyCatch */
try {
// Do something.
} finally {
// Do something.
} catch(Exception $e) {
// Do something.
}

/* testTryFinally */
try {
// Do something.
} FINALLY {
// Do something.
}

class FinallyAsMethod {
/* testFinallyUsedAsClassConstantName */
const FINALLY = 'foo';

/* testFinallyUsedAsMethodName */
public function finally() {
// Do something.

/* testFinallyUsedAsPropertyName */
$this->finally = 'foo';
}
}
96 changes: 96 additions & 0 deletions tests/Core/Tokenizer/FinallyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php
/**
* Tests the tokenization of the finally keyword.
*
* @author Juliette Reinders Folmer <[email protected]>
* @copyright 2021 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 FinallyTest extends AbstractMethodUnitTest
{


/**
* Test that the finally keyword is tokenized as such.
*
* @param string $testMarker The comment which prefaces the target token in the test file.
*
* @dataProvider dataFinallyKeyword
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
*
* @return void
*/
public function testFinallyKeyword($testMarker)
{
$tokens = self::$phpcsFile->getTokens();

$target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]);
$this->assertSame(T_FINALLY, $tokens[$target]['code']);
$this->assertSame('T_FINALLY', $tokens[$target]['type']);

}//end testFinallyKeyword()


/**
* Data provider.
*
* @see testFinallyKeyword()
*
* @return array
*/
public function dataFinallyKeyword()
{
return [
['/* testTryCatchFinally */'],
['/* testTryFinallyCatch */'],
['/* testTryFinally */'],
];

}//end dataFinallyKeyword()


/**
* Test that 'finally' when not used as the reserved keyword is tokenized as `T_STRING`.
*
* @param string $testMarker The comment which prefaces the target token in the test file.
*
* @dataProvider dataFinallyNonKeyword
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
*
* @return void
*/
public function testFinallyNonKeyword($testMarker)
{
$tokens = self::$phpcsFile->getTokens();

$target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]);
$this->assertSame(T_STRING, $tokens[$target]['code']);
$this->assertSame('T_STRING', $tokens[$target]['type']);

}//end testFinallyNonKeyword()


/**
* Data provider.
*
* @see testFinallyNonKeyword()
*
* @return array
*/
public function dataFinallyNonKeyword()
{
return [
['/* testFinallyUsedAsClassConstantName */'],
['/* testFinallyUsedAsMethodName */'],
['/* testFinallyUsedAsPropertyName */'],
];

}//end dataFinallyNonKeyword()


}//end class

0 comments on commit 118891d

Please sign in to comment.