From 216033b5a88c71acb7f0abc8074a4d1004551a48 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Tue, 20 Feb 2024 21:20:35 +0100 Subject: [PATCH] Add always used method extension --- conf/config.neon | 3 +++ .../DeadCode/UnusedPrivateMethodRule.php | 13 +++++++++ .../Methods/AlwaysUsedMethodExtension.php | 27 +++++++++++++++++++ .../AlwaysUsedMethodExtensionProvider.php | 15 +++++++++++ ...irectAlwaysUsedMethodExtensionProvider.php | 20 ++++++++++++++ .../LazyAlwaysUsedMethodExtensionProvider.php | 22 +++++++++++++++ .../DeadCode/UnusedPrivateMethodRuleTest.php | 21 ++++++++++++++- .../DeadCode/data/unused-private-method.php | 11 ++++++++ 8 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/Rules/Methods/AlwaysUsedMethodExtension.php create mode 100644 src/Rules/Methods/AlwaysUsedMethodExtensionProvider.php create mode 100644 src/Rules/Methods/DirectAlwaysUsedMethodExtensionProvider.php create mode 100644 src/Rules/Methods/LazyAlwaysUsedMethodExtensionProvider.php diff --git a/conf/config.neon b/conf/config.neon index 5799bb1169..29dbaf60f1 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -974,6 +974,9 @@ services: - class: PHPStan\Rules\Constants\LazyAlwaysUsedClassConstantsExtensionProvider + - + class: PHPStan\Rules\Methods\LazyAlwaysUsedMethodExtensionProvider + - class: PHPStan\Rules\PhpDoc\ConditionalReturnTypeRuleHelper diff --git a/src/Rules/DeadCode/UnusedPrivateMethodRule.php b/src/Rules/DeadCode/UnusedPrivateMethodRule.php index df805f3731..938778fe4d 100644 --- a/src/Rules/DeadCode/UnusedPrivateMethodRule.php +++ b/src/Rules/DeadCode/UnusedPrivateMethodRule.php @@ -7,6 +7,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\ClassMethodsNode; use PHPStan\Reflection\MethodReflection; +use PHPStan\Rules\Methods\AlwaysUsedMethodExtensionProvider; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\Constant\ConstantStringType; @@ -22,6 +23,10 @@ class UnusedPrivateMethodRule implements Rule { + public function __construct(private AlwaysUsedMethodExtensionProvider $extensionProvider) + { + } + public function getNodeType(): string { return ClassMethodsNode::class; @@ -54,6 +59,14 @@ public function processNode(Node $node, Scope $scope): array if (strtolower($methodName) === '__clone') { continue; } + + $methodReflection = $classType->getMethod($methodName, $scope); + foreach ($this->extensionProvider->getExtensions() as $extension) { + if ($extension->isAlwaysUsed($methodReflection)) { + continue 2; + } + } + $methods[strtolower($methodName)] = $method; } diff --git a/src/Rules/Methods/AlwaysUsedMethodExtension.php b/src/Rules/Methods/AlwaysUsedMethodExtension.php new file mode 100644 index 0000000000..cfccf5b972 --- /dev/null +++ b/src/Rules/Methods/AlwaysUsedMethodExtension.php @@ -0,0 +1,27 @@ +extensions; + } + +} diff --git a/src/Rules/Methods/LazyAlwaysUsedMethodExtensionProvider.php b/src/Rules/Methods/LazyAlwaysUsedMethodExtensionProvider.php new file mode 100644 index 0000000000..cbd397ee94 --- /dev/null +++ b/src/Rules/Methods/LazyAlwaysUsedMethodExtensionProvider.php @@ -0,0 +1,22 @@ +extensions ??= $this->container->getServicesByTag(static::EXTENSION_TAG); + } + +} diff --git a/tests/PHPStan/Rules/DeadCode/UnusedPrivateMethodRuleTest.php b/tests/PHPStan/Rules/DeadCode/UnusedPrivateMethodRuleTest.php index 83a1e8ef83..246237f97f 100644 --- a/tests/PHPStan/Rules/DeadCode/UnusedPrivateMethodRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/UnusedPrivateMethodRuleTest.php @@ -2,6 +2,9 @@ namespace PHPStan\Rules\DeadCode; +use PHPStan\Reflection\MethodReflection; +use PHPStan\Rules\Methods\AlwaysUsedMethodExtension; +use PHPStan\Rules\Methods\DirectAlwaysUsedMethodExtensionProvider; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; use const PHP_VERSION_ID; @@ -14,7 +17,19 @@ class UnusedPrivateMethodRuleTest extends RuleTestCase protected function getRule(): Rule { - return new UnusedPrivateMethodRule(); + return new UnusedPrivateMethodRule( + new DirectAlwaysUsedMethodExtensionProvider([ + new class() implements AlwaysUsedMethodExtension { + + public function isAlwaysUsed(MethodReflection $methodReflection): bool + { + return $methodReflection->getDeclaringClass()->is('UnusedPrivateMethod\IgnoredByExtension') + && $methodReflection->getName() === 'foo'; + } + + }, + ]), + ); } public function testRule(): void @@ -40,6 +55,10 @@ public function testRule(): void 'Method UnusedPrivateMethod\Lorem::doBaz() is unused.', 99, ], + [ + 'Method UnusedPrivateMethod\IgnoredByExtension::bar() is unused.', + 181, + ], ]); } diff --git a/tests/PHPStan/Rules/DeadCode/data/unused-private-method.php b/tests/PHPStan/Rules/DeadCode/data/unused-private-method.php index 3bdf538e6b..ce43e40a90 100644 --- a/tests/PHPStan/Rules/DeadCode/data/unused-private-method.php +++ b/tests/PHPStan/Rules/DeadCode/data/unused-private-method.php @@ -171,3 +171,14 @@ public function doTest(): void } } + +class IgnoredByExtension +{ + private function foo(): void + { + } + + private function bar(): void + { + } +}