Skip to content

Commit

Permalink
The PHP 7.4 T_FN token has been made available for older versions (ref
Browse files Browse the repository at this point in the history
  • Loading branch information
gsherwood committed Nov 4, 2019
1 parent 6a4abf4 commit 8fedf8c
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 1 deletion.
9 changes: 9 additions & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ http://pear.php.net/dtd/package-2.0.xsd">
</stability>
<license uri="https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt">BSD 3-Clause License</license>
<notes>
- The PHP 7.4 T_FN token has been made available for older versions
-- T_FN represents the fn string used for arrow functions
-- The token is associated with the opening and closing parenthesis of the statement
- Generic.CodeAnalysis.EmptyPhpStatement now reports unnecessary semicolons after control structure closing braces
-- Thanks to Vincent Langlet for the patch
- Fixed bug #2638 : Squiz.CSS.DuplicateClassDefinitionSniff sees comments as part of the class name
Expand Down Expand Up @@ -89,6 +92,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<dir name="Tokenizer">
<file baseinstalldir="" name="AnonClassParenthesisOwnerTest.inc" role="test" />
<file baseinstalldir="" name="AnonClassParenthesisOwnerTest.php" role="test" />
<file baseinstalldir="" name="BackfillFnTokenTest.inc" role="test" />
<file baseinstalldir="" name="BackfillFnTokenTest.php" role="test" />
</dir>
<file baseinstalldir="" name="AbstractMethodUnitTest.php" role="test" />
<file baseinstalldir="" name="AllTests.php" role="test" />
Expand Down Expand Up @@ -1917,6 +1922,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<install as="CodeSniffer/Core/Filters/Filter/AcceptTest.xml" name="tests/Core/Filters/Filter/AcceptTest.xml" />
<install as="CodeSniffer/Core/Tokenizer/AnonClassParenthesisOwnerTest.php" name="tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.php" />
<install as="CodeSniffer/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc" name="tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc" />
<install as="CodeSniffer/Core/Tokenizer/BackfillFnTokenTest.php" name="tests/Core/Tokenizer/BackfillFnTokenTest.php" />
<install as="CodeSniffer/Core/Tokenizer/BackfillFnTokenTest.inc" name="tests/Core/Tokenizer/BackfillFnTokenTest.inc" />
<install as="CodeSniffer/Standards/AllSniffs.php" name="tests/Standards/AllSniffs.php" />
<install as="CodeSniffer/Standards/AbstractSniffUnitTest.php" name="tests/Standards/AbstractSniffUnitTest.php" />
</filelist>
Expand Down Expand Up @@ -1956,6 +1963,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<install as="CodeSniffer/Core/Filters/Filter/AcceptTest.xml" name="tests/Core/Filters/Filter/AcceptTest.xml" />
<install as="CodeSniffer/Core/Tokenizer/AnonClassParenthesisOwnerTest.php" name="tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.php" />
<install as="CodeSniffer/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc" name="tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc" />
<install as="CodeSniffer/Core/Tokenizer/BackfillFnTokenTest.php" name="tests/Core/Tokenizer/BackfillFnTokenTest.php" />
<install as="CodeSniffer/Core/Tokenizer/BackfillFnTokenTest.inc" name="tests/Core/Tokenizer/BackfillFnTokenTest.inc" />
<install as="CodeSniffer/Standards/AllSniffs.php" name="tests/Standards/AllSniffs.php" />
<install as="CodeSniffer/Standards/AbstractSniffUnitTest.php" name="tests/Standards/AbstractSniffUnitTest.php" />
<ignore name="bin/phpcs.bat" />
Expand Down
30 changes: 29 additions & 1 deletion src/Tokenizers/PHP.php
Original file line number Diff line number Diff line change
Expand Up @@ -1045,7 +1045,7 @@ protected function tokenize($string)
}//end if

/*
Tokens after a double colon may be look like scope openers,
Tokens after a double colon may look like scope openers,
such as when writing code like Foo::NAMESPACE, but they are
only ever variables or strings.
*/
Expand Down Expand Up @@ -1606,6 +1606,34 @@ protected function processAdditional()
}//end if

continue;
} else if ($this->tokens[$i]['code'] === T_STRING
&& strtolower($this->tokens[$i]['content']) === 'fn'
) {
// Possible arrow function.
for ($x = ($i + 1); $i < $numTokens; $x++) {
if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) {
// Non-whitespace content.
break;
}
}

if ($this->tokens[$x]['code'] === T_OPEN_PARENTHESIS) {
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$line = $this->tokens[$i]['line'];
echo "\t* token $i on line $line changed from T_STRING to T_FN".PHP_EOL;
}

$this->tokens[$i]['code'] = T_FN;
$this->tokens[$i]['type'] = 'T_FN';
$this->tokens[$i]['parenthesis_owner'] = $i;
$this->tokens[$i]['parenthesis_opener'] = $x;
$this->tokens[$i]['parenthesis_closer'] = $this->tokens[$x]['parenthesis_closer'];

$opener = $this->tokens[$i]['parenthesis_opener'];
$closer = $this->tokens[$i]['parenthesis_closer'];
$this->tokens[$opener]['parenthesis_owner'] = $i;
$this->tokens[$closer]['parenthesis_owner'] = $i;
}
} else if ($this->tokens[$i]['code'] === T_OPEN_SQUARE_BRACKET) {
if (isset($this->tokens[$i]['bracket_closer']) === false) {
continue;
Expand Down
4 changes: 4 additions & 0 deletions src/Util/Tokens.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@
define('T_BAD_CHARACTER', 'PHPCS_T_BAD_CHARACTER');
}

if (defined('T_FN') === false) {
define('T_FN', 'PHPCS_T_FN');
}

// Tokens used for parsing doc blocks.
define('T_DOC_COMMENT_STAR', 'PHPCS_T_DOC_COMMENT_STAR');
define('T_DOC_COMMENT_WHITESPACE', 'PHPCS_T_DOC_COMMENT_WHITESPACE');
Expand Down
16 changes: 16 additions & 0 deletions tests/Core/Tokenizer/BackfillFnTokenTest.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

/* testStandard */
$fn1 = fn($x) => $x + $y;

/* testMixedCase */
$fn1 = Fn($x) => $x + $y;

/* testWhitespace */
$fn1 = fn ($x) => $x + $y;

/* testComment */
$fn1 = fn /* comment here */ ($x) => $x + $y;

/* testFunctionName */
function fn() {}
69 changes: 69 additions & 0 deletions tests/Core/Tokenizer/BackfillFnTokenTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
/**
* Tests the backfilling of the T_FN token to PHP < 7.4.
*
* @author Greg Sherwood <gsherwood@squiz.net>
* @copyright 2019 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 BackfillFnTokenTest extends AbstractMethodUnitTest
{


/**
* Data provider.
*
* @see testBackill()
*
* @return array
*/
public function dataBackfill()
{
return [
['/* testStandard */'],
['/* testMixedCase */'],
['/* testWhitespace */'],
['/* testComment */'],
['/* testFunctionName */'],
];

}//end dataAnonClassNoParentheses()


/**
* Test that anonymous class tokens without parenthesis do not get assigned a parenthesis owner.
*
* @param string $testMarker The comment which prefaces the target token in the test file.
*
* @dataProvider dataBackfill
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
*
* @return void
*/
public function testBackfill($testMarker)
{
$tokens = self::$phpcsFile->getTokens();

$token = $this->getTargetToken($testMarker, T_FN);
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$token]), 'Parenthesis owner is not set');
$this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$token]), 'Parenthesis opener is not set');
$this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$token]), 'Parenthesis closer is not set');
$this->assertSame($tokens[$token]['parenthesis_owner'], $token, 'Parenthesis owner is not the T_FN token');

$opener = $tokens[$token]['parenthesis_opener'];
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener]), 'Opening parenthesis owner is not set');
$this->assertSame($tokens[$opener]['parenthesis_owner'], $token, 'Opening parenthesis owner is not the T_FN token');

$closer = $tokens[$token]['parenthesis_closer'];
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer]), 'Closing parenthesis owner is not set');
$this->assertSame($tokens[$closer]['parenthesis_owner'], $token, 'Closing parenthesis owner is not the T_FN token');

}//end testAnonClassNoParentheses()


}//end class

0 comments on commit 8fedf8c

Please sign in to comment.