From 49f41ed0ef95e6ebe830a43643aa96021c83bed5 Mon Sep 17 00:00:00 2001 From: Jeroen Noten Date: Wed, 15 Dec 2021 17:16:31 +0100 Subject: [PATCH] Fix false positive about private service in service subscriber --- .../ContainerInterfacePrivateServiceRule.php | 16 +++++++++++++++- tests/Rules/Symfony/ExampleServiceSubscriber.php | 10 ++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php b/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php index ee4d5b05..4c9a6af1 100644 --- a/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php +++ b/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php @@ -8,7 +8,9 @@ use PHPStan\Rules\Rule; use PHPStan\ShouldNotHappenException; use PHPStan\Symfony\ServiceMap; +use PHPStan\TrinaryLogic; use PHPStan\Type\ObjectType; +use PHPStan\Type\Type; use function sprintf; /** @@ -53,7 +55,7 @@ public function processNode(Node $node, Scope $scope): array $isTestContainerType = (new ObjectType('Symfony\Bundle\FrameworkBundle\Test\TestContainer'))->isSuperTypeOf($argType); $isOldServiceSubscriber = (new ObjectType('Symfony\Component\DependencyInjection\ServiceSubscriberInterface'))->isSuperTypeOf($argType); - $isServiceSubscriber = (new ObjectType('Symfony\Contracts\Service\ServiceSubscriberInterface'))->isSuperTypeOf($argType); + $isServiceSubscriber = $this->isServiceSubscriber($argType, $scope); $isServiceLocator = (new ObjectType('Symfony\Component\DependencyInjection\ServiceLocator'))->isSuperTypeOf($argType); if ($isTestContainerType->yes() || $isOldServiceSubscriber->yes() || $isServiceSubscriber->yes() || $isServiceLocator->yes()) { return []; @@ -83,4 +85,16 @@ public function processNode(Node $node, Scope $scope): array return []; } + private function isServiceSubscriber(Type $containerType, Scope $scope): TrinaryLogic + { + $serviceSubscriberInterfaceType = new ObjectType('Symfony\Contracts\Service\ServiceSubscriberInterface'); + $isContainerServiceSubscriber = $serviceSubscriberInterfaceType->isSuperTypeOf($containerType); + $classReflection = $scope->getClassReflection(); + if ($classReflection === null) { + return $isContainerServiceSubscriber; + } + $containedClassType = new ObjectType($classReflection->getName()); + return $isContainerServiceSubscriber->or($serviceSubscriberInterfaceType->isSuperTypeOf($containedClassType)); + } + } diff --git a/tests/Rules/Symfony/ExampleServiceSubscriber.php b/tests/Rules/Symfony/ExampleServiceSubscriber.php index 9f5968df..3d7f294d 100644 --- a/tests/Rules/Symfony/ExampleServiceSubscriber.php +++ b/tests/Rules/Symfony/ExampleServiceSubscriber.php @@ -2,14 +2,24 @@ namespace PHPStan\Rules\Symfony; +use Psr\Container\ContainerInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface; final class ExampleServiceSubscriber implements ServiceSubscriberInterface { + /** @var ContainerInterface */ + private $locator; + + public function __construct(ContainerInterface $locator) + { + $this->locator = $locator; + } + public function privateService(): void { $this->get('private'); + $this->locator->get('private'); } public function containerParameter(): void