Skip to content

Commit a31046c

Browse files
authored
Allow global var assignment to count as a read (#83)
* Tests: improve tests for global keyword * Add some additional debugging for undefined vars * Add docs for some VariableInfo properties * Inline getStackPtrIfVariableIsUnused * Allow global var assignment to count as a read * Tests: add fixture for single unused global
1 parent 92047de commit a31046c

File tree

5 files changed

+31
-22
lines changed

5 files changed

+31
-22
lines changed

VariableAnalysis/Lib/Helpers.php

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -228,16 +228,6 @@ public static function findVariableScope(File $phpcsFile, $stackPtr) {
228228
return 0;
229229
}
230230

231-
public static function getStackPtrIfVariableIsUnused(VariableInfo $varInfo) {
232-
if (isset($varInfo->firstDeclared)) {
233-
return $varInfo->firstDeclared;
234-
}
235-
if (isset($varInfo->firstInitialized)) {
236-
return $varInfo->firstInitialized;
237-
}
238-
return null;
239-
}
240-
241231
public static function debug($message) {
242232
if (! defined('PHP_CODESNIFFER_VERBOSITY')) {
243233
return;

VariableAnalysis/Lib/VariableInfo.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ class VariableInfo {
1313
public $scopeType;
1414
public $typeHint;
1515
public $passByReference = false;
16-
public $firstDeclared;
17-
public $firstInitialized;
18-
public $firstRead;
16+
public $firstDeclared; // stack pointer of first declaration
17+
public $firstInitialized; // stack pointer of first initialization
18+
public $firstRead; // stack pointer of first read
1919
public $ignoreUnused = false;
2020
public $ignoreUndefined = false;
2121
public $isForeachLoopVar = false;

VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ protected function isVariableUndefined($varName, $stackPtr, $currScope) {
274274
protected function markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope) {
275275
$this->markVariableRead($varName, $stackPtr, $currScope);
276276
if ($this->isVariableUndefined($varName, $stackPtr, $currScope) === true) {
277+
Helpers::debug("variable $varName looks undefined");
277278
$phpcsFile->addWarning(
278279
"Variable %s is undefined.",
279280
$stackPtr,
@@ -319,6 +320,7 @@ protected function checkForFunctionPrototype(File $phpcsFile, $stackPtr, $varNam
319320
$this->markVariableRead($varName, $stackPtr, $currScope);
320321
if ($this->isVariableUndefined($varName, $stackPtr, $currScope) === true) {
321322
// We haven't been defined by this point.
323+
Helpers::debug("variable $varName in function prototype looks undefined");
322324
$phpcsFile->addWarning("Variable %s is undefined.", $stackPtr, 'UndefinedVariable', ["\${$varName}"]);
323325
return true;
324326
}
@@ -577,7 +579,6 @@ protected function checkForListAssignment(File $phpcsFile, $stackPtr, $varName,
577579

578580
protected function checkForGlobalDeclaration(File $phpcsFile, $stackPtr, $varName, $currScope) {
579581
$tokens = $phpcsFile->getTokens();
580-
$token = $tokens[$stackPtr];
581582

582583
// Are we a global declaration?
583584
// Search backwards for first token that isn't whitespace, comma or variable.
@@ -1052,8 +1053,15 @@ protected function processScopeCloseForVariable($phpcsFile, $varInfo, $scopeInfo
10521053
// of "unused variable" warnings.
10531054
return;
10541055
}
1055-
$stackPtr = Helpers::getStackPtrIfVariableIsUnused($varInfo);
1056+
if ($varInfo->scopeType === 'global' && isset($varInfo->firstInitialized)) {
1057+
// If we imported this variable from the global scope, any further use of
1058+
// the variable, including assignment, should count as "variable use" for
1059+
// the purposes of "unused variable" warnings.
1060+
return;
1061+
}
1062+
$stackPtr = $varInfo->firstDeclared ?? $varInfo->firstInitialized ?? null;
10561063
if ($stackPtr) {
1064+
Helpers::debug("variable {$varInfo->name} at end of scope looks undefined");
10571065
$phpcsFile->addWarning(
10581066
"Unused %s %s.",
10591067
$stackPtr,

VariableAnalysis/Tests/CodeAnalysis/VariableAnalysisTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ public function testFunctionWithGlobalVarWarnings() {
9595
8,
9696
23,
9797
28,
98-
29
98+
29,
99+
39,
99100
];
100101
$this->assertEquals($expectedWarnings, $lines);
101102
}
@@ -734,6 +735,7 @@ public function testValidUndefinedVariableNamesIgnoresVarsInGlobalScope() {
734735
4,
735736
7,
736737
23,
738+
39,
737739
];
738740
$this->assertEquals($expectedWarnings, $lines);
739741
}

VariableAnalysis/Tests/CodeAnalysis/fixtures/FunctionWithGlobalVarFixture.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<?php
22

33
function function_with_global_var() {
4-
global $var, $var2, $unused;
4+
global $var, $var2, $unused; // should warn that `unused` is unused
55

66
echo $var;
7-
echo $var3;
8-
echo $ice_cream;
7+
echo $var3; // should warn that var is undefined
8+
echo $ice_cream; // should warn that var is undefined
99
return $var2;
1010
}
1111

@@ -20,12 +20,21 @@ function function_with_superglobals() {
2020
echo print_r($_REQUEST, true);
2121
echo print_r($_ENV, true);
2222
echo "{$GLOBALS['whatever']}";
23-
echo "{$GLOBALS['whatever']} $var";
23+
echo "{$GLOBALS['whatever']} $var"; // should warn that var is undefined
2424
}
2525

2626
// Variables within the global scope
2727
$cherry = 'topping';
28-
$sunday = $ice_cream . 'and a ' . $cherry;
29-
if ( $ice_cream ) {
28+
$sunday = $ice_cream . 'and a ' . $cherry; // should warn that ice_cream is undefined
29+
if ( $ice_cream ) { // should warn that var is undefined
3030
echo 'Two scoops please!';
3131
}
32+
33+
function updateGlobal($newVal) {
34+
global $myGlobal;
35+
$myGlobal = $newVal;
36+
}
37+
38+
function unusedGlobal() {
39+
global $myGlobal; // should warn that var is unused
40+
}

0 commit comments

Comments
 (0)