Skip to content

Commit a07fe65

Browse files
authored
Add UndefinedUnsetVariable sniff code (#208)
* Add test for UndefinedUnsetVariable sniff code * Add UndefinedUnsetVariable sniff code * Add UndefinedUnsetVariable to README
1 parent 0537dec commit a07fe65

File tree

5 files changed

+87
-0
lines changed

5 files changed

+87
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Please note that this README is for VariableAnalysis v3. For documentation about
88

99
- Warns if variables are used without being defined. (Sniff code: `VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable`)
1010
- Warns if variables are used for an array push shortcut without being defined. (Sniff code: `VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedArrayVariable`)
11+
- Warns if variables are used inside `unset()` without being defined. (Sniff code: `VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedUnsetVariable`)
1112
- Warns if variables are set or declared but never used. (Sniff code: `VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable`)
1213
- Warns if function parameters are declared but never used. (Sniff code: `VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedParameter`)
1314
- Warns if function parameters are declared but never used before other parameters that are used. (Sniff code: `VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedParameterBeforeUsed`)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
namespace VariableAnalysis\Tests\VariableAnalysisSniff;
3+
4+
use VariableAnalysis\Tests\BaseTestCase;
5+
6+
class UnsetTest extends BaseTestCase {
7+
public function testUnsetReportsUndefinedVariables() {
8+
$fixtureFile = $this->getFixture('UnsetFixture.php');
9+
$phpcsFile = $this->prepareLocalFileForSniffs($fixtureFile);
10+
$phpcsFile->process();
11+
$lines = $this->getWarningLineNumbersFromFile($phpcsFile);
12+
// Technically, these are not illegal, but they may be typos. See https://github.com/sirbrillig/phpcs-variable-analysis/issues/174
13+
$expectedWarnings = [
14+
6,
15+
11,
16+
];
17+
$this->assertEquals($expectedWarnings, $lines);
18+
}
19+
20+
public function testUnsetHasCorrectSniffCodes() {
21+
$fixtureFile = $this->getFixture('UnsetFixture.php');
22+
$phpcsFile = $this->prepareLocalFileForSniffs($fixtureFile);
23+
$phpcsFile->process();
24+
25+
$warnings = $phpcsFile->getWarnings();
26+
$this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedUnsetVariable', $warnings[6][7][0]['source']);
27+
$this->assertEquals('VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedUnsetVariable', $warnings[11][9][0]['source']);
28+
}
29+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
$foo = 'hello';
4+
5+
unset($foo);
6+
unset($bar); // undefined variable $bar
7+
8+
function unset_loop($array) {
9+
foreach ($array as $value) {
10+
}
11+
unset($key, $value); // undefined variable $key
12+
}

VariableAnalysis/Lib/Helpers.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,4 +830,25 @@ public static function isVariableArrayPushShortcut(File $phpcsFile, $stackPtr) {
830830

831831
return true;
832832
}
833+
834+
/**
835+
* @param File $phpcsFile
836+
* @param int $stackPtr
837+
*
838+
* @return bool
839+
*/
840+
public static function isVariableInsideUnset(File $phpcsFile, $stackPtr) {
841+
$functionIndex = self::getFunctionIndexForFunctionCallArgument($phpcsFile, $stackPtr);
842+
if (! is_int($functionIndex)) {
843+
return false;
844+
}
845+
$tokens = $phpcsFile->getTokens();
846+
if (! isset($tokens[$functionIndex])) {
847+
return false;
848+
}
849+
if ($tokens[$functionIndex]['content'] === 'unset') {
850+
return true;
851+
}
852+
return false;
853+
}
833854
}

VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,12 +560,19 @@ protected function markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $sta
560560
$this->markVariableRead($varName, $stackPtr, $currScope);
561561
if ($this->isVariableUndefined($varName, $stackPtr, $currScope) === true) {
562562
Helpers::debug("variable $varName looks undefined");
563+
563564
if (Helpers::isVariableArrayPushShortcut($phpcsFile, $stackPtr)) {
564565
$this->warnAboutUndefinedArrayPushShortcut($phpcsFile, $varName, $stackPtr);
565566
// Mark the variable as defined if it's of the form `$x[] = 1;`
566567
$this->markVariableAssignment($varName, $stackPtr, $currScope);
567568
return;
568569
}
570+
571+
if (Helpers::isVariableInsideUnset($phpcsFile, $stackPtr)) {
572+
$this->warnAboutUndefinedUnset($phpcsFile, $varName, $stackPtr);
573+
return;
574+
}
575+
569576
$this->warnAboutUndefinedVariable($phpcsFile, $varName, $stackPtr);
570577
}
571578
}
@@ -1773,6 +1780,7 @@ protected function warnAboutUndefinedVariable(File $phpcsFile, $varName, $stackP
17731780
["\${$varName}"]
17741781
);
17751782
}
1783+
17761784
/**
17771785
* @param File $phpcsFile
17781786
* @param string $varName
@@ -1788,4 +1796,20 @@ protected function warnAboutUndefinedArrayPushShortcut(File $phpcsFile, $varName
17881796
["\${$varName}"]
17891797
);
17901798
}
1799+
1800+
/**
1801+
* @param File $phpcsFile
1802+
* @param string $varName
1803+
* @param int $stackPtr
1804+
*
1805+
* @return void
1806+
*/
1807+
protected function warnAboutUndefinedUnset(File $phpcsFile, $varName, $stackPtr) {
1808+
$phpcsFile->addWarning(
1809+
"Variable %s inside unset call is undefined.",
1810+
$stackPtr,
1811+
'UndefinedUnsetVariable',
1812+
["\${$varName}"]
1813+
);
1814+
}
17911815
}

0 commit comments

Comments
 (0)