diff --git a/src/Handler/ContainerHandler.php b/src/Handler/ContainerHandler.php index cdc19d0..c22ae57 100644 --- a/src/Handler/ContainerHandler.php +++ b/src/Handler/ContainerHandler.php @@ -11,9 +11,11 @@ use Psalm\Plugin\EventHandler\AfterClassLikeVisitInterface; use Psalm\Plugin\EventHandler\AfterCodebasePopulatedInterface; use Psalm\Plugin\EventHandler\AfterMethodCallAnalysisInterface; +use Psalm\Plugin\EventHandler\BeforeAddIssueInterface; use Psalm\Plugin\EventHandler\Event\AfterClassLikeVisitEvent; use Psalm\Plugin\EventHandler\Event\AfterCodebasePopulatedEvent; use Psalm\Plugin\EventHandler\Event\AfterMethodCallAnalysisEvent; +use Psalm\Plugin\EventHandler\Event\BeforeAddIssueEvent; use Psalm\SymfonyPsalmPlugin\Issue\NamingConventionViolation; use Psalm\SymfonyPsalmPlugin\Issue\PrivateService; use Psalm\SymfonyPsalmPlugin\Issue\ServiceNotFound; @@ -22,7 +24,7 @@ use Psalm\Type\Union; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; -class ContainerHandler implements AfterMethodCallAnalysisInterface, AfterClassLikeVisitInterface, AfterCodebasePopulatedInterface +class ContainerHandler implements AfterMethodCallAnalysisInterface, AfterClassLikeVisitInterface, AfterCodebasePopulatedInterface, BeforeAddIssueInterface { private const GET_CLASSLIKES = [ 'Psr\Container\ContainerInterface', @@ -38,9 +40,18 @@ class ContainerHandler implements AfterMethodCallAnalysisInterface, AfterClassLi */ private static $containerMeta; + /** + * @var array collection of cower-cased class names that are present in the container + */ + private static array $containerClassNames = []; + public static function init(ContainerMeta $containerMeta): void { self::$containerMeta = $containerMeta; + + self::$containerClassNames = array_map(function (string $className): string { + return strtolower($className); + }, self::$containerMeta->getClassNames()); } public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $event): void @@ -173,17 +184,27 @@ public static function afterCodebasePopulated(AfterCodebasePopulatedEvent $event return; } - $containerClassNames = array_map(function (string $className): string { - return strtolower($className); - }, self::$containerMeta->getClassNames()); - foreach ($event->getCodebase()->classlike_storage_provider->getAll() as $name => $storage) { - if (in_array($name, $containerClassNames, true)) { + if (in_array($name, self::$containerClassNames, true)) { $storage->suppressed_issues[] = 'UnusedClass'; } } } + public static function beforeAddIssue(BeforeAddIssueEvent $event): ?bool + { + $data = $event->getIssue()->toIssueData('error'); + if ('PossiblyUnusedMethod' === $data->type + && '__construct' === $data->selected_text + && null !== $data->dupe_key + && in_array(preg_replace('/::__construct$/', '', $data->dupe_key), self::$containerClassNames, true)) { + // Don't report service constructors as PossiblyUnusedMethod + return false; + } + + return null; + } + public static function isContainerMethod(string $declaringMethodId, string $methodName): bool { return in_array(