Skip to content

Commit

Permalink
Merge pull request #79 from PHPCSStandards/functiondeclarations/sync-…
Browse files Browse the repository at this point in the history
…arrow-functions-with-phpcs-3.5.5

Improve support for arrow functions / sync with phpcs 3.5.5
  • Loading branch information
jrfnl authored Feb 11, 2020
2 parents 2ad3390 + 37440af commit 00b8ca9
Show file tree
Hide file tree
Showing 21 changed files with 630 additions and 412 deletions.
37 changes: 17 additions & 20 deletions PHPCSUtils/BackCompat/BCFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
* array return type declarations.
* - Typed properties were not recognized prior to PHPCS 3.5.0, including the
* `?` nullability token not being converted to `T_NULLABLE`.
* - Arrow functions were not recognized properly until PHPCS 3.5.3.
* - General PHP cross-version incompatibilities.
*
* Most functions in this class will have a related twin-function in the relevant
Expand Down Expand Up @@ -98,6 +99,8 @@ class BCFile
* `\PHP_CodeSniffer\Exceptions\RuntimeException`.
* - PHPCS 3.5.3: Allow for functions to be called `fn` for backwards compatibility.
* Related to PHP 7.4 T_FN arrow functions.
* - PHPCS 3.5.5: Remove arrow function work-around which is no longer needed due to
* a change in the tokenization of arrow functions.
*
* Note: For ES6 classes in combination with PHPCS 2.x, passing a `T_STRING` token to
* this method will be accepted for JS files.
Expand Down Expand Up @@ -159,6 +162,7 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr)
$content = null;
for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) {
if ($tokens[$i]['code'] === T_STRING
// BC: PHPCS 3.5.3/3.5.4.
|| $tokens[$i]['type'] === 'T_FN'
) {
/*
Expand Down Expand Up @@ -265,12 +269,13 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr)
*/
public static function getMethodParameters(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$tokens = $phpcsFile->getTokens();
$arrowOpenClose = FunctionDeclarations::getArrowFunctionOpenClose($phpcsFile, $stackPtr);

if ($tokens[$stackPtr]['code'] !== T_FUNCTION
&& $tokens[$stackPtr]['code'] !== T_CLOSURE
&& $tokens[$stackPtr]['code'] !== T_USE
&& FunctionDeclarations::isArrowFunction($phpcsFile, $stackPtr) === false
&& $arrowOpenClose === false
) {
throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN');
}
Expand All @@ -280,15 +285,9 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
if ($opener === false || isset($tokens[$opener]['parenthesis_owner']) === true) {
throw new RuntimeException('$stackPtr was not a valid T_USE');
}
} elseif ($tokens[$stackPtr]['code'] === \T_STRING || $tokens[$stackPtr]['type'] === 'T_FN') {
/*
* Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3.
*/
$opener = $phpcsFile->findNext((Tokens::$emptyTokens + [\T_BITWISE_AND]), ($stackPtr + 1), null, true);
if ($opener === false || $tokens[$opener]['code'] !== T_OPEN_PARENTHESIS) {
// Live coding or syntax error, so no params to find.
return [];
}
} elseif ($arrowOpenClose !== false) {
// Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3/4/5.
$opener = $arrowOpenClose['parenthesis_opener'];
} else {
if (isset($tokens[$stackPtr]['parenthesis_opener']) === false) {
// Live coding or syntax error, so no params to find.
Expand Down Expand Up @@ -552,7 +551,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr)

if ($tokens[$stackPtr]['code'] !== T_FUNCTION
&& $tokens[$stackPtr]['code'] !== T_CLOSURE
&& $arrowOpenClose === []
&& $arrowOpenClose === false
) {
throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN');
}
Expand Down Expand Up @@ -622,7 +621,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr)
$parenthesisCloser = null;
if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) {
$parenthesisCloser = $tokens[$stackPtr]['parenthesis_closer'];
} elseif ($arrowOpenClose !== [] && $arrowOpenClose['parenthesis_closer'] !== false) {
} elseif ($arrowOpenClose !== false) {
// Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3.
$parenthesisCloser = $arrowOpenClose['parenthesis_closer'];
}
Expand All @@ -631,7 +630,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr)
$scopeOpener = null;
if (isset($tokens[$stackPtr]['scope_opener']) === true) {
$scopeOpener = $tokens[$stackPtr]['scope_opener'];
} elseif ($arrowOpenClose !== [] && $arrowOpenClose['scope_opener'] !== false) {
} elseif ($arrowOpenClose !== false) {
// Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3.
$scopeOpener = $arrowOpenClose['scope_opener'];
}
Expand All @@ -648,7 +647,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr)
// Handle nullable tokens in PHPCS < 2.8.0.
|| (defined('T_NULLABLE') === false && $tokens[$i]['code'] === T_INLINE_THEN)
// Handle nullable tokens with arrow functions in PHPCS 2.8.0 - 2.9.0.
|| ($arrowOpenClose !== [] && $tokens[$i]['code'] === T_INLINE_THEN
|| ($arrowOpenClose !== false && $tokens[$i]['code'] === T_INLINE_THEN
&& version_compare(Helper::getVersion(), '2.9.1', '<') === true)
) {
$nullableReturnType = true;
Expand All @@ -664,7 +663,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr)
}

$bodyTokens = [T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET];
if ($arrowOpenClose !== []) {
if ($arrowOpenClose !== false) {
$bodyTokens = [T_DOUBLE_ARROW => T_DOUBLE_ARROW];
if (defined('T_FN_ARROW') === true) {
// PHPCS 3.5.3+.
Expand Down Expand Up @@ -1332,12 +1331,10 @@ public static function findEndOfStatement(File $phpcsFile, $start, $ignore = nul
if ($end !== false) {
$i = $end;
}
} elseif ($tokens[$i]['code'] === T_STRING || $tokens[$i]['type'] === 'T_FN') {
} elseif (isset(Collections::arrowFunctionTokensBC()[$tokens[$i]['code']]) === true) {
// Potentially a PHP 7.4 arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3/3.5.4.
$arrowFunctionOpenClose = FunctionDeclarations::getArrowFunctionOpenClose($phpcsFile, $i);
if ($arrowFunctionOpenClose !== []
&& $arrowFunctionOpenClose['scope_closer'] !== false
) {
if ($arrowFunctionOpenClose !== false) {
if ($i === $start) {
return $arrowFunctionOpenClose['scope_closer'];
}
Expand Down
23 changes: 23 additions & 0 deletions PHPCSUtils/Tokens/Collections.php
Original file line number Diff line number Diff line change
Expand Up @@ -393,4 +393,27 @@ class Collections
\T_CONSTANT_ENCAPSED_STRING => \T_CONSTANT_ENCAPSED_STRING,
\T_DOUBLE_QUOTED_STRING => \T_DOUBLE_QUOTED_STRING,
];

/**
* Tokens which can represent the arrow function keyword.
*
* Note: this is a method, not a property as the `T_FN` token may not exist.
*
* @since 1.0.0
*
* @return array <int|string> => <int|string>
*/
public static function arrowFunctionTokensBC()
{
$tokens = [
\T_STRING => \T_STRING,
];

if (\defined('T_FN') === true) {
// PHP 7.4 or PHPCS 3.5.3+.
$tokens[\T_FN] = \T_FN;
}

return $tokens;
}
}
8 changes: 3 additions & 5 deletions PHPCSUtils/Utils/Arrays.php
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,8 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end)
);
}

$targets = self::$doubleArrowTargets + Collections::$closedScopes;
if (\defined('T_FN') === true) {
$targets[\T_FN] = \T_FN;
}
$targets = self::$doubleArrowTargets + Collections::$closedScopes;
$targets += Collections::arrowFunctionTokensBC();

$doubleArrow = ($start - 1);
++$end;
Expand Down Expand Up @@ -294,7 +292,7 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end)
}

// BC for PHP 7.4 arrow functions with PHPCS < 3.5.3.
if ($tokens[$doubleArrow]['code'] === \T_STRING
if (isset(Collections::arrowFunctionTokensBC()[$tokens[$doubleArrow]['code']]) === true
&& FunctionDeclarations::isArrowFunction($phpcsFile, $doubleArrow) === false
) {
// Not an arrow function, continue looking.
Expand Down
Loading

0 comments on commit 00b8ca9

Please sign in to comment.