Skip to content

Commit c4b5195

Browse files
committed
ForbidVariableTypeOverwritingRule: fix false positive with fluent $this returns (#347)
Generalize StaticType to its base ObjectType before comparison, so that methods returning $this/static don't cause false positives when reassigning to the same variable. Keep isSuperTypeOf() for comparison to preserve detection of int/float type changes.
1 parent 4cbffcd commit c4b5195

File tree

2 files changed

+17
-4
lines changed

2 files changed

+17
-4
lines changed

src/Rule/ForbidVariableTypeOverwritingRule.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use PHPStan\Type\IntegerRangeType;
1717
use PHPStan\Type\IntersectionType;
1818
use PHPStan\Type\MixedType;
19+
use PHPStan\Type\StaticType;
1920
use PHPStan\Type\SubtractableType;
2021
use PHPStan\Type\Type;
2122
use PHPStan\Type\TypeCombinator;
@@ -63,10 +64,10 @@ public function processNode(
6364
return [];
6465
}
6566

66-
$narrowing = $previousVariableType->accepts($newVariableType, true)->yes();
67-
$generalization = $newVariableType->accepts($previousVariableType, true)->yes();
68-
69-
if (!$narrowing && !$generalization) {
67+
if (
68+
!$previousVariableType->isSuperTypeOf($newVariableType)->yes() // allow narrowing
69+
&& !$newVariableType->isSuperTypeOf($previousVariableType)->yes() // allow generalization
70+
) {
7071
$error = RuleErrorBuilder::message("Overwriting variable \$$variableName while changing its type from {$previousVariableType->describe(VerbosityLevel::precise())} to {$newVariableType->describe(VerbosityLevel::precise())}")
7172
->identifier('shipmonk.variableTypeOverwritten')
7273
->build();
@@ -85,6 +86,10 @@ private function generalizeDeeply(Type $type): Type
8586

8687
private function generalize(Type $type): Type
8788
{
89+
if ($type instanceof StaticType) {
90+
$type = $type->getStaticObjectType(); // @phpstan-ignore shipmonk.variableTypeOverwritten
91+
}
92+
8893
if (
8994
$type->isConstantValue()->yes()
9095
|| $type instanceof IntegerRangeType

tests/Rule/data/ForbidVariableTypeOverwritingRule/code.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,14 @@ function testIntToInt(int $positive, int $negative) {
163163
$positive = $negative;
164164
}
165165

166+
function testFloatToInt(float $float, int $int) {
167+
$float = $int; // error: Overwriting variable $float while changing its type from float to int
168+
}
169+
170+
function testIntToFloat(int $int, float $float) {
171+
$int = $float; // error: Overwriting variable $int while changing its type from int to float
172+
}
173+
166174
class FluentClass {
167175
/** @return $this */
168176
public function orderBy(): static {

0 commit comments

Comments
 (0)