Skip to content

Commit 984a0ae

Browse files
authored
Make assignment of a reference variable be considered a use (#128)
* Add a test * Mark reference variables are used when they are * Fix coding standards
1 parent 4f8e440 commit 984a0ae

File tree

4 files changed

+75
-0
lines changed

4 files changed

+75
-0
lines changed

VariableAnalysis/Lib/VariableInfo.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ class VariableInfo {
2828
*/
2929
public $passByReference = false;
3030

31+
/**
32+
* @var bool
33+
*/
34+
public $isReference = false;
35+
3136
/**
3237
* Stack pointer of first declaration
3338
*

VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,19 @@ protected function checkForAssignment(File $phpcsFile, $stackPtr, $varName, $cur
756756
// Plain ol' assignment. Simpl(ish).
757757
$writtenPtr = Helpers::findWhereAssignExecuted($phpcsFile, $assignPtr);
758758
$this->markVariableAssignment($varName, $writtenPtr, $currScope);
759+
760+
// Are we are reference variable?
761+
$tokens = $tokens = $phpcsFile->getTokens();
762+
$referencePtr = $phpcsFile->findNext(T_WHITESPACE, $assignPtr + 1, null, true, null, true);
763+
$varInfo = $this->getOrCreateVariableInfo($varName, $currScope);
764+
if (($referencePtr !== false) && ($tokens[$referencePtr]['code'] === T_BITWISE_AND)) {
765+
$varInfo->isReference = true;
766+
} elseif ($varInfo->isReference) {
767+
// If this is an assigment to a reference variable then that variable is
768+
// used.
769+
$this->markVariableRead($varName, $stackPtr, $currScope);
770+
}
771+
759772
return true;
760773
}
761774

VariableAnalysis/Tests/CodeAnalysis/VariableAnalysisTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,4 +936,16 @@ public function testUnusedVarWithValueChange() {
936936
];
937937
$this->assertEquals($expectedWarnings, $lines);
938938
}
939+
940+
public function testAssignmentByReference() {
941+
$fixtureFile = $this->getFixture('AssignmentByReferenceFixture.php');
942+
$phpcsFile = $this->prepareLocalFileForSniffs($fixtureFile);
943+
$phpcsFile->process();
944+
$lines = $this->getWarningLineNumbersFromFile($phpcsFile);
945+
$expectedWarnings = [
946+
26,
947+
33,
948+
];
949+
$this->assertEquals($expectedWarnings, $lines);
950+
}
939951
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
class A {
4+
protected $prop = [];
5+
6+
public function __construct() {
7+
$this->prop[] = 'foo';
8+
}
9+
10+
public function &getProp() {
11+
return $this->prop;
12+
}
13+
}
14+
15+
function usedAssignmentByReference() {
16+
$a = new A();
17+
18+
$var = &$a->getProp();
19+
$var = ['bar'];
20+
return $a;
21+
}
22+
23+
function unusedAssignmentByReference() {
24+
$a = new A();
25+
26+
$var = &$a->getProp();
27+
return $a;
28+
}
29+
30+
function doubleUnusedAssignmentByReference() {
31+
$a = new A();
32+
33+
$var = &$a->getProp();
34+
$var = &$a->getProp();
35+
return $a;
36+
}
37+
38+
function doubleUnusedThenUsedAssignmentByReference() {
39+
$a = new A();
40+
41+
// @todo the first one should be marked as unused.
42+
$var = &$a->getProp();
43+
$var = &$a->getProp();
44+
return $var;
45+
}

0 commit comments

Comments
 (0)