diff --git a/src/Handler/DoctrineRepositoryHandler.php b/src/Handler/DoctrineRepositoryHandler.php index f5967157..0569c4ed 100644 --- a/src/Handler/DoctrineRepositoryHandler.php +++ b/src/Handler/DoctrineRepositoryHandler.php @@ -17,6 +17,8 @@ use Psalm\SymfonyPsalmPlugin\Issue\RepositoryStringShortcut; use Psalm\Type\Atomic\TNamedObject; use Psalm\Type\Union; +use ReflectionClass; +use ReflectionException; class DoctrineRepositoryHandler implements AfterMethodCallAnalysisInterface, AfterClassLikeVisitInterface { @@ -41,13 +43,17 @@ public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $eve $statements_source->getSuppressedIssues() ); } elseif ($entityName instanceof Expr\ClassConstFetch) { - /** @psalm-var class-string $className */ + /** @psalm-var class-string|null $className */ $className = $entityName->class->getAttribute('resolvedName'); + if (null === $className) { + return; + } + try { - $reflectionClass = new \ReflectionClass($className); + $reflectionClass = new ReflectionClass($className); - if (method_exists(\ReflectionClass::class, 'getAttributes')) { + if (\PHP_VERSION_ID >= 80000 && method_exists(ReflectionClass::class, 'getAttributes')) { $entityAttributes = $reflectionClass->getAttributes(EntityAnnotation::class); foreach ($entityAttributes as $entityAttribute) { @@ -70,7 +76,7 @@ public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $eve $event->setReturnTypeCandidate(new Union([new TNamedObject($entityAnnotation->repositoryClass)])); } } - } catch (\ReflectionException $e) { + } catch (ReflectionException $e) { } } } diff --git a/tests/acceptance/acceptance/DoctrineQueryBuilder.feature b/tests/acceptance/acceptance/doctrine/DoctrineQueryBuilder.feature similarity index 100% rename from tests/acceptance/acceptance/DoctrineQueryBuilder.feature rename to tests/acceptance/acceptance/doctrine/DoctrineQueryBuilder.feature diff --git a/tests/acceptance/acceptance/doctrine/RepositoryClass.feature b/tests/acceptance/acceptance/doctrine/RepositoryClass.feature new file mode 100644 index 00000000..0399d408 --- /dev/null +++ b/tests/acceptance/acceptance/doctrine/RepositoryClass.feature @@ -0,0 +1,53 @@ +@symfony-common +Feature: RepositoryClass + + Background: + Given I have issue handlers "UndefinedClass,UnusedVariable" suppressed + And I have Symfony plugin enabled + And I have the following code preamble + """ + getRepository(Foo::class); + } + } + """ + When I run Psalm + Then I see these errors + | Type | Message | + | Trace | $repository: Psalm\SymfonyPsalmPlugin\Tests\Fixture\Doctrine\FooRepository | + And I see no other errors + + Scenario: Passing variable class does not crash the plugin + Given I have the following code + """ + class SomeService + { + public function __construct(EntityManagerInterface $entityManager) + { + $entity = 'Psalm\SymfonyPsalmPlugin\Tests\Fixture\Doctrine\Foo'; + /** @psalm-trace $repository */ + $repository = $entityManager->getRepository($entity::class); + } + } + """ + When I run Psalm + Then I see these errors + | Type | Message | + | Trace | $repository: Doctrine\ORM\EntityRepository | + | MixedArgument | Argument 1 of Doctrine\ORM\EntityManagerInterface::getRepository cannot be mixed, expecting class-string | + And I see no other errors diff --git a/tests/acceptance/acceptance/RepositoryStringShortcut.feature b/tests/acceptance/acceptance/doctrine/RepositoryStringShortcut.feature similarity index 75% rename from tests/acceptance/acceptance/RepositoryStringShortcut.feature rename to tests/acceptance/acceptance/doctrine/RepositoryStringShortcut.feature index 79f58721..06403498 100644 --- a/tests/acceptance/acceptance/RepositoryStringShortcut.feature +++ b/tests/acceptance/acceptance/doctrine/RepositoryStringShortcut.feature @@ -5,27 +5,21 @@ Feature: RepositoryStringShortcut I need Psalm to check preferred repository syntax Background: - Given I have issue handlers "UndefinedClass,UnusedVariable" suppressed + Given I have issue handlers "ArgumentTypeCoercion,MixedArgument,UndefinedClass" suppressed And I have Symfony plugin enabled And I have the following code preamble """ getRepository(Entity::class); + $entityManager->getRepository(Foo::class); } } """ @@ -61,7 +55,7 @@ Feature: RepositoryStringShortcut { public function __construct(EntityManagerInterface $entityManager) { - $className = 'App\Entity\EntityA'; + $className = Foo::class; $entityManager->getRepository($className); } } diff --git a/tests/fixture/Doctrine/Foo.php b/tests/fixture/Doctrine/Foo.php new file mode 100644 index 00000000..3a6c8a1f --- /dev/null +++ b/tests/fixture/Doctrine/Foo.php @@ -0,0 +1,14 @@ +