Skip to content

Commit

Permalink
Generalize to AST-based MemberUsageProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
janedbal committed Dec 9, 2024
1 parent 5cba669 commit 247098f
Show file tree
Hide file tree
Showing 26 changed files with 379 additions and 268 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ services:
```php

use ReflectionMethod;
use ShipMonk\PHPStan\DeadCode\Provider\SimpleMethodUsageProvider;
use ShipMonk\PHPStan\DeadCode\Provider\ReflectionBasedMemberUsageProvider;

class ApiOutputMethodUsageProvider extends SimpleMethodUsageProvider
class ApiOutputMethodUsageProvider extends ReflectionBasedMemberUsageProvider
{

public function shouldMarkMethodAsUsed(ReflectionMethod $method): bool
Expand Down
3 changes: 1 addition & 2 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ parameters:
PHPStan\Rules\Rule: Rule
PHPStan\Collectors\Collector: Collector
ShipMonk\PHPStan\DeadCode\Rule\RuleTestCase: RuleTest
ShipMonk\PHPStan\DeadCode\Provider\ConstantUsageProvider: UsageProvider
ShipMonk\PHPStan\DeadCode\Provider\MethodUsageProvider: UsageProvider
ShipMonk\PHPStan\DeadCode\Provider\MemberUsageProvider: UsageProvider
enforceReadonlyPublicProperty:
enabled: false # we support even PHP 7.4

Expand Down
15 changes: 7 additions & 8 deletions rules.neon
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,42 @@ services:
-
class: ShipMonk\PHPStan\DeadCode\Provider\VendorUsageProvider
tags:
- shipmonk.deadCode.methodUsageProvider
- shipmonk.deadCode.memberUsageProvider
arguments:
enabled: %shipmonkDeadCode.usageProviders.vendor.enabled%

-
class: ShipMonk\PHPStan\DeadCode\Provider\PhpUnitUsageProvider
tags:
- shipmonk.deadCode.methodUsageProvider
- shipmonk.deadCode.memberUsageProvider
arguments:
enabled: %shipmonkDeadCode.usageProviders.phpunit.enabled%

-
class: ShipMonk\PHPStan\DeadCode\Provider\SymfonyUsageProvider
tags:
- shipmonk.deadCode.methodUsageProvider
- shipmonk.deadCode.memberUsageProvider
arguments:
enabled: %shipmonkDeadCode.usageProviders.symfony.enabled%

-
class: ShipMonk\PHPStan\DeadCode\Provider\DoctrineUsageProvider
tags:
- shipmonk.deadCode.methodUsageProvider
- shipmonk.deadCode.memberUsageProvider
arguments:
enabled: %shipmonkDeadCode.usageProviders.doctrine.enabled%

-
class: ShipMonk\PHPStan\DeadCode\Provider\PhpStanUsageProvider
tags:
- shipmonk.deadCode.methodUsageProvider
- shipmonk.deadCode.memberUsageProvider
arguments:
enabled: %shipmonkDeadCode.usageProviders.phpstan.enabled%

-
class: ShipMonk\PHPStan\DeadCode\Provider\NetteUsageProvider
tags:
- shipmonk.deadCode.methodUsageProvider
- shipmonk.deadCode.memberUsageProvider
arguments:
enabled: %shipmonkDeadCode.usageProviders.nette.enabled%

Expand Down Expand Up @@ -73,8 +73,7 @@ services:
tags:
- phpstan.collector
arguments:
methodUsageProviders: tagged(shipmonk.deadCode.methodUsageProvider)
constantUsageProviders: tagged(shipmonk.deadCode.constantUsageProvider)
memberUsageProviders: tagged(shipmonk.deadCode.memberUsageProvider)

-
class: ShipMonk\PHPStan\DeadCode\Rule\DeadCodeRule
Expand Down
43 changes: 43 additions & 0 deletions src/Collector/BufferedUsageCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php declare(strict_types = 1);

namespace ShipMonk\PHPStan\DeadCode\Collector;

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Node\ClassMethodsNode;
use ShipMonk\PHPStan\DeadCode\Graph\ClassMemberUsage;
use function array_map;

trait BufferedUsageCollector
{

/**
* @var list<ClassMemberUsage>
*/
private array $usageBuffer = [];

/**
* @return non-empty-list<string>|null
*/
private function tryFlushBuffer(
Node $node,
Scope $scope
): ?array
{
if (!$scope->isInClass() || $node instanceof ClassMethodsNode) { // @phpstan-ignore-line ignore BC promise
$data = $this->usageBuffer;
$this->usageBuffer = [];

// collect data once per class to save memory & resultCache size
return $data === []
? null
: array_map(
static fn (ClassMemberUsage $call): string => $call->serialize(),
$data,
);
}

return null;
}

}
25 changes: 4 additions & 21 deletions src/Collector/ConstantFetchCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use PhpParser\Node\Name;
use PHPStan\Analyser\Scope;
use PHPStan\Collectors\Collector;
use PHPStan\Node\ClassMethodsNode;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\Constant\ConstantStringType;
Expand All @@ -31,10 +30,7 @@
class ConstantFetchCollector implements Collector
{

/**
* @var list<ClassConstantUsage>
*/
private array $accessBuffer = [];
use BufferedUsageCollector;

private ReflectionProvider $reflectionProvider;

Expand Down Expand Up @@ -70,20 +66,7 @@ public function processNode(
$this->registerFunctionCall($node, $scope);
}

if (!$scope->isInClass() || $node instanceof ClassMethodsNode) { // @phpstan-ignore-line ignore BC promise
$data = $this->accessBuffer;
$this->accessBuffer = [];

// collect data once per class to save memory & resultCache size
return $data === []
? null
: array_map(
static fn (ClassConstantUsage $fetch): string => $fetch->serialize(),
$data,
);
}

return null;
return $this->tryFlushBuffer($node, $scope);
}

private function registerFunctionCall(FuncCall $node, Scope $scope): void
Expand Down Expand Up @@ -125,7 +108,7 @@ private function registerFunctionCall(FuncCall $node, Scope $scope): void
}
}

$this->accessBuffer[] = new ClassConstantUsage(
$this->usageBuffer[] = new ClassConstantUsage(
$this->getCaller($scope),
new ClassConstantRef($className, $constantName, true),
);
Expand All @@ -149,7 +132,7 @@ private function registerFetch(ClassConstFetch $node, Scope $scope): void

foreach ($constantNames as $constantName) {
foreach ($this->getDeclaringTypesWithConstant($ownerType, $constantName) as $className) {
$this->accessBuffer[] = new ClassConstantUsage(
$this->usageBuffer[] = new ClassConstantUsage(
$this->getCaller($scope),
new ClassConstantRef($className, $constantName, $possibleDescendantFetch),
);
Expand Down
32 changes: 7 additions & 25 deletions src/Collector/MethodCallCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use PhpParser\Node\Name;
use PHPStan\Analyser\Scope;
use PHPStan\Collectors\Collector;
use PHPStan\Node\ClassMethodsNode;
use PHPStan\Node\MethodCallableNode;
use PHPStan\Node\StaticMethodCallableNode;
use PHPStan\Reflection\MethodReflection;
Expand All @@ -25,18 +24,14 @@
use PHPStan\Type\TypeUtils;
use ShipMonk\PHPStan\DeadCode\Graph\ClassMethodRef;
use ShipMonk\PHPStan\DeadCode\Graph\ClassMethodUsage;
use function array_map;

/**
* @implements Collector<Node, list<string>>
*/
class MethodCallCollector implements Collector
{

/**
* @var list<ClassMethodUsage>
*/
private array $callsBuffer = [];
use BufferedUsageCollector;

private bool $trackMixedAccess;

Expand Down Expand Up @@ -86,20 +81,7 @@ public function processNode(
$this->registerAttribute($node, $scope);
}

if (!$scope->isInClass() || $node instanceof ClassMethodsNode) { // @phpstan-ignore-line ignore BC promise
$data = $this->callsBuffer;
$this->callsBuffer = [];

// collect data once per class to save memory & resultCache size
return $data === []
? null
: array_map(
static fn (ClassMethodUsage $call): string => $call->serialize(),
$data,
);
}

return null;
return $this->tryFlushBuffer($node, $scope);
}

/**
Expand Down Expand Up @@ -131,7 +113,7 @@ private function registerMethodCall(

foreach ($methodNames as $methodName) {
foreach ($this->getDeclaringTypesWithMethod($scope, $callerType, $methodName, TrinaryLogic::createNo()) as $className) {
$this->callsBuffer[] = new ClassMethodUsage(
$this->usageBuffer[] = new ClassMethodUsage(
$this->getCaller($scope),
new ClassMethodRef($className, $methodName, $possibleDescendantCall),
);
Expand All @@ -157,7 +139,7 @@ private function registerStaticCall(

foreach ($methodNames as $methodName) {
foreach ($this->getDeclaringTypesWithMethod($scope, $callerType, $methodName, TrinaryLogic::createYes()) as $className) {
$this->callsBuffer[] = new ClassMethodUsage(
$this->usageBuffer[] = new ClassMethodUsage(
$this->getCaller($scope),
new ClassMethodRef($className, $methodName, $possibleDescendantCall),
);
Expand All @@ -182,7 +164,7 @@ private function registerArrayCallable(
$possibleDescendantCall = !$caller->isClassString()->yes();

foreach ($this->getDeclaringTypesWithMethod($scope, $caller, $methodName, TrinaryLogic::createMaybe()) as $className) {
$this->callsBuffer[] = new ClassMethodUsage(
$this->usageBuffer[] = new ClassMethodUsage(
$this->getCaller($scope),
new ClassMethodRef($className, $methodName, $possibleDescendantCall),
);
Expand All @@ -194,7 +176,7 @@ private function registerArrayCallable(

private function registerAttribute(Attribute $node, Scope $scope): void
{
$this->callsBuffer[] = new ClassMethodUsage(
$this->usageBuffer[] = new ClassMethodUsage(
null,
new ClassMethodRef($scope->resolveName($node->name), '__construct', false),
);
Expand All @@ -206,7 +188,7 @@ private function registerClone(Clone_ $node, Scope $scope): void
$callerType = $scope->getType($node->expr);

foreach ($this->getDeclaringTypesWithMethod($scope, $callerType, $methodName, TrinaryLogic::createNo()) as $className) {
$this->callsBuffer[] = new ClassMethodUsage(
$this->usageBuffer[] = new ClassMethodUsage(
$this->getCaller($scope),
new ClassMethodRef($className, $methodName, true),
);
Expand Down
Loading

0 comments on commit 247098f

Please sign in to comment.