Skip to content

Commit a039eb0

Browse files
committed
Force custom descendant detection for cases where PHPStan cannot do that properly (Scope->resolveTypeByName)
1 parent bcb59fe commit a039eb0

File tree

3 files changed

+25
-6
lines changed

3 files changed

+25
-6
lines changed

src/Collector/MethodCallCollector.php

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,24 @@ private function registerMethodCall(
113113
$methodNames = $this->getMethodName($methodCall, $scope);
114114

115115
if ($methodCall instanceof New_) {
116-
if ($methodCall->class instanceof Expr || $methodCall->class instanceof Name) {
116+
if ($methodCall->class instanceof Expr) {
117117
$callerType = $scope->getType($methodCall);
118+
$possibleDescendantCall = null;
119+
120+
} elseif ($methodCall->class instanceof Name) {
121+
$callerType = $scope->resolveTypeByName($methodCall->class);
122+
$possibleDescendantCall = $methodCall->class->toString() === 'static';
123+
118124
} else {
119125
return;
120126
}
121127
} else {
122128
$callerType = $scope->getType($methodCall->var);
129+
$possibleDescendantCall = null;
123130
}
124131

125132
foreach ($methodNames as $methodName) {
126-
foreach ($this->getDeclaringTypesWithMethod($methodName, $callerType, TrinaryLogic::createNo()) as $methodRef) {
133+
foreach ($this->getDeclaringTypesWithMethod($methodName, $callerType, TrinaryLogic::createNo(), $possibleDescendantCall) as $methodRef) {
127134
$this->registerUsage(
128135
new ClassMethodUsage(
129136
$this->usageOriginDetector->detectOrigin($scope),
@@ -145,12 +152,15 @@ private function registerStaticCall(
145152

146153
if ($staticCall->class instanceof Expr) {
147154
$callerType = $scope->getType($staticCall->class);
155+
$possibleDescendantCall = null;
156+
148157
} else {
149-
$callerType = $scope->resolveTypeByName($staticCall->class); // broken in PHPStan, the type here is marked as NOT final
158+
$callerType = $scope->resolveTypeByName($staticCall->class);
159+
$possibleDescendantCall = $staticCall->class->toString() === 'static';
150160
}
151161

152162
foreach ($methodNames as $methodName) {
153-
foreach ($this->getDeclaringTypesWithMethod($methodName, $callerType, TrinaryLogic::createYes()) as $methodRef) {
163+
foreach ($this->getDeclaringTypesWithMethod($methodName, $callerType, TrinaryLogic::createYes(), $possibleDescendantCall) as $methodRef) {
154164
$this->registerUsage(
155165
new ClassMethodUsage(
156166
$this->usageOriginDetector->detectOrigin($scope),
@@ -249,7 +259,8 @@ private function getMethodName(CallLike $call, Scope $scope): array
249259
private function getDeclaringTypesWithMethod(
250260
string $methodName,
251261
Type $type,
252-
TrinaryLogic $isStaticCall
262+
TrinaryLogic $isStaticCall,
263+
?bool $isPossibleDescendant = null
253264
): array
254265
{
255266
$typeNoNull = TypeCombinator::removeNull($type); // remove null to support nullsafe calls
@@ -259,7 +270,8 @@ private function getDeclaringTypesWithMethod(
259270
$result = [];
260271

261272
foreach ($classReflections as $classReflection) {
262-
$result[] = new ClassMethodRef($classReflection->getName(), $methodName, !$classReflection->isFinal());
273+
$possibleDescendant = $isPossibleDescendant ?? !$classReflection->isFinal();
274+
$result[] = new ClassMethodRef($classReflection->getName(), $methodName, $possibleDescendant);
263275
}
264276

265277
if ($this->trackMixedAccess) {

tests/Rule/data/methods/array-map-1.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public function __construct()
1212
[$this, 'method4'];
1313
[self::class, 'method5'];
1414
['static', 'method6']; // https://github.com/phpstan/phpstan/issues/11594
15+
[new self(), 'method7'];
1516
}
1617

1718
public function method1(string $foo): void {} // error: Unused DeadMap\ArrayMapTest::method1
@@ -20,6 +21,7 @@ public function method3(): void {}
2021
public function method4(): void {}
2122
public static function method5(): void {}
2223
public static function method6(): void {} // error: Unused DeadMap\ArrayMapTest::method6
24+
public function method7(): void {}
2325
}
2426

2527
class Child extends ArrayMapTest {
@@ -29,6 +31,7 @@ public function method3(): void {}
2931
public function method4(): void {}
3032
public static function method5(): void {} // should be reported (https://github.com/phpstan/phpstan-src/pull/3372)
3133
public static function method6(): void {} // error: Unused DeadMap\Child::method6
34+
public function method7(): void {} // error: Unused DeadMap\Child::method7
3235

3336
}
3437

tests/Rule/data/methods/clone.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ class CloneClass1 {
66
public function __clone() {}
77
}
88

9+
class CloneClassChild extends CloneClass1 {
10+
public function __clone() {} // error: Unused DeadClone\CloneClassChild::__clone
11+
}
12+
913
class CloneClass2 {
1014
public function __clone() {} // error: Unused DeadClone\CloneClass2::__clone
1115
}

0 commit comments

Comments
 (0)