diff --git a/README.md b/README.md index 2ad55ca..fa6afcf 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ includes: - `#[Required]` attribute - `#[Route]` attributes - `onKernelResponse`, `onKernelRequest`, etc +- class constants referenced in `containerXmlPath` via `!php/const:` #### Doctrine: - `#[AsEntityListener]` attribute @@ -72,24 +73,26 @@ parameters: ``` ## Customization: -- If your application does some magic calls unknown to this library, you can implement your own entrypoint provider. -- Just tag it with `shipmonk.deadCode.entrypointProvider` and implement `ShipMonk\PHPStan\DeadCode\Provider\MethodEntrypointProvider` -- You can simplify your implementation by extending `ShipMonk\PHPStan\DeadCode\Provider\SimpleMethodEntrypointProvider` +- If your application does some magic calls unknown to this library, you can implement your own usage provider. +- Just tag it with `shipmonk.deadCode.methodUsageProvider` and implement `ShipMonk\PHPStan\DeadCode\Provider\MethodUsageProvider` +- You can simplify your implementation by extending `ShipMonk\PHPStan\DeadCode\Provider\SimpleMethodUsageProvider` +- Similar classes and interfaces are also available for constant usages ```neon # phpstan.neon.dist services: - - class: App\ApiOutputEntrypointProvider + class: App\ApiOutputMethodUsageProvider tags: - - shipmonk.deadCode.entrypointProvider + - shipmonk.deadCode.methodUsageProvider ``` + ```php use ReflectionMethod; -use ShipMonk\PHPStan\DeadCode\Provider\SimpleMethodEntrypointProvider; +use ShipMonk\PHPStan\DeadCode\Provider\SimpleMethodUsageProvider; -class ApiOutputEntrypointProvider extends SimpleMethodEntrypointProvider +class ApiOutputMethodUsageProvider extends SimpleMethodUsageProvider { public function isEntrypointMethod(ReflectionMethod $method): bool diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 675fd59..6f50b76 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -41,7 +41,8 @@ parameters: PHPStan\Rules\Rule: Rule PHPStan\Collectors\Collector: Collector ShipMonk\PHPStan\DeadCode\Rule\RuleTestCase: RuleTest - ShipMonk\PHPStan\DeadCode\Provider\MethodEntrypointProvider: EntrypointProvider + ShipMonk\PHPStan\DeadCode\Provider\ConstantUsageProvider: UsageProvider + ShipMonk\PHPStan\DeadCode\Provider\MethodUsageProvider: UsageProvider enforceReadonlyPublicProperty: enabled: false # we support even PHP 7.4 diff --git a/rules.neon b/rules.neon index 57c1aa2..c4a7b9e 100644 --- a/rules.neon +++ b/rules.neon @@ -8,46 +8,46 @@ services: class: ShipMonk\PHPStan\DeadCode\Transformer\FileSystem - - class: ShipMonk\PHPStan\DeadCode\Provider\VendorEntrypointProvider + class: ShipMonk\PHPStan\DeadCode\Provider\VendorUsageProvider tags: - - shipmonk.deadCode.entrypointProvider + - shipmonk.deadCode.methodUsageProvider arguments: - enabled: %shipmonkDeadCode.entrypoints.vendor.enabled% + enabled: %shipmonkDeadCode.usageProviders.vendor.enabled% - - class: ShipMonk\PHPStan\DeadCode\Provider\PhpUnitEntrypointProvider + class: ShipMonk\PHPStan\DeadCode\Provider\PhpUnitUsageProvider tags: - - shipmonk.deadCode.entrypointProvider + - shipmonk.deadCode.methodUsageProvider arguments: - enabled: %shipmonkDeadCode.entrypoints.phpunit.enabled% + enabled: %shipmonkDeadCode.usageProviders.phpunit.enabled% - - class: ShipMonk\PHPStan\DeadCode\Provider\SymfonyEntrypointProvider + class: ShipMonk\PHPStan\DeadCode\Provider\SymfonyUsageProvider tags: - - shipmonk.deadCode.entrypointProvider + - shipmonk.deadCode.methodUsageProvider arguments: - enabled: %shipmonkDeadCode.entrypoints.symfony.enabled% + enabled: %shipmonkDeadCode.usageProviders.symfony.enabled% - - class: ShipMonk\PHPStan\DeadCode\Provider\DoctrineEntrypointProvider + class: ShipMonk\PHPStan\DeadCode\Provider\DoctrineUsageProvider tags: - - shipmonk.deadCode.entrypointProvider + - shipmonk.deadCode.methodUsageProvider arguments: - enabled: %shipmonkDeadCode.entrypoints.doctrine.enabled% + enabled: %shipmonkDeadCode.usageProviders.doctrine.enabled% - - class: ShipMonk\PHPStan\DeadCode\Provider\PhpStanEntrypointProvider + class: ShipMonk\PHPStan\DeadCode\Provider\PhpStanUsageProvider tags: - - shipmonk.deadCode.entrypointProvider + - shipmonk.deadCode.methodUsageProvider arguments: - enabled: %shipmonkDeadCode.entrypoints.phpstan.enabled% + enabled: %shipmonkDeadCode.usageProviders.phpstan.enabled% - - class: ShipMonk\PHPStan\DeadCode\Provider\NetteEntrypointProvider + class: ShipMonk\PHPStan\DeadCode\Provider\NetteUsageProvider tags: - - shipmonk.deadCode.entrypointProvider + - shipmonk.deadCode.methodUsageProvider arguments: - enabled: %shipmonkDeadCode.entrypoints.nette.enabled% + enabled: %shipmonkDeadCode.usageProviders.nette.enabled% - class: ShipMonk\PHPStan\DeadCode\Collector\MethodCallCollector @@ -69,11 +69,12 @@ services: - phpstan.collector - - class: ShipMonk\PHPStan\DeadCode\Collector\EntrypointCollector + class: ShipMonk\PHPStan\DeadCode\Collector\ProvidedUsagesCollector tags: - phpstan.collector arguments: - entrypointProviders: tagged(shipmonk.deadCode.entrypointProvider) + methodUsageProviders: tagged(shipmonk.deadCode.methodUsageProvider) + constantUsageProviders: tagged(shipmonk.deadCode.constantUsageProvider) - class: ShipMonk\PHPStan\DeadCode\Rule\DeadCodeRule @@ -89,7 +90,7 @@ parameters: shipmonkDeadCode: trackMixedAccess: true reportTransitivelyDeadMethodAsSeparateError: false - entrypoints: + usageProviders: vendor: enabled: true phpstan: @@ -107,7 +108,7 @@ parametersSchema: shipmonkDeadCode: structure([ trackMixedAccess: bool() reportTransitivelyDeadMethodAsSeparateError: bool() - entrypoints: structure([ + usageProviders: structure([ vendor: structure([ enabled: bool() ]) diff --git a/src/Collector/EntrypointCollector.php b/src/Collector/EntrypointCollector.php deleted file mode 100644 index 6f94587..0000000 --- a/src/Collector/EntrypointCollector.php +++ /dev/null @@ -1,67 +0,0 @@ -> - */ -class EntrypointCollector implements Collector -{ - - /** - * @var list - */ - private array $entrypointProviders; - - /** - * @param list $entrypointProviders - */ - public function __construct( - array $entrypointProviders - ) - { - $this->entrypointProviders = $entrypointProviders; - } - - public function getNodeType(): string - { - return InClassNode::class; - } - - /** - * @param InClassNode $node - * @return non-empty-list|null - */ - public function processNode( - Node $node, - Scope $scope - ): ?array - { - $entrypoints = []; - - foreach ($this->entrypointProviders as $entrypointProvider) { - foreach ($entrypointProvider->getEntrypoints($node->getClassReflection()) as $entrypointMethod) { - $call = new ClassMethodUsage( - null, - new ClassMethodRef( - $entrypointMethod->getDeclaringClass()->getName(), - $entrypointMethod->getName(), - false, - ), - ); - $entrypoints[] = $call->serialize(); - } - } - - return $entrypoints === [] ? null : $entrypoints; - } - -} diff --git a/src/Collector/ProvidedUsagesCollector.php b/src/Collector/ProvidedUsagesCollector.php new file mode 100644 index 0000000..e7b272d --- /dev/null +++ b/src/Collector/ProvidedUsagesCollector.php @@ -0,0 +1,92 @@ +> + */ +class ProvidedUsagesCollector implements Collector +{ + + /** + * @var list + */ + private array $methodUsageProviders; + + /** + * @var list + */ + private array $constantUsageProviders; + + /** + * @param list $methodUsageProviders + * @param list $constantUsageProviders + */ + public function __construct( + array $methodUsageProviders, + array $constantUsageProviders + ) + { + $this->methodUsageProviders = $methodUsageProviders; + $this->constantUsageProviders = $constantUsageProviders; + } + + public function getNodeType(): string + { + return InClassNode::class; + } + + /** + * @param InClassNode $node + * @return non-empty-list|null + */ + public function processNode( + Node $node, + Scope $scope + ): ?array + { + $usages = []; + + foreach ($this->methodUsageProviders as $methodUsageProvider) { + foreach ($methodUsageProvider->getMethodUsages($node->getClassReflection()) as $usedMethod) { + $methodUsage = new ClassMethodUsage( + null, + new ClassMethodRef( + $usedMethod->getDeclaringClass()->getName(), + $usedMethod->getName(), + false, + ), + ); + $usages[] = $methodUsage->serialize(); + } + } + + foreach ($this->constantUsageProviders as $constantUsageProvider) { + foreach ($constantUsageProvider->getConstantUsages($node->getClassReflection()) as $usedConstant) { + $constantUsage = new ClassConstantUsage( + null, + new ClassConstantRef( + $usedConstant->getDeclaringClass()->getName(), + $usedConstant->getName(), + false, + ), + ); + $usages[] = $constantUsage->serialize(); + } + } + + return $usages === [] ? null : $usages; + } + +} diff --git a/src/Provider/ConstantUsageProvider.php b/src/Provider/ConstantUsageProvider.php new file mode 100644 index 0000000..f196219 --- /dev/null +++ b/src/Provider/ConstantUsageProvider.php @@ -0,0 +1,27 @@ + + */ + public function getConstantUsages(ClassReflection $classReflection): array; + +} diff --git a/src/Provider/DoctrineEntrypointProvider.php b/src/Provider/DoctrineUsageProvider.php similarity index 96% rename from src/Provider/DoctrineEntrypointProvider.php rename to src/Provider/DoctrineUsageProvider.php index ac10e89..fba00fe 100644 --- a/src/Provider/DoctrineEntrypointProvider.php +++ b/src/Provider/DoctrineUsageProvider.php @@ -7,7 +7,7 @@ use ReflectionMethod; use const PHP_VERSION_ID; -class DoctrineEntrypointProvider extends SimpleMethodEntrypointProvider +class DoctrineUsageProvider extends SimpleMethodUsageProvider { private bool $enabled; @@ -17,7 +17,7 @@ public function __construct(?bool $enabled) $this->enabled = $enabled ?? $this->isDoctrineInstalled(); } - public function isEntrypointMethod(ReflectionMethod $method): bool + public function shouldMarkMethodAsUsed(ReflectionMethod $method): bool { if (!$this->enabled) { return false; diff --git a/src/Provider/MethodEntrypointProvider.php b/src/Provider/MethodUsageProvider.php similarity index 50% rename from src/Provider/MethodEntrypointProvider.php rename to src/Provider/MethodUsageProvider.php index b342c50..7441c70 100644 --- a/src/Provider/MethodEntrypointProvider.php +++ b/src/Provider/MethodUsageProvider.php @@ -6,22 +6,22 @@ use PHPStan\Reflection\MethodReflection; /** - * Extension point for marking methods as entrypoints (not dead) based on custom reflection logic. + * Extension point for marking methods as used based on custom reflection logic. * * Register in your phpstan.neon.dist: * * services: * - - * class: App\MyEntrypointProvider + * class: App\MyAppUsageProvider * tags: - * - shipmonk.deadCode.entrypointProvider + * - shipmonk.deadCode.methodUsageProvider */ -interface MethodEntrypointProvider +interface MethodUsageProvider { /** * @return list */ - public function getEntrypoints(ClassReflection $classReflection): array; + public function getMethodUsages(ClassReflection $classReflection): array; } diff --git a/src/Provider/NetteEntrypointProvider.php b/src/Provider/NetteUsageProvider.php similarity index 97% rename from src/Provider/NetteEntrypointProvider.php rename to src/Provider/NetteUsageProvider.php index 4fdd012..d3e21b3 100644 --- a/src/Provider/NetteEntrypointProvider.php +++ b/src/Provider/NetteUsageProvider.php @@ -19,7 +19,7 @@ use function ucfirst; use const PREG_SET_ORDER; -class NetteEntrypointProvider extends SimpleMethodEntrypointProvider +class NetteUsageProvider extends SimpleMethodUsageProvider { private ReflectionProvider $reflectionProvider; @@ -40,7 +40,7 @@ public function __construct( $this->enabled = $enabled ?? $this->isNetteInstalled(); } - public function isEntrypointMethod(ReflectionMethod $method): bool + public function shouldMarkMethodAsUsed(ReflectionMethod $method): bool { if (!$this->enabled) { return false; diff --git a/src/Provider/PhpStanEntrypointProvider.php b/src/Provider/PhpStanUsageProvider.php similarity index 84% rename from src/Provider/PhpStanEntrypointProvider.php rename to src/Provider/PhpStanUsageProvider.php index eb77b10..b95f5a3 100644 --- a/src/Provider/PhpStanEntrypointProvider.php +++ b/src/Provider/PhpStanUsageProvider.php @@ -5,7 +5,7 @@ use PHPStan\DependencyInjection\Container; use ReflectionMethod; -class PhpStanEntrypointProvider extends SimpleMethodEntrypointProvider +class PhpStanUsageProvider extends SimpleMethodUsageProvider { private bool $enabled; @@ -18,7 +18,7 @@ public function __construct(bool $enabled, Container $container) $this->container = $container; } - public function isEntrypointMethod(ReflectionMethod $method): bool + public function shouldMarkMethodAsUsed(ReflectionMethod $method): bool { if (!$this->enabled) { return false; diff --git a/src/Provider/PhpUnitEntrypointProvider.php b/src/Provider/PhpUnitUsageProvider.php similarity index 92% rename from src/Provider/PhpUnitEntrypointProvider.php rename to src/Provider/PhpUnitUsageProvider.php index d339e05..b43be6d 100644 --- a/src/Provider/PhpUnitEntrypointProvider.php +++ b/src/Provider/PhpUnitUsageProvider.php @@ -14,7 +14,7 @@ use function strpos; use const PHP_VERSION_ID; -class PhpUnitEntrypointProvider implements MethodEntrypointProvider +class PhpUnitUsageProvider implements MethodUsageProvider { private bool $enabled; @@ -30,7 +30,7 @@ public function __construct(?bool $enabled, PhpDocParser $phpDocParser, Lexer $l $this->phpDocParser = $phpDocParser; } - public function getEntrypoints(ClassReflection $classReflection): array + public function getMethodUsages(ClassReflection $classReflection): array { if (!$this->enabled) { return []; @@ -40,7 +40,7 @@ public function getEntrypoints(ClassReflection $classReflection): array return []; } - $entrypoints = []; + $usages = []; foreach ($classReflection->getNativeReflection()->getMethods() as $method) { $dataProviders = array_merge( @@ -50,16 +50,16 @@ public function getEntrypoints(ClassReflection $classReflection): array foreach ($dataProviders as $dataProvider) { if ($classReflection->hasNativeMethod($dataProvider)) { - $entrypoints[] = $classReflection->getNativeMethod($dataProvider); + $usages[] = $classReflection->getNativeMethod($dataProvider); } } if ($this->isTestCaseMethod($method)) { - $entrypoints[] = $classReflection->getNativeMethod($method->getName()); + $usages[] = $classReflection->getNativeMethod($method->getName()); } } - return $entrypoints; + return $usages; } private function isTestCaseMethod(ReflectionMethod $method): bool diff --git a/src/Provider/SimpleConstantUsageProvider.php b/src/Provider/SimpleConstantUsageProvider.php new file mode 100644 index 0000000..9855a38 --- /dev/null +++ b/src/Provider/SimpleConstantUsageProvider.php @@ -0,0 +1,32 @@ +getNativeReflection(); + + $usages = []; + + foreach ($nativeClassReflection->getReflectionConstants() as $nativeConstantReflection) { + if ($nativeConstantReflection->getDeclaringClass()->getName() !== $nativeClassReflection->getName()) { + continue; // skip constants from ancestors + } + + if ($this->shouldMarkConstantAsUsed($nativeConstantReflection)) { + $usages[] = $nativeConstantReflection; + } + } + + return $usages; + } + + abstract protected function shouldMarkConstantAsUsed(ReflectionClassConstant $constant): bool; + +} diff --git a/src/Provider/SimpleMethodEntrypointProvider.php b/src/Provider/SimpleMethodUsageProvider.php similarity index 53% rename from src/Provider/SimpleMethodEntrypointProvider.php rename to src/Provider/SimpleMethodUsageProvider.php index 39595cc..29f4d85 100644 --- a/src/Provider/SimpleMethodEntrypointProvider.php +++ b/src/Provider/SimpleMethodUsageProvider.php @@ -5,28 +5,28 @@ use PHPStan\Reflection\ClassReflection; use ReflectionMethod; -abstract class SimpleMethodEntrypointProvider implements MethodEntrypointProvider +abstract class SimpleMethodUsageProvider implements MethodUsageProvider { - public function getEntrypoints(ClassReflection $classReflection): array + public function getMethodUsages(ClassReflection $classReflection): array { $nativeClassReflection = $classReflection->getNativeReflection(); - $entrypoints = []; + $usages = []; foreach ($nativeClassReflection->getMethods() as $nativeMethodReflection) { if ($nativeMethodReflection->getDeclaringClass()->getName() !== $nativeClassReflection->getName()) { continue; // skip methods from ancestors } - if ($this->isEntrypointMethod($nativeMethodReflection)) { - $entrypoints[] = $classReflection->getNativeMethod($nativeMethodReflection->getName()); + if ($this->shouldMarkMethodAsUsed($nativeMethodReflection)) { + $usages[] = $classReflection->getNativeMethod($nativeMethodReflection->getName()); } } - return $entrypoints; + return $usages; } - abstract protected function isEntrypointMethod(ReflectionMethod $method): bool; + abstract protected function shouldMarkMethodAsUsed(ReflectionMethod $method): bool; } diff --git a/src/Provider/SymfonyEntrypointProvider.php b/src/Provider/SymfonyUsageProvider.php similarity index 82% rename from src/Provider/SymfonyEntrypointProvider.php rename to src/Provider/SymfonyUsageProvider.php index e328dd4..45459fb 100644 --- a/src/Provider/SymfonyEntrypointProvider.php +++ b/src/Provider/SymfonyUsageProvider.php @@ -12,7 +12,7 @@ use Reflector; use const PHP_VERSION_ID; -class SymfonyEntrypointProvider implements MethodEntrypointProvider +class SymfonyUsageProvider implements MethodUsageProvider { private bool $enabled; @@ -30,43 +30,48 @@ public function __construct( $this->enabled = $enabled ?? $this->isSymfonyInstalled(); if ($serviceMapFactory !== null) { - foreach ($serviceMapFactory->create()->getServices() as $service) { // @phpstan-ignore phpstanApi.method - $dicClass = $service->getClass(); + $this->fillDicClasses($serviceMapFactory); + } + } - if ($dicClass === null) { - continue; - } + private function fillDicClasses(ServiceMapFactory $serviceMapFactory): void + { + foreach ($serviceMapFactory->create()->getServices() as $service) { // @phpstan-ignore phpstanApi.method + $dicClass = $service->getClass(); - $this->dicClasses[$dicClass] = true; + if ($dicClass === null) { + continue; } + + $this->dicClasses[$dicClass] = true; } } - public function getEntrypoints(ClassReflection $classReflection): array + public function getMethodUsages(ClassReflection $classReflection): array { $nativeReflection = $classReflection->getNativeReflection(); $className = $classReflection->getName(); - $entrypoints = []; + $usages = []; foreach ($nativeReflection->getMethods() as $method) { if ($method->isConstructor() && isset($this->dicClasses[$className])) { - $entrypoints[] = $classReflection->getNativeMethod($method->getName()); + $usages[] = $classReflection->getNativeMethod($method->getName()); } if ($method->getDeclaringClass()->getName() !== $nativeReflection->getName()) { continue; } - if ($this->isEntrypointMethod($method)) { - $entrypoints[] = $classReflection->getNativeMethod($method->getName()); + if ($this->shouldMarkAsUsed($method)) { + $usages[] = $classReflection->getNativeMethod($method->getName()); } } - return $entrypoints; + return $usages; } - public function isEntrypointMethod(ReflectionMethod $method): bool + public function shouldMarkAsUsed(ReflectionMethod $method): bool { if (!$this->enabled) { return false; diff --git a/src/Provider/VendorEntrypointProvider.php b/src/Provider/VendorUsageProvider.php similarity index 94% rename from src/Provider/VendorEntrypointProvider.php rename to src/Provider/VendorUsageProvider.php index 519dd0a..96ac9dd 100644 --- a/src/Provider/VendorEntrypointProvider.php +++ b/src/Provider/VendorUsageProvider.php @@ -11,7 +11,7 @@ use function strpos; use function substr; -class VendorEntrypointProvider extends SimpleMethodEntrypointProvider +class VendorUsageProvider extends SimpleMethodUsageProvider { /** @@ -27,7 +27,7 @@ public function __construct(bool $enabled) $this->enabled = $enabled; } - public function isEntrypointMethod(ReflectionMethod $method): bool + public function shouldMarkMethodAsUsed(ReflectionMethod $method): bool { if (!$this->enabled) { return false; diff --git a/src/Rule/DeadCodeRule.php b/src/Rule/DeadCodeRule.php index 6d37159..32f1606 100644 --- a/src/Rule/DeadCodeRule.php +++ b/src/Rule/DeadCodeRule.php @@ -13,8 +13,8 @@ use PHPStan\Rules\RuleErrorBuilder; use ShipMonk\PHPStan\DeadCode\Collector\ClassDefinitionCollector; use ShipMonk\PHPStan\DeadCode\Collector\ConstantFetchCollector; -use ShipMonk\PHPStan\DeadCode\Collector\EntrypointCollector; use ShipMonk\PHPStan\DeadCode\Collector\MethodCallCollector; +use ShipMonk\PHPStan\DeadCode\Collector\ProvidedUsagesCollector; use ShipMonk\PHPStan\DeadCode\Enum\ClassLikeKind; use ShipMonk\PHPStan\DeadCode\Enum\Visibility; use ShipMonk\PHPStan\DeadCode\Error\BlackMember; @@ -145,11 +145,11 @@ public function processNode( $methodDeclarationData = $node->get(ClassDefinitionCollector::class); $methodCallData = $node->get(MethodCallCollector::class); $constFetchData = $node->get(ConstantFetchCollector::class); - $entrypointData = $node->get(EntrypointCollector::class); + $providedUsagesData = $node->get(ProvidedUsagesCollector::class); /** @var array>> $memberUseData */ - $memberUseData = array_merge_recursive($methodCallData, $entrypointData, $constFetchData); - unset($methodCallData, $entrypointData, $constFetchData); + $memberUseData = array_merge_recursive($methodCallData, $providedUsagesData, $constFetchData); + unset($methodCallData, $providedUsagesData, $constFetchData); foreach ($memberUseData as $usesPerFile) { foreach ($usesPerFile as $useStrings) { diff --git a/tests/AllServicesInConfigTest.php b/tests/AllServicesInConfigTest.php index d66c8c5..97888d7 100644 --- a/tests/AllServicesInConfigTest.php +++ b/tests/AllServicesInConfigTest.php @@ -16,8 +16,10 @@ use ShipMonk\PHPStan\DeadCode\Graph\ClassMemberUsage; use ShipMonk\PHPStan\DeadCode\Graph\ClassMethodRef; use ShipMonk\PHPStan\DeadCode\Graph\ClassMethodUsage; -use ShipMonk\PHPStan\DeadCode\Provider\MethodEntrypointProvider; -use ShipMonk\PHPStan\DeadCode\Provider\SimpleMethodEntrypointProvider; +use ShipMonk\PHPStan\DeadCode\Provider\ConstantUsageProvider; +use ShipMonk\PHPStan\DeadCode\Provider\MethodUsageProvider; +use ShipMonk\PHPStan\DeadCode\Provider\SimpleConstantUsageProvider; +use ShipMonk\PHPStan\DeadCode\Provider\SimpleMethodUsageProvider; use ShipMonk\PHPStan\DeadCode\Transformer\RemoveClassMemberVisitor; use ShipMonk\PHPStan\DeadCode\Transformer\RemoveDeadCodeTransformer; use function array_keys; @@ -59,8 +61,10 @@ public function test(): void ClassLikeKind::class, Visibility::class, BlackMember::class, - MethodEntrypointProvider::class, - SimpleMethodEntrypointProvider::class, + MethodUsageProvider::class, + ConstantUsageProvider::class, + SimpleMethodUsageProvider::class, + SimpleConstantUsageProvider::class, RemoveDeadCodeTransformer::class, RemoveClassMemberVisitor::class, ]; diff --git a/tests/Rule/DeadCodeRuleTest.php b/tests/Rule/DeadCodeRuleTest.php index 780e31f..edd3841 100644 --- a/tests/Rule/DeadCodeRuleTest.php +++ b/tests/Rule/DeadCodeRuleTest.php @@ -17,18 +17,19 @@ use ReflectionMethod; use ShipMonk\PHPStan\DeadCode\Collector\ClassDefinitionCollector; use ShipMonk\PHPStan\DeadCode\Collector\ConstantFetchCollector; -use ShipMonk\PHPStan\DeadCode\Collector\EntrypointCollector; use ShipMonk\PHPStan\DeadCode\Collector\MethodCallCollector; +use ShipMonk\PHPStan\DeadCode\Collector\ProvidedUsagesCollector; use ShipMonk\PHPStan\DeadCode\Formatter\RemoveDeadCodeFormatter; use ShipMonk\PHPStan\DeadCode\Hierarchy\ClassHierarchy; -use ShipMonk\PHPStan\DeadCode\Provider\DoctrineEntrypointProvider; -use ShipMonk\PHPStan\DeadCode\Provider\MethodEntrypointProvider; -use ShipMonk\PHPStan\DeadCode\Provider\NetteEntrypointProvider; -use ShipMonk\PHPStan\DeadCode\Provider\PhpStanEntrypointProvider; -use ShipMonk\PHPStan\DeadCode\Provider\PhpUnitEntrypointProvider; -use ShipMonk\PHPStan\DeadCode\Provider\SimpleMethodEntrypointProvider; -use ShipMonk\PHPStan\DeadCode\Provider\SymfonyEntrypointProvider; -use ShipMonk\PHPStan\DeadCode\Provider\VendorEntrypointProvider; +use ShipMonk\PHPStan\DeadCode\Provider\ConstantUsageProvider; +use ShipMonk\PHPStan\DeadCode\Provider\DoctrineUsageProvider; +use ShipMonk\PHPStan\DeadCode\Provider\MethodUsageProvider; +use ShipMonk\PHPStan\DeadCode\Provider\NetteUsageProvider; +use ShipMonk\PHPStan\DeadCode\Provider\PhpStanUsageProvider; +use ShipMonk\PHPStan\DeadCode\Provider\PhpUnitUsageProvider; +use ShipMonk\PHPStan\DeadCode\Provider\SimpleMethodUsageProvider; +use ShipMonk\PHPStan\DeadCode\Provider\SymfonyUsageProvider; +use ShipMonk\PHPStan\DeadCode\Provider\VendorUsageProvider; use ShipMonk\PHPStan\DeadCode\Transformer\FileSystem; use function file_get_contents; use function is_array; @@ -68,7 +69,7 @@ protected function getRule(): DeadCodeRule protected function getCollectors(): array { return [ - new EntrypointCollector($this->getEntrypointProviders()), + new ProvidedUsagesCollector($this->getMethodUsageProviders(), $this->getConstantUsageProviders()), new ClassDefinitionCollector(), new MethodCallCollector($this->trackMixedAccess), new ConstantFetchCollector(self::createReflectionProvider(), $this->trackMixedAccess), @@ -355,46 +356,66 @@ private function getTransformedFilePath(string $file): string } /** - * @return list + * @return list */ - private function getEntrypointProviders(): array + private function getMethodUsageProviders(): array { return [ - new class extends SimpleMethodEntrypointProvider + new class extends SimpleMethodUsageProvider { - public function isEntrypointMethod(ReflectionMethod $method): bool + public function shouldMarkMethodAsUsed(ReflectionMethod $method): bool { return $method->getDeclaringClass()->getName() === 'DeadEntrypoint\Entrypoint'; } }, - new VendorEntrypointProvider( + new VendorUsageProvider( true, ), - new PhpUnitEntrypointProvider( + new PhpUnitUsageProvider( true, self::getContainer()->getByType(PhpDocParser::class), self::getContainer()->getByType(Lexer::class), ), - new SymfonyEntrypointProvider( - $this->createServiceMapFactoryMock(), - true, - ), - new DoctrineEntrypointProvider( + new DoctrineUsageProvider( true, ), - new PhpStanEntrypointProvider( + new PhpStanUsageProvider( true, $this->createPhpStanContainerMock(), ), - new NetteEntrypointProvider( + new NetteUsageProvider( self::getContainer()->getByType(ReflectionProvider::class), true, ), + $this->createSymfonyUsageProvider(), ]; } + /** + * @return list + */ + private function getConstantUsageProviders(): array + { + return []; + } + + private function createSymfonyUsageProvider(): SymfonyUsageProvider + { + /** @var SymfonyUsageProvider|null $cache */ + static $cache = null; + + if ($cache === null) { + $cache = new SymfonyUsageProvider( + $this->createServiceMapFactoryMock(), + true, + ); + } + + return $cache; + } + private function createPhpStanContainerMock(): Container { $mock = $this->createMock(Container::class);