Skip to content

Commit

Permalink
Use the same technique for finding list assignments as phpcs might
Browse files Browse the repository at this point in the history
  • Loading branch information
sirbrillig committed Aug 12, 2022
1 parent 459c69b commit 96274aa
Showing 1 changed file with 68 additions and 17 deletions.
85 changes: 68 additions & 17 deletions VariableAnalysis/Lib/Helpers.php
Expand Up @@ -654,7 +654,70 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr)
}

/**
* Return a list of indices for variables assigned within a list assignment
* Determine if a token is a list opener for list assignment/destructuring.
*
* The index provided can be either the opening square brace of a short list
* assignment like the first character of `[$a] = $b;` or the `list` token of
* an expression like `list($a) = $b;` or the opening parenthesis of that
* expression.
*
* @param File $phpcsFile
* @param int $listOpenerIndex
*
* @return bool
*/
private static function isListAssignment(File $phpcsFile, $listOpenerIndex)
{
$tokens = $phpcsFile->getTokens();
// Match `[$a] = $b;` except for when the previous token is a parenthesis.
if ($tokens[$listOpenerIndex]['code'] === T_OPEN_SHORT_ARRAY) {
return true;
}
// Match `list($a) = $b;`
if ($tokens[$listOpenerIndex]['code'] === T_LIST) {
return true;
}

// If $listOpenerIndex is the open parenthesis of `list($a) = $b;`, then
// match that too.
if ($tokens[$listOpenerIndex]['code'] === T_OPEN_PARENTHESIS) {
$previousTokenPtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, $listOpenerIndex - 1, null, true);
if (
isset($tokens[$previousTokenPtr])
&& $tokens[$previousTokenPtr]['code'] === T_LIST
) {
return true;
}
return true;
}

// If the list opener token is a square bracket that is preceeded by a
// close parenthesis that has an owner which is a scope opener, then this
// is a list assignment and not an array access.
//
// Match `if (true) [$a] = $b;`
if ($tokens[$listOpenerIndex]['code'] === T_OPEN_SQUARE_BRACKET) {
$previousTokenPtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, $listOpenerIndex - 1, null, true);
if (
isset($tokens[$previousTokenPtr])
&& $tokens[$previousTokenPtr]['code'] === T_CLOSE_PARENTHESIS
&& isset($tokens[$previousTokenPtr]['parenthesis_owner'])
&& isset(Tokens::$scopeOpeners[$tokens[$tokens[$previousTokenPtr]['parenthesis_owner']]['code']])
) {
return true;
}
}

return false;
}

/**
* Return a list of indices for variables assigned within a list assignment.
*
* The index provided can be either the opening square brace of a short list
* assignment like the first character of `[$a] = $b;` or the `list` token of
* an expression like `list($a) = $b;` or the opening parenthesis of that
* expression.
*
* @param File $phpcsFile
* @param int $listOpenerIndex
Expand All @@ -666,22 +729,6 @@ public static function getListAssignments(File $phpcsFile, $listOpenerIndex)
$tokens = $phpcsFile->getTokens();
self::debug('getListAssignments', $listOpenerIndex, $tokens[$listOpenerIndex]);

// If the list opener token is preceeded by a variable or a bracket (a
// multidimensional array), this is an array access and not a list
// assignment.
$previousStatementPtr = self::getPreviousStatementPtr($phpcsFile, $listOpenerIndex);
$previousTokenPtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, $listOpenerIndex - 1, $previousStatementPtr, true);
$arrayAccessEvidence = [
T_VARIABLE,
T_CLOSE_SQUARE_BRACKET,
];
if (
isset($tokens[$previousTokenPtr])
&& in_array($tokens[$previousTokenPtr]['code'], $arrayAccessEvidence, true)
) {
return null;
}

// First find the end of the list
$closePtr = null;
if (isset($tokens[$listOpenerIndex]['parenthesis_closer'])) {
Expand Down Expand Up @@ -735,6 +782,10 @@ public static function getListAssignments(File $phpcsFile, $listOpenerIndex)
++$currentPtr;
}

if (! self::isListAssignment($phpcsFile, $listOpenerIndex)) {
return null;
}

return $variablePtrs;
}

Expand Down

0 comments on commit 96274aa

Please sign in to comment.