diff --git a/src/Type/Doctrine/QueryBuilder/OtherMethodQueryBuilderParser.php b/src/Type/Doctrine/QueryBuilder/OtherMethodQueryBuilderParser.php index afe3a595..4375c17a 100644 --- a/src/Type/Doctrine/QueryBuilder/OtherMethodQueryBuilderParser.php +++ b/src/Type/Doctrine/QueryBuilder/OtherMethodQueryBuilderParser.php @@ -21,6 +21,7 @@ use PHPStan\Type\Type; use PHPStan\Type\TypeTraverser; use PHPStan\Type\UnionType; +use function array_key_exists; use function is_array; use function sprintf; @@ -36,7 +37,11 @@ class OtherMethodQueryBuilderParser /** @var Container */ private $container; - /** @var array> */ + /** + * Null if the method is currently being processed + * + * @var array|null> + */ private $cache = []; public function __construct(bool $descendIntoOtherMethods, Parser $parser, Container $container) @@ -64,10 +69,16 @@ public function findQueryBuilderTypesInCalledMethod(Scope $scope, MethodReflecti $cacheKey = $this->buildCacheKey($fileName, $className, $methodName); - if (isset($this->cache[$cacheKey])) { + if (array_key_exists($cacheKey, $this->cache)) { + if ($this->cache[$cacheKey] === null) { + return []; // recursion + } + return $this->cache[$cacheKey]; } + $this->cache[$cacheKey] = null; + $nodes = $this->parser->parseFile($fileName); $classNode = $this->findClassNode($className, $nodes); if ($classNode === null) { diff --git a/tests/Type/Doctrine/data/QueryResult/queryBuilderExpressionTypeResolver.php b/tests/Type/Doctrine/data/QueryResult/queryBuilderExpressionTypeResolver.php index 9fe7bcd1..f6197db8 100644 --- a/tests/Type/Doctrine/data/QueryResult/queryBuilderExpressionTypeResolver.php +++ b/tests/Type/Doctrine/data/QueryResult/queryBuilderExpressionTypeResolver.php @@ -71,6 +71,21 @@ private function adjustQueryBuilderToIndexByInt(QueryBuilder $qb): void $qb->indexBy('m', 'm.intColumn'); } + private function getQueryBuilderRecursively(EntityManagerInterface $em): QueryBuilder + { + return $this->getQueryBuilderRecursively($em); + } + + private function getQueryBuilderRecursivelyInLoop(EntityManagerInterface $em): QueryBuilder + { + return $this->getQueryBuilderRecursivelyInLoop2($em); + } + + private function getQueryBuilderRecursivelyInLoop2(EntityManagerInterface $em): QueryBuilder + { + return $this->getQueryBuilderRecursivelyInLoop($em); + } + private function getQueryBuilder(EntityManagerInterface $em): QueryBuilder { return $em->createQueryBuilder()