Skip to content

Commit

Permalink
Fix unused-before-used detection (#171)
Browse files Browse the repository at this point in the history
* Add test for unused params after used with global

* Make sure areFollowingArgumentsUsed only examines params

* Remove unused function arguments
  • Loading branch information
sirbrillig committed May 25, 2020
1 parent c905c40 commit 4a60e8b
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 15 deletions.
6 changes: 6 additions & 0 deletions Tests/VariableAnalysisSniff/VariableAnalysisTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public function testFunctionWithGlobalVarWarnings() {
28,
29,
39,
54,
];
$this->assertEquals($expectedWarnings, $lines);
}
Expand Down Expand Up @@ -762,6 +763,7 @@ public function testValidUndefinedVariableNamesIgnoresVarsInGlobalScope() {
7,
23,
39,
54,
];
$this->assertEquals($expectedWarnings, $lines);
}
Expand Down Expand Up @@ -802,6 +804,8 @@ public function testUnusedArgumentsBeforeUsedArgumentsAreFoundIfFalse() {
8,
16,
19,
28,
34,
];
$this->assertEquals($expectedWarnings, $lines);
}
Expand All @@ -814,6 +818,8 @@ public function testUnusedArgumentsBeforeUsedArgumentsAreIgnoredByDefault() {
$expectedWarnings = [
8,
19,
28,
34,
];
$this->assertEquals($expectedWarnings, $lines);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,8 @@ function updateGlobalWithListShorthand($newVal) {
[ $myGlobal, $otherVar ] = my_function($newVal);
echo $otherVar;
}

function globalWithUnusedFunctionArg($user_type, $text, $testvar) { // should warn that testvar is unused
global $config;
return $config . $text . $user_type;
}
14 changes: 14 additions & 0 deletions Tests/VariableAnalysisSniff/fixtures/UnusedAfterUsedFixture.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,17 @@ function inner_function() {
};
$foo();
}

// The following line should report an unused variable (unused after used)
function function_with_one_unused_param($used, $used_two, $unused_three) {
echo $used;
echo $used_two;
}

// The following line should report an unused variable (unused after used)
function function_with_local_and_unused_params($used, $used_two, $unused_three) {
$foobar = 'hello';
echo $used;
echo $foobar;
echo $used_two;
}
27 changes: 12 additions & 15 deletions VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ protected function areFollowingArgumentsUsed($varInfo, $scopeInfo) {
if (! $foundVarPosition) {
continue;
}
if ($variable->scopeType !== 'param') {
continue;
}
if ($variable->firstRead) {
return true;
}
Expand Down Expand Up @@ -522,12 +525,10 @@ protected function checkForFunctionPrototype(File $phpcsFile, $stackPtr, $varNam
/**
* @param File $phpcsFile
* @param int $stackPtr
* @param string $varName
* @param int $currScope
*
* @return bool
*/
protected function checkForClassProperty(File $phpcsFile, $stackPtr, $varName, $currScope) {
protected function checkForClassProperty(File $phpcsFile, $stackPtr) {
$propertyDeclarationKeywords = [
T_PUBLIC,
T_PRIVATE,
Expand Down Expand Up @@ -660,12 +661,10 @@ protected function checkForSuperGlobal(File $phpcsFile, $stackPtr, $varName) {
/**
* @param File $phpcsFile
* @param int $stackPtr
* @param string $varName
* @param int $currScope
*
* @return bool
*/
protected function checkForStaticMember(File $phpcsFile, $stackPtr, $varName, $currScope) {
protected function checkForStaticMember(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();

$doubleColonPtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 1, null, true);
Expand Down Expand Up @@ -696,11 +695,10 @@ protected function checkForStaticMember(File $phpcsFile, $stackPtr, $varName, $c
* @param File $phpcsFile
* @param int $stackPtr
* @param string $varName
* @param int $currScope
*
* @return bool
*/
protected function checkForStaticOutsideClass(File $phpcsFile, $stackPtr, $varName, $currScope) {
protected function checkForStaticOutsideClass(File $phpcsFile, $stackPtr, $varName) {
// Are we refering to self:: outside a class?
$tokens = $phpcsFile->getTokens();
Expand Down Expand Up @@ -752,7 +750,7 @@ protected function checkForAssignment(File $phpcsFile, $stackPtr, $varName, $cur
}

// Is this a variable variable? If so, it's not an assignment to the current variable.
if ($this->checkForVariableVariable($phpcsFile, $stackPtr, $varName, $currScope)) {
if ($this->checkForVariableVariable($phpcsFile, $stackPtr)) {
Helpers::debug('found variable variable');
return false;
}
Expand All @@ -779,12 +777,10 @@ protected function checkForAssignment(File $phpcsFile, $stackPtr, $varName, $cur
/**
* @param File $phpcsFile
* @param int $stackPtr
* @param string $varName
* @param int $currScope
*
* @return bool
*/
protected function checkForVariableVariable(File $phpcsFile, $stackPtr, $varName, $currScope) {
protected function checkForVariableVariable(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();

$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true);
Expand Down Expand Up @@ -1184,18 +1180,18 @@ protected function processVariable(File $phpcsFile, $stackPtr) {
}

// Check for static members used outside a class
if ($this->checkForStaticOutsideClass($phpcsFile, $stackPtr, $varName, $currScope)) {
if ($this->checkForStaticOutsideClass($phpcsFile, $stackPtr, $varName)) {
Helpers::debug('found static usage outside of class');
return;
}

// $var part of class::$var static member
if ($this->checkForStaticMember($phpcsFile, $stackPtr, $varName, $currScope)) {
if ($this->checkForStaticMember($phpcsFile, $stackPtr)) {
Helpers::debug('found static member');
return;
}

if ($this->checkForClassProperty($phpcsFile, $stackPtr, $varName, $currScope)) {
if ($this->checkForClassProperty($phpcsFile, $stackPtr)) {
Helpers::debug('found class property definition');
return;
}
Expand Down Expand Up @@ -1403,6 +1399,7 @@ protected function processScopeCloseForVariable(File $phpcsFile, VariableInfo $v
return;
}
if ($this->allowUnusedParametersBeforeUsed && $varInfo->scopeType === 'param' && $this->areFollowingArgumentsUsed($varInfo, $scopeInfo)) {
Helpers::debug("variable {$varInfo->name} at end of scope has unused following args");
return;
}
if ($this->allowUnusedForeachVariables && $varInfo->isForeachLoopAssociativeValue) {
Expand Down

0 comments on commit 4a60e8b

Please sign in to comment.