diff --git a/src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php b/src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php index 11abc81813..27bfb04022 100644 --- a/src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php +++ b/src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php @@ -20,13 +20,13 @@ final class CachingVisitor extends NodeVisitorAbstract private string $contents; - /** @var array>> */ + /** @var array>> */ private array $classNodes; - /** @var array>> */ + /** @var array>> */ private array $functionNodes; - /** @var array>> */ + /** @var array>> */ private array $constantNodes; private ?Node\Stmt\Namespace_ $currentNamespaceNode = null; @@ -124,7 +124,7 @@ public function leaveNode(Node $node) } /** - * @return array>> + * @return array>> */ public function getClassNodes(): array { @@ -132,7 +132,7 @@ public function getClassNodes(): array } /** - * @return array>> + * @return array>> */ public function getFunctionNodes(): array { @@ -140,7 +140,7 @@ public function getFunctionNodes(): array } /** - * @return array>> + * @return array>> */ public function getConstantNodes(): array { diff --git a/src/Reflection/BetterReflection/SourceLocator/FetchedNodesResult.php b/src/Reflection/BetterReflection/SourceLocator/FetchedNodesResult.php index ac90178d49..9061e3845a 100644 --- a/src/Reflection/BetterReflection/SourceLocator/FetchedNodesResult.php +++ b/src/Reflection/BetterReflection/SourceLocator/FetchedNodesResult.php @@ -8,9 +8,9 @@ final class FetchedNodesResult { /** - * @param array>> $classNodes - * @param array>> $functionNodes - * @param array>> $constantNodes + * @param array>> $classNodes + * @param array>> $functionNodes + * @param array>> $constantNodes */ public function __construct( private array $classNodes, @@ -21,7 +21,7 @@ public function __construct( } /** - * @return array>> + * @return array>> */ public function getClassNodes(): array { @@ -29,7 +29,7 @@ public function getClassNodes(): array } /** - * @return array>> + * @return array>> */ public function getFunctionNodes(): array { @@ -37,7 +37,7 @@ public function getFunctionNodes(): array } /** - * @return array>> + * @return array>> */ public function getConstantNodes(): array { diff --git a/src/Reflection/SignatureMap/Php8SignatureMapProvider.php b/src/Reflection/SignatureMap/Php8SignatureMapProvider.php index 61b1553782..19884d7037 100644 --- a/src/Reflection/SignatureMap/Php8SignatureMapProvider.php +++ b/src/Reflection/SignatureMap/Php8SignatureMapProvider.php @@ -41,10 +41,10 @@ final class Php8SignatureMapProvider implements SignatureMapProvider private const DIRECTORY = __DIR__ . '/../../../vendor/phpstan/php-8-stubs'; - /** @var array> */ + /** @var array> */ private array $methodNodes = []; - /** @var array> */ + /** @var array> */ private array $constantTypes = []; private Php8StubsMap $map; @@ -82,10 +82,26 @@ private function findMethodNode(string $className, string $methodName): ?array { $lowerClassName = strtolower($className); $lowerMethodName = strtolower($methodName); + + $this->findClassStubs($className); if (isset($this->methodNodes[$lowerClassName][$lowerMethodName])) { return $this->methodNodes[$lowerClassName][$lowerMethodName]; } + return null; + } + + private function findClassStubs(string $className): void + { + $lowerClassName = strtolower($className); + + if ( + isset($this->methodNodes[$lowerClassName]) + || isset($this->constantTypes[$lowerClassName]) + ) { + return; + } + $stubFile = self::DIRECTORY . '/' . $this->map->classes[$lowerClassName]; $nodes = $this->fileNodesFetcher->fetchNodes($stubFile); $classes = $nodes->getClassNodes(); @@ -98,20 +114,37 @@ private function findMethodNode(string $className, string $methodName): ?array throw new ShouldNotHappenException(sprintf('Class %s stub not found in %s.', $className, $stubFile)); } + $this->methodNodes[$lowerClassName] = []; + $this->constantTypes[$lowerClassName] = []; + + // find and remember all methods/constants within the stubFile foreach ($class[0]->getNode()->stmts as $stmt) { - if (!$stmt instanceof ClassMethod) { + if ($stmt instanceof ClassMethod) { + if (!$this->isForCurrentVersion($stmt->attrGroups)) { + continue; + } + + $this->methodNodes[$lowerClassName][$stmt->name->toLowerString()] = [$stmt, $stubFile]; + continue; } - if ($stmt->name->toLowerString() === $lowerMethodName) { + if (!$stmt instanceof ClassConst) { + continue; + } + + foreach ($stmt->consts as $const) { + if ($stmt->type === null) { + continue; + } + if (!$this->isForCurrentVersion($stmt->attrGroups)) { continue; } - return $this->methodNodes[$lowerClassName][$lowerMethodName] = [$stmt, $stubFile]; + + $this->constantTypes[$lowerClassName][$const->name->toLowerString()] = ParserNodeTypeToPHPStanType::resolve($stmt->type, null); } } - - return null; } /** @@ -481,44 +514,12 @@ private function findConstantType(string $className, string $constantName): ?Typ { $lowerClassName = strtolower($className); $lowerConstantName = strtolower($constantName); + + $this->findClassStubs($className); if (isset($this->constantTypes[$lowerClassName][$lowerConstantName])) { return $this->constantTypes[$lowerClassName][$lowerConstantName]; } - $stubFile = self::DIRECTORY . '/' . $this->map->classes[$lowerClassName]; - $nodes = $this->fileNodesFetcher->fetchNodes($stubFile); - $classes = $nodes->getClassNodes(); - if (count($classes) !== 1) { - throw new ShouldNotHappenException(sprintf('Class %s stub not found in %s.', $className, $stubFile)); - } - - $class = $classes[$lowerClassName]; - if (count($class) !== 1) { - throw new ShouldNotHappenException(sprintf('Class %s stub not found in %s.', $className, $stubFile)); - } - - foreach ($class[0]->getNode()->stmts as $stmt) { - if (!$stmt instanceof ClassConst) { - continue; - } - - foreach ($stmt->consts as $const) { - if ($const->name->toString() !== $constantName) { - continue; - } - - if (!$this->isForCurrentVersion($stmt->attrGroups)) { - continue; - } - - if ($stmt->type === null) { - return null; - } - - return $this->constantTypes[$lowerClassName][$lowerConstantName] = ParserNodeTypeToPHPStanType::resolve($stmt->type, null); - } - } - return null; }