Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cbdb30d

Browse files
committed
Do not report unused class elements if the element is used on an uncertain type like mixed
1 parent 6c941ae commit cbdb30d

File tree

7 files changed

+120
-0
lines changed

7 files changed

+120
-0
lines changed

src/Rules/DeadCode/UnusedPrivateConstantRule.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPStan\Rules\Constants\AlwaysUsedClassConstantsExtensionProvider;
99
use PHPStan\Rules\Rule;
1010
use PHPStan\Rules\RuleErrorBuilder;
11+
use PHPStan\Type\ObjectType;
1112
use function sprintf;
1213

1314
/**
@@ -32,6 +33,7 @@ public function processNode(Node $node, Scope $scope): array
3233
}
3334

3435
$classReflection = $node->getClassReflection();
36+
$classType = new ObjectType($classReflection->getName());
3537

3638
$constants = [];
3739
foreach ($node->getConstants() as $constant) {
@@ -68,10 +70,16 @@ public function processNode(Node $node, Scope $scope): array
6870

6971
$constantReflection = $fetchScope->getConstantReflection($fetchedOnClass, $fetchNode->name->toString());
7072
if ($constantReflection === null) {
73+
if (!$classType->isSuperTypeOf($fetchedOnClass)->no()) {
74+
unset($constants[$fetchNode->name->toString()]);
75+
}
7176
continue;
7277
}
7378

7479
if ($constantReflection->getDeclaringClass()->getName() !== $classReflection->getName()) {
80+
if (!$classType->isSuperTypeOf($fetchedOnClass)->no()) {
81+
unset($constants[$fetchNode->name->toString()]);
82+
}
7583
continue;
7684
}
7785

src/Rules/DeadCode/UnusedPrivateMethodRule.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PHPStan\Rules\Rule;
1111
use PHPStan\Rules\RuleErrorBuilder;
1212
use PHPStan\Type\Constant\ConstantStringType;
13+
use PHPStan\Type\ObjectType;
1314
use function array_map;
1415
use function count;
1516
use function sprintf;
@@ -32,6 +33,7 @@ public function processNode(Node $node, Scope $scope): array
3233
return [];
3334
}
3435
$classReflection = $node->getClassReflection();
36+
$classType = new ObjectType($classReflection->getName());
3537
$constructor = null;
3638
if ($classReflection->hasConstructor()) {
3739
$constructor = $classReflection->getConstructor();
@@ -93,9 +95,15 @@ public function processNode(Node $node, Scope $scope): array
9395
foreach ($methodNames as $methodName) {
9496
$methodReflection = $callScope->getMethodReflection($calledOnType, $methodName);
9597
if ($methodReflection === null) {
98+
if (!$classType->isSuperTypeOf($calledOnType)->no()) {
99+
unset($methods[strtolower($methodName)]);
100+
}
96101
continue;
97102
}
98103
if ($methodReflection->getDeclaringClass()->getName() !== $classReflection->getName()) {
104+
if (!$classType->isSuperTypeOf($calledOnType)->no()) {
105+
unset($methods[strtolower($methodName)]);
106+
}
99107
continue;
100108
}
101109
if ($inMethod->getName() === $methodName) {

src/Rules/DeadCode/UnusedPrivatePropertyRule.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PHPStan\Rules\Rule;
1111
use PHPStan\Rules\RuleErrorBuilder;
1212
use PHPStan\Type\Constant\ConstantStringType;
13+
use PHPStan\Type\ObjectType;
1314
use function array_key_exists;
1415
use function array_map;
1516
use function count;
@@ -46,6 +47,7 @@ public function processNode(Node $node, Scope $scope): array
4647
return [];
4748
}
4849
$classReflection = $node->getClassReflection();
50+
$classType = new ObjectType($classReflection->getName());
4951
$properties = [];
5052
foreach ($node->getProperties() as $property) {
5153
if (!$property->isPrivate()) {
@@ -139,9 +141,23 @@ public function processNode(Node $node, Scope $scope): array
139141
}
140142
$propertyReflection = $usage->getScope()->getPropertyReflection($fetchedOnType, $propertyName);
141143
if ($propertyReflection === null) {
144+
if (!$classType->isSuperTypeOf($fetchedOnType)->no()) {
145+
if ($usage instanceof PropertyRead) {
146+
$properties[$propertyName]['read'] = true;
147+
} else {
148+
$properties[$propertyName]['written'] = true;
149+
}
150+
}
142151
continue;
143152
}
144153
if ($propertyReflection->getDeclaringClass()->getName() !== $classReflection->getName()) {
154+
if (!$classType->isSuperTypeOf($fetchedOnType)->no()) {
155+
if ($usage instanceof PropertyRead) {
156+
$properties[$propertyName]['read'] = true;
157+
} else {
158+
$properties[$propertyName]['written'] = true;
159+
}
160+
}
145161
continue;
146162
}
147163

tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,9 @@ public function testBug9005(): void
9292
$this->analyse([__DIR__ . '/data/bug-9005.php'], []);
9393
}
9494

95+
public function testBug9765(): void
96+
{
97+
$this->analyse([__DIR__ . '/data/bug-9765.php'], []);
98+
}
99+
95100
}

tests/PHPStan/Rules/DeadCode/UnusedPrivateMethodRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,9 @@ public function testBug6039(): void
109109
$this->analyse([__DIR__ . '/data/bug-6039.php'], []);
110110
}
111111

112+
public function testBug9765(): void
113+
{
114+
$this->analyse([__DIR__ . '/data/bug-9765.php'], []);
115+
}
116+
112117
}

tests/PHPStan/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,4 +286,11 @@ public function testBug9409(): void
286286
$this->analyse([__DIR__ . '/data/bug-9409.php'], []);
287287
}
288288

289+
public function testBug9765(): void
290+
{
291+
$this->alwaysWrittenTags = [];
292+
$this->alwaysReadTags = [];
293+
$this->analyse([__DIR__ . '/data/bug-9765.php'], []);
294+
}
295+
289296
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug9765;
4+
5+
class HelloWorld
6+
{
7+
8+
public static function runner(): \Closure
9+
{
10+
return function (int $arg) {
11+
return $this->add($arg);
12+
};
13+
}
14+
15+
public function do(): void
16+
{
17+
$c = self::runner();
18+
print $c->bindTo($this)(5);
19+
}
20+
21+
private function add(int $a): int
22+
{
23+
return $a + 1;
24+
}
25+
26+
}
27+
28+
class HelloWorld2
29+
{
30+
31+
/** @var int */
32+
private $foo;
33+
34+
public static function runner(): \Closure
35+
{
36+
return function (int $arg) {
37+
if ($arg > 0) {
38+
$this->foo = $arg;
39+
} else {
40+
echo $this->foo;
41+
}
42+
};
43+
}
44+
45+
public function do(): void
46+
{
47+
$c = self::runner();
48+
print $c->bindTo($this)(5);
49+
}
50+
51+
}
52+
53+
class HelloWorld3
54+
{
55+
56+
private const FOO = 1;
57+
58+
public static function runner(): \Closure
59+
{
60+
return function (int $arg) {
61+
echo $this::FOO;
62+
};
63+
}
64+
65+
public function do(): void
66+
{
67+
$c = self::runner();
68+
print $c->bindTo($this)(5);
69+
}
70+
71+
}

0 commit comments

Comments
 (0)