Skip to content

Commit 75768da

Browse files
committed
Simplify getListAssignments using Lists::getAssignments
1 parent 4cc7f35 commit 75768da

File tree

1 file changed

+27
-114
lines changed

1 file changed

+27
-114
lines changed

VariableAnalysis/Lib/Helpers.php

Lines changed: 27 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use VariableAnalysis\Lib\VariableInfo;
1212
use PHP_CodeSniffer\Util\Tokens;
1313
use PHPCSUtils\Utils\Context;
14+
use PHPCSUtils\Utils\Lists;
1415
use PHPCSUtils\Utils\Parentheses;
1516

1617
class Helpers
@@ -733,64 +734,6 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr)
733734
];
734735
}
735736

736-
/**
737-
* Determine if a token is a list opener for list assignment/destructuring.
738-
*
739-
* The index provided can be either the opening square brace of a short list
740-
* assignment like the first character of `[$a] = $b;` or the `list` token of
741-
* an expression like `list($a) = $b;` or the opening parenthesis of that
742-
* expression.
743-
*
744-
* @param File $phpcsFile
745-
* @param int $listOpenerIndex
746-
*
747-
* @return bool
748-
*/
749-
private static function isListAssignment(File $phpcsFile, $listOpenerIndex)
750-
{
751-
$tokens = $phpcsFile->getTokens();
752-
// Match `[$a] = $b;` except for when the previous token is a parenthesis.
753-
if ($tokens[$listOpenerIndex]['code'] === T_OPEN_SHORT_ARRAY) {
754-
return true;
755-
}
756-
// Match `list($a) = $b;`
757-
if ($tokens[$listOpenerIndex]['code'] === T_LIST) {
758-
return true;
759-
}
760-
761-
// If $listOpenerIndex is the open parenthesis of `list($a) = $b;`, then
762-
// match that too.
763-
if ($tokens[$listOpenerIndex]['code'] === T_OPEN_PARENTHESIS) {
764-
$previousTokenPtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, $listOpenerIndex - 1, null, true);
765-
if (
766-
isset($tokens[$previousTokenPtr])
767-
&& $tokens[$previousTokenPtr]['code'] === T_LIST
768-
) {
769-
return true;
770-
}
771-
return true;
772-
}
773-
774-
// If the list opener token is a square bracket that is preceeded by a
775-
// close parenthesis that has an owner which is a scope opener, then this
776-
// is a list assignment and not an array access.
777-
//
778-
// Match `if (true) [$a] = $b;`
779-
if ($tokens[$listOpenerIndex]['code'] === T_OPEN_SQUARE_BRACKET) {
780-
$previousTokenPtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, $listOpenerIndex - 1, null, true);
781-
if (
782-
isset($tokens[$previousTokenPtr])
783-
&& $tokens[$previousTokenPtr]['code'] === T_CLOSE_PARENTHESIS
784-
&& isset($tokens[$previousTokenPtr]['parenthesis_owner'])
785-
&& isset(Tokens::$scopeOpeners[$tokens[$tokens[$previousTokenPtr]['parenthesis_owner']]['code']])
786-
) {
787-
return true;
788-
}
789-
}
790-
791-
return false;
792-
}
793-
794737
/**
795738
* Return a list of indices for variables assigned within a list assignment.
796739
*
@@ -806,74 +749,44 @@ private static function isListAssignment(File $phpcsFile, $listOpenerIndex)
806749
*/
807750
public static function getListAssignments(File $phpcsFile, $listOpenerIndex)
808751
{
809-
$tokens = $phpcsFile->getTokens();
810-
self::debug('getListAssignments', $listOpenerIndex, $tokens[$listOpenerIndex]);
752+
self::debug('getListAssignments', $listOpenerIndex, $phpcsFile->getTokens()[$listOpenerIndex]);
811753

812-
// First find the end of the list
813-
$closePtr = null;
814-
if (isset($tokens[$listOpenerIndex]['parenthesis_closer'])) {
815-
$closePtr = $tokens[$listOpenerIndex]['parenthesis_closer'];
816-
}
817-
if (isset($tokens[$listOpenerIndex]['bracket_closer'])) {
818-
$closePtr = $tokens[$listOpenerIndex]['bracket_closer'];
819-
}
820-
if (! $closePtr) {
754+
// Use PHPCSUtils to get detailed assignment information
755+
try {
756+
$assignments = \PHPCSUtils\Utils\Lists::getAssignments($phpcsFile, $listOpenerIndex);
757+
} catch (\PHPCSUtils\Exceptions\UnexpectedTokenType $e) {
758+
// Not a list token
821759
return null;
822760
}
823761

824-
// Find the assignment (equals sign) which, if this is a list assignment, should be the next non-space token
825-
$assignPtr = $phpcsFile->findNext(Tokens::$emptyTokens, $closePtr + 1, null, true);
826-
827-
// If the next token isn't an assignment, check for nested brackets because we might be a nested assignment
828-
if (! is_int($assignPtr) || $tokens[$assignPtr]['code'] !== T_EQUAL) {
829-
// Collect the enclosing list open/close tokens ($parents is an assoc array keyed by opener index and the value is the closer index)
830-
$parents = isset($tokens[$listOpenerIndex]['nested_parenthesis']) ? $tokens[$listOpenerIndex]['nested_parenthesis'] : [];
831-
// There's no record of nested brackets for short lists; we'll have to find the parent ourselves
832-
if (empty($parents)) {
833-
$parentSquareBracketPtr = self::findContainingOpeningSquareBracket($phpcsFile, $listOpenerIndex);
834-
if (is_int($parentSquareBracketPtr)) {
835-
// Make sure that the parent is really a parent by checking that its
836-
// closing index is outside of the current bracket's closing index.
837-
$parentSquareBracketToken = $tokens[$parentSquareBracketPtr];
838-
$parentSquareBracketClosePtr = $parentSquareBracketToken['bracket_closer'];
839-
if ($parentSquareBracketClosePtr && $parentSquareBracketClosePtr > $closePtr) {
840-
self::debug("found enclosing bracket for {$listOpenerIndex}: {$parentSquareBracketPtr}");
841-
// Collect the opening index, but we don't actually need the closing paren index so just make that 0
842-
$parents = [$parentSquareBracketPtr => 0];
843-
}
844-
}
845-
}
846-
// If we have no parents, this is not a nested assignment and therefore is not an assignment
847-
if (empty($parents)) {
848-
return null;
849-
}
850-
851-
// Recursively check to see if the parent is a list assignment (we only need to check one level due to the recursion)
852-
$isNestedAssignment = null;
853-
$parentListOpener = array_keys(array_reverse($parents, true))[0];
854-
$isNestedAssignment = self::getListAssignments($phpcsFile, $parentListOpener);
855-
if ($isNestedAssignment === null) {
856-
return null;
857-
}
762+
if (empty($assignments)) {
763+
return null;
858764
}
859765

766+
// Extract just the variable token positions for backward compatibility
860767
$variablePtrs = [];
768+
foreach ($assignments as $assignment) {
769+
// Skip empty list items like in: list($a, , $b)
770+
if ($assignment['is_empty']) {
771+
continue;
772+
}
861773

862-
$currentPtr = $listOpenerIndex;
863-
$variablePtr = 0;
864-
while ($currentPtr < $closePtr && is_int($variablePtr)) {
865-
$variablePtr = $phpcsFile->findNext([T_VARIABLE], $currentPtr + 1, $closePtr);
866-
if (is_int($variablePtr)) {
867-
$variablePtrs[] = $variablePtr;
774+
// For nested lists, recursively get the assignments
775+
if ($assignment['is_nested_list'] && $assignment['assignment_token'] !== false) {
776+
$nestedVars = self::getListAssignments($phpcsFile, $assignment['assignment_token']);
777+
if (is_array($nestedVars)) {
778+
$variablePtrs = array_merge($variablePtrs, $nestedVars);
779+
}
780+
continue;
868781
}
869-
++$currentPtr;
870-
}
871782

872-
if (! self::isListAssignment($phpcsFile, $listOpenerIndex)) {
873-
return null;
783+
// For regular variables, use the assignment_token which points to the T_VARIABLE
784+
if ($assignment['assignment_token'] !== false && $assignment['variable'] !== false) {
785+
$variablePtrs[] = $assignment['assignment_token'];
786+
}
874787
}
875788

876-
return $variablePtrs;
789+
return empty($variablePtrs) ? null : $variablePtrs;
877790
}
878791

879792
/**

0 commit comments

Comments
 (0)