From 25823a9964c17c419e5b5957b0c58896f229feae Mon Sep 17 00:00:00 2001 From: Payton Swick Date: Fri, 12 Oct 2018 16:42:18 -0400 Subject: [PATCH] Support shorthand list assignment (#50) * Tests: add test for destructuring assignment * Support shorthand list assignment --- VariableAnalysis/Lib/Helpers.php | 19 +++++++++++++ .../CodeAnalysis/VariableAnalysisSniff.php | 28 +++++++++++++++++++ .../CodeAnalysis/VariableAnalysisTest.php | 12 ++++++++ .../fixtures/DestructuringFixture.php | 16 +++++++++++ 4 files changed, 75 insertions(+) create mode 100644 VariableAnalysis/Tests/CodeAnalysis/fixtures/DestructuringFixture.php diff --git a/VariableAnalysis/Lib/Helpers.php b/VariableAnalysis/Lib/Helpers.php index 015b43c2..f9fff8f9 100644 --- a/VariableAnalysis/Lib/Helpers.php +++ b/VariableAnalysis/Lib/Helpers.php @@ -5,6 +5,25 @@ use PHP_CodeSniffer\Files\File; class Helpers { + public static function findContainingOpeningSquareBracket(File $phpcsFile, $stackPtr) { + $tokens = $phpcsFile->getTokens(); + $previousStatementPtr = self::getPreviousStatementPtr($phpcsFile, $stackPtr); + return $phpcsFile->findPrevious(T_OPEN_SHORT_ARRAY, $stackPtr - 1, $previousStatementPtr); + } + + public static function findContainingClosingSquareBracket(File $phpcsFile, $stackPtr) { + $tokens = $phpcsFile->getTokens(); + $endOfStatementPtr = $phpcsFile->findNext([T_SEMICOLON], $stackPtr + 1); + if (! $endOfStatementPtr) { + return false; + } + return $phpcsFile->findNext(T_CLOSE_SHORT_ARRAY, $stackPtr + 1, $endOfStatementPtr); + } + + public static function getPreviousStatementPtr(File $phpcsFile, $stackPtr) { + return $phpcsFile->findPrevious([T_SEMICOLON, T_CLOSE_CURLY_BRACKET], $stackPtr - 1) ?: 1; + } + public static function findContainingOpeningBracket(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]['nested_parenthesis'])) { diff --git a/VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php b/VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php index 074d0dec..4515d277 100644 --- a/VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php +++ b/VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php @@ -446,6 +446,29 @@ protected function checkForAssignment(File $phpcsFile, $stackPtr, $varName, $cur return true; } + protected function checkForListShorthandAssignment(File $phpcsFile, $stackPtr, $varName, $currScope) { + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr]; + + // OK, are we within a [ ... ] construct? + $openPtr = Helpers::findContainingOpeningSquareBracket($phpcsFile, $stackPtr); + if ($openPtr === false) { + return false; + } + + // OK, we're a [ ... ] construct... are we being assigned to? + $closePtr = Helpers::findContainingClosingSquareBracket($phpcsFile, $stackPtr); + $assignPtr = Helpers::isNextThingAnAssign($phpcsFile, $closePtr); + if ($assignPtr === false) { + return false; + } + + // Yes, we're being assigned. + $writtenPtr = Helpers::findWhereAssignExecuted($phpcsFile, $assignPtr); + $this->markVariableAssignment($varName, $writtenPtr, $currScope); + return true; + } + protected function checkForListAssignment(File $phpcsFile, $stackPtr, $varName, $currScope) { $tokens = $phpcsFile->getTokens(); $token = $tokens[$stackPtr]; @@ -745,6 +768,11 @@ protected function processVariable(File $phpcsFile, $stackPtr) { return; } + // OK, are we within a [...] = construct? + if ($this->checkForListShorthandAssignment($phpcsFile, $stackPtr, $varName, $currScope)) { + return; + } + // Are we a global declaration? if ($this->checkForGlobalDeclaration($phpcsFile, $stackPtr, $varName, $currScope)) { return; diff --git a/VariableAnalysis/Tests/CodeAnalysis/VariableAnalysisTest.php b/VariableAnalysis/Tests/CodeAnalysis/VariableAnalysisTest.php index 6606337d..63ca64e9 100644 --- a/VariableAnalysis/Tests/CodeAnalysis/VariableAnalysisTest.php +++ b/VariableAnalysis/Tests/CodeAnalysis/VariableAnalysisTest.php @@ -541,4 +541,16 @@ public function testIgnoreUnusedRegexpIgnoresUnusedVariables() { ]; $this->assertEquals($expectedWarnings, $lines); } + + public function testAllowDestructuringAssignment() { + $fixtureFile = $this->getFixture('DestructuringFixture.php'); + $phpcsFile = $this->prepareLocalFileForSniffs($this->getSniffFiles(), $fixtureFile); + $phpcsFile->process(); + $lines = $this->getWarningLineNumbersFromFile($phpcsFile); + $expectedWarnings = [ + 4, + 12, + ]; + $this->assertEquals($expectedWarnings, $lines); + } } diff --git a/VariableAnalysis/Tests/CodeAnalysis/fixtures/DestructuringFixture.php b/VariableAnalysis/Tests/CodeAnalysis/fixtures/DestructuringFixture.php new file mode 100644 index 00000000..a044fd5c --- /dev/null +++ b/VariableAnalysis/Tests/CodeAnalysis/fixtures/DestructuringFixture.php @@ -0,0 +1,16 @@ +