Skip to content

Commit 4d53127

Browse files
committed
Add analysis of variable use within HEREDOC blocks.
Fix regexp for finding variables in string blocks. Explicit ignore of scope for class member vars. Trial code for fixing file-scope vars (warning: untested!)
1 parent fa6e01c commit 4d53127

File tree

3 files changed

+53
-14
lines changed

3 files changed

+53
-14
lines changed

Sniffs/CodeAnalysis/VariableAnalysisSniff.php

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -346,10 +346,10 @@ class Generic_Sniffs_CodeAnalysis_VariableAnalysisSniff implements PHP_CodeSniff
346346

347347
/**
348348
* Returns an array of tokens this test wants to listen for.
349-
*
349+
*
350350
* @return array
351351
*/
352-
public function register() {
352+
public function register() {
353353
// Magic to modfy $_passByRefFunctions with any site-specific settings.
354354
if (!empty($this->sitePassByRefFunctions)) {
355355
foreach (preg_split('/\s+/', trim($this->sitePassByRefFunctions)) as $line) {
@@ -364,6 +364,7 @@ public function register() {
364364
return array(
365365
T_VARIABLE,
366366
T_DOUBLE_QUOTED_STRING,
367+
T_HEREDOC,
367368
T_CLOSE_CURLY_BRACKET,
368369
);
369370
}//end register()
@@ -374,7 +375,7 @@ public function register() {
374375
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
375376
* @param int $stackPtr The position of the current token
376377
* in the stack passed in $tokens.
377-
*
378+
*
378379
* @return void
379380
*/
380381
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) {
@@ -392,7 +393,8 @@ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) {
392393
if ($token['code'] === T_VARIABLE) {
393394
return $this->processVariable($phpcsFile, $stackPtr);
394395
}
395-
if ($token['code'] === T_DOUBLE_QUOTED_STRING) {
396+
if (($token['code'] === T_DOUBLE_QUOTED_STRING) ||
397+
($token['code'] === T_HEREDOC)) {
396398
return $this->processVariableInString($phpcsFile, $stackPtr);
397399
}
398400
if (($token['code'] === T_CLOSE_CURLY_BRACKET) &&
@@ -541,15 +543,29 @@ function findVariableScope(
541543
$tokens = $phpcsFile->getTokens();
542544
$token = $tokens[$stackPtr];
543545

546+
$in_class = false;
544547
if (!empty($token['conditions'])) {
545548
foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) {
546549
if (($scopeCode === T_FUNCTION) || ($scopeCode === T_CLOSURE)) {
547550
return $scopePtr;
548551
}
552+
if (($scopeCode === T_CLASS) || ($scopeCode === T_INTERFACE)) {
553+
$in_class = true;
554+
}
549555
}
550556
}
551557

552-
return $this->findFunctionPrototype($phpcsFile, $stackPtr);
558+
if (($scopePtr = $this->findFunctionPrototype($phpcsFile, $stackPtr)) !== false) {
559+
return $scopePtr;
560+
}
561+
562+
if ($in_class) {
563+
// Member var of a class, we don't care.
564+
return false;
565+
}
566+
567+
// File scope, hmm, lets use first token of file?
568+
return 0;
553569
}
554570

555571
function isNextThingAnAssign(
@@ -1229,7 +1245,7 @@ protected function processVariableInString(
12291245
$tokens = $phpcsFile->getTokens();
12301246
$token = $tokens[$stackPtr];
12311247

1232-
$pattern = '|[^\\\]\${?([a-zA-Z0-9_]+)}?|';
1248+
$pattern = '|(?<!\\\\)(?:\\\\{2})*\${?([a-zA-Z0-9_]+)}?|';
12331249
if (!preg_match_all($pattern, $token['content'], $matches)) {
12341250
return;
12351251
}
@@ -1242,7 +1258,7 @@ protected function processVariableInString(
12421258
continue;
12431259
}
12441260
if ($this->checkForSuperGlobal($phpcsFile, $stackPtr, $varName, $currScope)) {
1245-
return;
1261+
continue;
12461262
}
12471263
$this->markVariableRead($varName, $stackPtr, $currScope);
12481264
if ($this->isVariableUndefined($varName, $stackPtr, $currScope) === true) {

Tests/CodeAnalysis/VariableAnalysisUnitTest.inc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ function function_without_param() {
44
echo $var;
55
echo "xxx $var xxx";
66
echo "xxx {$var} xxx";
7+
echo "xxx ${var} xxx";
78
echo "xxx $var $var2 xxx";
89
echo "xxx {$var} {$var2} xxx";
910
func($var);
@@ -375,4 +376,19 @@ function function_with_superglobals() {
375376
echo print_r($_REQUEST, true);
376377
echo print_r($_ENV, true);
377378
echo "$GLOBALS['whatever']";
379+
echo "$GLOBALS['whatever'] $var";
380+
}
381+
382+
function function_with_heredoc() {
383+
$var = 10;
384+
echo <<<END_OF_TEXT
385+
$var
386+
{$var}
387+
${var}
388+
$var2
389+
{$var2}
390+
${var2}
391+
\$var2
392+
\\$var2
393+
END_OF_TEXT;
378394
}

Tests/CodeAnalysis/VariableAnalysisUnitTest.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,19 @@ private function _getWarningAndErrorList() {
5959
($base += 3) => 0,
6060
($base + 1) => 1, // $var
6161
($base + 2) => 1, // $var
62-
($base + 3) => 1, // $var
63-
($base + 4) => 2, // $var $var2
62+
($base + 3) => 1, // {$var}
63+
($base + 4) => 1, // ${var}
6464
($base + 5) => 2, // $var $var2
65-
($base + 6) => 1, // $var
65+
($base + 6) => 2, // $var $var2
6666
($base + 7) => 1, // $var
6767
($base + 8) => 1, // $var
6868
($base + 9) => 1, // $var
69-
($base + 14) => 1, // $var2
69+
($base + 10) => 1, // $var
7070
($base + 15) => 1, // $var2
71-
// function_with_param() line (+23)
71+
($base + 16) => 1, // $var2
72+
// function_with_param() line (+24)
7273
// no warnings.
73-
($base += 23) => 0,
74+
($base += 24) => 0,
7475
// function_with_default_defined_param() line (+11)
7576
($base += 11) => 0,
7677
($base + 0) => 1, // $unused
@@ -205,8 +206,14 @@ private function _getWarningAndErrorList() {
205206
// no warnings.
206207
($base += 19) => 0,
207208
// function_with_superglobals() line (+11)
208-
// no warnings.
209209
($base += 11) => 0,
210+
($base + 11) => 1, // $var
211+
// function_with_heredoc() line (+14)
212+
($base += 14) => 0,
213+
($base + 6) => 1, // $var2
214+
($base + 7) => 1, // {$var2}
215+
($base + 8) => 1, // ${var2}
216+
($base + 10) => 1, // \\$var2
210217
);
211218
}//end _getWarningAndErrorList()
212219

0 commit comments

Comments
 (0)