Skip to content

Commit c2cfca3

Browse files
committed
UselessVariableSniff: Fixed false positive
1 parent 165c96a commit c2cfca3

File tree

5 files changed

+47
-8
lines changed

5 files changed

+47
-8
lines changed

SlevomatCodingStandard/Sniffs/Variables/UselessVariableSniff.php

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use function preg_quote;
1616
use function sprintf;
1717
use const T_AND_EQUAL;
18+
use const T_BITWISE_AND;
1819
use const T_CONCAT_EQUAL;
1920
use const T_DIV_EQUAL;
2021
use const T_DO;
@@ -78,7 +79,13 @@ public function process(File $phpcsFile, $returnPointer): void
7879

7980
$variableName = $tokens[$variablePointer]['content'];
8081

81-
if ($this->isStaticVariable($phpcsFile, $variablePointer, $variableName)) {
82+
$functionPointer = $this->findFunctionPointer($phpcsFile, $variablePointer);
83+
84+
if ($this->isReturnedByReference($phpcsFile, $functionPointer)) {
85+
return;
86+
}
87+
88+
if ($this->isStaticVariable($phpcsFile, $functionPointer, $variablePointer, $variableName)) {
8289
return;
8390
}
8491

@@ -118,7 +125,10 @@ public function process(File $phpcsFile, $returnPointer): void
118125
return;
119126
}
120127

121-
if (!in_array($tokens[$pointerBeforePreviousVariable]['code'], [T_SEMICOLON, T_OPEN_CURLY_BRACKET], true)) {
128+
if (
129+
!in_array($tokens[$pointerBeforePreviousVariable]['code'], [T_SEMICOLON, T_OPEN_CURLY_BRACKET], true)
130+
&& TokenHelper::findNextEffective($phpcsFile, $returnSemicolonPointer + 1) !== null
131+
) {
122132
$phpcsFile->addError(...$errorParameters);
123133
return;
124134
}
@@ -223,22 +233,27 @@ private function isAssigmentToVariable(File $phpcsFile, int $pointer): bool
223233
], true);
224234
}
225235

226-
private function isStaticVariable(File $phpcsFile, int $variablePointer, string $variableName): bool
236+
private function findFunctionPointer(File $phpcsFile, int $pointer): ?int
227237
{
228238
$tokens = $phpcsFile->getTokens();
229239

230-
$functionPointer = null;
231-
foreach (array_reverse($tokens[$variablePointer]['conditions'], true) as $conditionPointer => $conditionTokenCode) {
240+
foreach (array_reverse($tokens[$pointer]['conditions'], true) as $conditionPointer => $conditionTokenCode) {
232241
if (in_array($conditionTokenCode, TokenHelper::$functionTokenCodes, true)) {
233-
$functionPointer = $conditionPointer;
234-
break;
242+
return $conditionPointer;
235243
}
236244
}
237245

246+
return null;
247+
}
248+
249+
private function isStaticVariable(File $phpcsFile, ?int $functionPointer, int $variablePointer, string $variableName): bool
250+
{
238251
if ($functionPointer === null) {
239252
return false;
240253
}
241254

255+
$tokens = $phpcsFile->getTokens();
256+
242257
for ($i = $tokens[$functionPointer]['scope_opener'] + 1; $i < $variablePointer; $i++) {
243258
if ($tokens[$i]['code'] !== T_VARIABLE) {
244259
continue;
@@ -256,6 +271,18 @@ private function isStaticVariable(File $phpcsFile, int $variablePointer, string
256271
return false;
257272
}
258273

274+
private function isReturnedByReference(File $phpcsFile, ?int $functionPointer): bool
275+
{
276+
if ($functionPointer === null) {
277+
return false;
278+
}
279+
280+
$tokens = $phpcsFile->getTokens();
281+
282+
$referencePointer = TokenHelper::findNextEffective($phpcsFile, $functionPointer + 1);
283+
return $tokens[$referencePointer]['code'] === T_BITWISE_AND;
284+
}
285+
259286
private function hasVariableVarAnnotation(File $phpcsFile, int $variablePointer): bool
260287
{
261288
$tokens = $phpcsFile->getTokens();

tests/Sniffs/Variables/UselessVariableSniffTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function testErrors(): void
1717
{
1818
$report = self::checkFile(__DIR__ . '/data/uselessVariableErrors.php');
1919

20-
self::assertSame(17, $report->getErrorCount());
20+
self::assertSame(18, $report->getErrorCount());
2121

2222
self::assertSniffError($report, 4, UselessVariableSniff::CODE_USELESS_VARIABLE, 'Useless variable $a.');
2323
self::assertSniffError($report, 9, UselessVariableSniff::CODE_USELESS_VARIABLE, 'Useless variable $b.');
@@ -36,6 +36,7 @@ public function testErrors(): void
3636
self::assertSniffError($report, 78, UselessVariableSniff::CODE_USELESS_VARIABLE, 'Useless variable $o.');
3737
self::assertSniffError($report, 84, UselessVariableSniff::CODE_USELESS_VARIABLE, 'Useless variable $p.');
3838
self::assertSniffError($report, 89, UselessVariableSniff::CODE_USELESS_VARIABLE, 'Useless variable $q.');
39+
self::assertSniffError($report, 93, UselessVariableSniff::CODE_USELESS_VARIABLE, 'Useless variable $z.');
3940

4041
self::assertAllFixedInFile($report);
4142
}

tests/Sniffs/Variables/data/uselessVariableErrors.fixed.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,5 @@ function assigmentAfterAssignment() {
7272
doSomething($qq = $q = 0);
7373
return $q;
7474
}
75+
76+
return null;

tests/Sniffs/Variables/data/uselessVariableErrors.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,6 @@ function assigmentAfterAssignment() {
8989
doSomething($qq = $q = 0);
9090
return $q;
9191
}
92+
93+
$z = null;
94+
return $z;

tests/Sniffs/Variables/data/uselessVariableNoErrors.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,9 @@ public static function popBar() : array
148148
}
149149

150150
}
151+
152+
function &returnsReference($result)
153+
{
154+
$value = $result->getValue();
155+
return $value;
156+
}

0 commit comments

Comments
 (0)