Skip to content

Commit 1d89f26

Browse files
brandonkalsirbrillig
authored andcommitted
Option for undefined vars (#56)
* Add option to ignore variable seen as undefined Rather than declaring `global $post` on every single WordPress theme part, I find this option useful, especially when reviewing third-party themes that would otherwise have many warnings. * Add tests * update readme
1 parent 25823a9 commit 1d89f26

File tree

6 files changed

+79
-3
lines changed

6 files changed

+79
-3
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ The available options are as follows:
6666
- `allowUnusedCaughtExceptions` (bool, default `false`): if set to true, caught Exception variables will never be marked as unused.
6767
- `validUnusedVariableNames` (string, default `null`): a space-separated list of names of placeholder variables that you want to ignore from unused variable warnings. For example, to ignore the variables `$junk` and `$unused`, this could be set to `'junk unused'`.
6868
- `ignoreUnusedRegexp` (string, default `null`): a PHP regexp string (note that this requires explicit delimiters) for variables that you want to ignore from unused variable warnings. For example, to ignore the variables `$_junk` and `$_unused`, this could be set to `'/^_/'`.
69+
- `validUndefinedVariableNames` (string, default `null`): a space-separated list of names of placeholder variables that you want to ignore from undefined variable warnings. For example, to ignore the variables `$post` and `$undefined`, this could be set to `'post undefined'`.
6970

7071
To set these these options, you must use XML in your ruleset. For details, see the [phpcs customizable sniff properties page](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Customisable-Sniff-Properties). Here is an example that ignores all variables that start with an underscore:
7172

Diff for: VariableAnalysis/Lib/VariableInfo.php

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class VariableInfo {
1717
public $firstInitialized;
1818
public $firstRead;
1919
public $ignoreUnused = false;
20+
public $ignoreUndefined = false;
2021

2122
public static $scopeTypeDescriptions = array(
2223
'local' => 'variable',

Diff for: VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php

+16
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ class VariableAnalysisSniff implements Sniff {
5454
*/
5555
public $ignoreUnusedRegexp = null;
5656

57+
/**
58+
* A space-separated list of names of placeholder variables that you want to
59+
* ignore from undefined variable warnings. For example, to ignore the variables
60+
* `$post` and `$undefined`, this could be set to `'post undefined'`.
61+
*/
62+
public $validUdefinedVariableNames = null;
63+
5764
public function register() {
5865
return [
5966
T_VARIABLE,
@@ -130,12 +137,18 @@ protected function getOrCreateVariableInfo($varName, $currScope) {
130137
$validUnusedVariableNames = (empty($this->validUnusedVariableNames))
131138
? []
132139
: preg_split('/\s+/', trim($this->validUnusedVariableNames));
140+
$validUndefinedVariableNames = (empty($this->validUndefinedVariableNames))
141+
? []
142+
: preg_split('/\s+/', trim($this->validUndefinedVariableNames));
133143
if (in_array($varName, $validUnusedVariableNames)) {
134144
$scopeInfo->variables[$varName]->ignoreUnused = true;
135145
}
136146
if (isset($this->ignoreUnusedRegexp) && preg_match($this->ignoreUnusedRegexp, $varName) === 1) {
137147
$scopeInfo->variables[$varName]->ignoreUnused = true;
138148
}
149+
if (in_array($varName, $validUndefinedVariableNames)) {
150+
$scopeInfo->variables[$varName]->ignoreUndefined = true;
151+
}
139152
}
140153
return $scopeInfo->variables[$varName];
141154
}
@@ -206,6 +219,9 @@ protected function isVariableInitialized($varName, $stackPtr, $currScope) {
206219

207220
protected function isVariableUndefined($varName, $stackPtr, $currScope) {
208221
$varInfo = $this->getVariableInfo($varName, $currScope);
222+
if ($varInfo->ignoreUndefined) {
223+
return false;
224+
}
209225
if (isset($varInfo->firstDeclared) && $varInfo->firstDeclared <= $stackPtr) {
210226
// TODO: do we want to check scopeType here?
211227
return false;

Diff for: VariableAnalysis/Tests/CodeAnalysis/VariableAnalysisTest.php

+49-3
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,10 @@ public function testFunctionWithGlobalVarWarnings() {
8484
$expectedWarnings = [
8585
4,
8686
7,
87-
22,
87+
8,
88+
23,
89+
28,
90+
29
8891
];
8992
$this->assertEquals($expectedWarnings, $lines);
9093
}
@@ -355,8 +358,12 @@ public function testClassReferenceWarnings() {
355358
$expectedWarnings = [
356359
10,
357360
11,
358-
20,
359-
21,
361+
12,
362+
13,
363+
22,
364+
23,
365+
24,
366+
25
360367
];
361368
$this->assertEquals($expectedWarnings, $lines);
362369
}
@@ -553,4 +560,43 @@ public function testAllowDestructuringAssignment() {
553560
];
554561
$this->assertEquals($expectedWarnings, $lines);
555562
}
563+
564+
public function testValidUndefinedVariableNamesIgnoresVarsInGlobalScope() {
565+
$fixtureFile = $this->getFixture('FunctionWithGlobalVarFixture.php');
566+
$phpcsFile = $this->prepareLocalFileForSniffs($this->getSniffFiles(), $fixtureFile);
567+
$phpcsFile->ruleset->setSniffProperty(
568+
'VariableAnalysis\Sniffs\CodeAnalysis\VariableAnalysisSniff',
569+
'validUndefinedVariableNames',
570+
'ice_cream'
571+
);
572+
$phpcsFile->process();
573+
$lines = $this->getWarningLineNumbersFromFile($phpcsFile);
574+
$expectedWarnings = [
575+
4,
576+
7,
577+
23,
578+
];
579+
$this->assertEquals($expectedWarnings, $lines);
580+
}
581+
582+
public function testValidUndefinedVariableNamesIgnoresUndefinedProperties() {
583+
$fixtureFile = $this->getFixture('ClassReferenceFixture.php');
584+
$phpcsFile = $this->prepareLocalFileForSniffs($this->getSniffFiles(), $fixtureFile);
585+
$phpcsFile->ruleset->setSniffProperty(
586+
'VariableAnalysis\Sniffs\CodeAnalysis\VariableAnalysisSniff',
587+
'validUndefinedVariableNames',
588+
'ignored_property'
589+
);
590+
$phpcsFile->process();
591+
$lines = $this->getWarningLineNumbersFromFile($phpcsFile);
592+
$expectedWarnings = [
593+
10,
594+
11,
595+
22,
596+
23,
597+
24,
598+
25
599+
];
600+
$this->assertEquals($expectedWarnings, $lines);
601+
}
556602
}

Diff for: VariableAnalysis/Tests/CodeAnalysis/fixtures/ClassReferenceFixture.php

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ function method_with_symbolic_ref_property() {
99
$this -> $property = 'some value';
1010
$this->$undefined_property = 'some value';
1111
$this -> $undefined_property = 'some value';
12+
$this->$ignored_property = 'some value';
13+
$this -> $ignored_property = 'some value';
1214
}
1315
}
1416

@@ -19,6 +21,8 @@ function method_with_symbolic_ref_method() {
1921
$this -> $method();
2022
$this->$undefined_method();
2123
$this -> $undefined_method();
24+
$this->$ignored_method();
25+
$this -> $ignored_method();
2226
}
2327
}
2428
}

Diff for: VariableAnalysis/Tests/CodeAnalysis/fixtures/FunctionWithGlobalVarFixture.php

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ function function_with_global_var() {
55

66
echo $var;
77
echo $var3;
8+
echo $ice_cream;
89
return $var2;
910
}
1011

@@ -21,3 +22,10 @@ function function_with_superglobals() {
2122
echo "{$GLOBALS['whatever']}";
2223
echo "{$GLOBALS['whatever']} $var";
2324
}
25+
26+
// Variables within the global scope
27+
$cherry = 'topping';
28+
$sunday = $ice_cream . 'and a ' . $cherry;
29+
if ( $ice_cream ) {
30+
echo 'Two scoops please!';
31+
}

0 commit comments

Comments
 (0)