Skip to content

Commit

Permalink
Do not report unused class elements if the element is used on an unce…
Browse files Browse the repository at this point in the history
…rtain type like `mixed`
  • Loading branch information
ondrejmirtes committed Aug 16, 2023
1 parent 6c941ae commit cbdb30d
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/Rules/DeadCode/UnusedPrivateConstantRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PHPStan\Rules\Constants\AlwaysUsedClassConstantsExtensionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\ObjectType;
use function sprintf;

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

$classReflection = $node->getClassReflection();
$classType = new ObjectType($classReflection->getName());

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

$constantReflection = $fetchScope->getConstantReflection($fetchedOnClass, $fetchNode->name->toString());
if ($constantReflection === null) {
if (!$classType->isSuperTypeOf($fetchedOnClass)->no()) {
unset($constants[$fetchNode->name->toString()]);
}
continue;
}

if ($constantReflection->getDeclaringClass()->getName() !== $classReflection->getName()) {
if (!$classType->isSuperTypeOf($fetchedOnClass)->no()) {
unset($constants[$fetchNode->name->toString()]);
}
continue;
}

Expand Down
8 changes: 8 additions & 0 deletions src/Rules/DeadCode/UnusedPrivateMethodRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\ObjectType;
use function array_map;
use function count;
use function sprintf;
Expand All @@ -32,6 +33,7 @@ public function processNode(Node $node, Scope $scope): array
return [];
}
$classReflection = $node->getClassReflection();
$classType = new ObjectType($classReflection->getName());
$constructor = null;
if ($classReflection->hasConstructor()) {
$constructor = $classReflection->getConstructor();
Expand Down Expand Up @@ -93,9 +95,15 @@ public function processNode(Node $node, Scope $scope): array
foreach ($methodNames as $methodName) {
$methodReflection = $callScope->getMethodReflection($calledOnType, $methodName);
if ($methodReflection === null) {
if (!$classType->isSuperTypeOf($calledOnType)->no()) {
unset($methods[strtolower($methodName)]);
}
continue;
}
if ($methodReflection->getDeclaringClass()->getName() !== $classReflection->getName()) {
if (!$classType->isSuperTypeOf($calledOnType)->no()) {
unset($methods[strtolower($methodName)]);
}
continue;
}
if ($inMethod->getName() === $methodName) {
Expand Down
16 changes: 16 additions & 0 deletions src/Rules/DeadCode/UnusedPrivatePropertyRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\ObjectType;
use function array_key_exists;
use function array_map;
use function count;
Expand Down Expand Up @@ -46,6 +47,7 @@ public function processNode(Node $node, Scope $scope): array
return [];
}
$classReflection = $node->getClassReflection();
$classType = new ObjectType($classReflection->getName());
$properties = [];
foreach ($node->getProperties() as $property) {
if (!$property->isPrivate()) {
Expand Down Expand Up @@ -139,9 +141,23 @@ public function processNode(Node $node, Scope $scope): array
}
$propertyReflection = $usage->getScope()->getPropertyReflection($fetchedOnType, $propertyName);
if ($propertyReflection === null) {
if (!$classType->isSuperTypeOf($fetchedOnType)->no()) {
if ($usage instanceof PropertyRead) {
$properties[$propertyName]['read'] = true;
} else {
$properties[$propertyName]['written'] = true;
}
}
continue;
}
if ($propertyReflection->getDeclaringClass()->getName() !== $classReflection->getName()) {
if (!$classType->isSuperTypeOf($fetchedOnType)->no()) {
if ($usage instanceof PropertyRead) {
$properties[$propertyName]['read'] = true;
} else {
$properties[$propertyName]['written'] = true;
}
}
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,9 @@ public function testBug9005(): void
$this->analyse([__DIR__ . '/data/bug-9005.php'], []);
}

public function testBug9765(): void
{
$this->analyse([__DIR__ . '/data/bug-9765.php'], []);
}

}
5 changes: 5 additions & 0 deletions tests/PHPStan/Rules/DeadCode/UnusedPrivateMethodRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,9 @@ public function testBug6039(): void
$this->analyse([__DIR__ . '/data/bug-6039.php'], []);
}

public function testBug9765(): void
{
$this->analyse([__DIR__ . '/data/bug-9765.php'], []);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -286,4 +286,11 @@ public function testBug9409(): void
$this->analyse([__DIR__ . '/data/bug-9409.php'], []);
}

public function testBug9765(): void
{
$this->alwaysWrittenTags = [];
$this->alwaysReadTags = [];
$this->analyse([__DIR__ . '/data/bug-9765.php'], []);
}

}
71 changes: 71 additions & 0 deletions tests/PHPStan/Rules/DeadCode/data/bug-9765.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php declare(strict_types = 1);

namespace Bug9765;

class HelloWorld
{

public static function runner(): \Closure
{
return function (int $arg) {
return $this->add($arg);
};
}

public function do(): void
{
$c = self::runner();
print $c->bindTo($this)(5);
}

private function add(int $a): int
{
return $a + 1;
}

}

class HelloWorld2
{

/** @var int */
private $foo;

public static function runner(): \Closure
{
return function (int $arg) {
if ($arg > 0) {
$this->foo = $arg;
} else {
echo $this->foo;
}
};
}

public function do(): void
{
$c = self::runner();
print $c->bindTo($this)(5);
}

}

class HelloWorld3
{

private const FOO = 1;

public static function runner(): \Closure
{
return function (int $arg) {
echo $this::FOO;
};
}

public function do(): void
{
$c = self::runner();
print $c->bindTo($this)(5);
}

}

0 comments on commit cbdb30d

Please sign in to comment.