Skip to content

Commit 4d5420d

Browse files
authored
[DeadCode] Skip RemoveAlwaysTrueIfConditionRector on maybe undefined variable (#8501)
1 parent 7dee71d commit 4d5420d

2 files changed

Lines changed: 31 additions & 3 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Rector\Tests\DeadCode\Rector\If_\RemoveAlwaysTrueIfConditionRector\Fixture;
4+
5+
class SkipMaybeUndefinedVariable
6+
{
7+
public function handle(string $username, string $password, object $response): void
8+
{
9+
if ($username !== 'admin') {
10+
$error = true;
11+
}
12+
13+
if ($password !== 'secret') {
14+
$error = true;
15+
}
16+
17+
if ($error) {
18+
$response->setAttribute('status', 'ERROR');
19+
}
20+
}
21+
}

‎rules/DeadCode/Rector/If_/RemoveAlwaysTrueIfConditionRector.php‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use PhpParser\Node\Stmt\Else_;
2020
use PhpParser\Node\Stmt\If_;
2121
use PhpParser\NodeVisitor;
22+
use PHPStan\Analyser\Scope;
2223
use PHPStan\Reflection\ClassReflection;
2324
use PHPStan\Type\IntersectionType;
2425
use Rector\DeadCode\NodeAnalyzer\SafeLeftTypeBooleanAndOrAnalyzer;
@@ -130,7 +131,8 @@ public function refactor(Node $node): int|null|array|If_
130131
return null;
131132
}
132133

133-
if ($this->shouldSkipFromVariable($node->cond)) {
134+
$scope = ScopeFetcher::fetch($node);
135+
if ($this->shouldSkipFromVariable($node->cond, $scope)) {
134136
return null;
135137
}
136138

@@ -139,7 +141,6 @@ public function refactor(Node $node): int|null|array|If_
139141
return null;
140142
}
141143

142-
$scope = ScopeFetcher::fetch($node);
143144
$type = $scope->getNativeType($node->cond);
144145
if (! $type->isTrue()->yes()) {
145146
return null;
@@ -165,12 +166,18 @@ public function refactor(Node $node): int|null|array|If_
165166
return $node->stmts;
166167
}
167168

168-
private function shouldSkipFromVariable(Expr $expr): bool
169+
private function shouldSkipFromVariable(Expr $expr, Scope $scope): bool
169170
{
170171
/** @var Variable[] $variables */
171172
$variables = $this->betterNodeFinder->findInstancesOf($expr, [Variable::class]);
172173

173174
foreach ($variables as $variable) {
175+
// maybe undefined variable is treated as null on some code paths, so the condition is not always true
176+
$variableName = $this->getName($variable);
177+
if (is_string($variableName) && ! $scope->hasVariableType($variableName)->yes()) {
178+
return true;
179+
}
180+
174181
if ($this->exprAnalyzer->isNonTypedFromParam($variable)) {
175182
return true;
176183
}

0 commit comments

Comments
 (0)