Skip to content

Commit fe80263

Browse files
authored
Find all constant/method types per class at once
1 parent 7472801 commit fe80263

File tree

3 files changed

+54
-53
lines changed

3 files changed

+54
-53
lines changed

src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ final class CachingVisitor extends NodeVisitorAbstract
2020

2121
private string $contents;
2222

23-
/** @var array<string, array<FetchedNode<Node\Stmt\ClassLike>>> */
23+
/** @var array<string, list<FetchedNode<Node\Stmt\ClassLike>>> */
2424
private array $classNodes;
2525

26-
/** @var array<string, array<FetchedNode<Node\Stmt\Function_>>> */
26+
/** @var array<string, list<FetchedNode<Node\Stmt\Function_>>> */
2727
private array $functionNodes;
2828

29-
/** @var array<string, array<FetchedNode<Node\Stmt\Const_|Node\Expr\FuncCall>>> */
29+
/** @var array<string, list<FetchedNode<Node\Stmt\Const_|Node\Expr\FuncCall>>> */
3030
private array $constantNodes;
3131

3232
private ?Node\Stmt\Namespace_ $currentNamespaceNode = null;
@@ -124,23 +124,23 @@ public function leaveNode(Node $node)
124124
}
125125

126126
/**
127-
* @return array<string, array<FetchedNode<Node\Stmt\ClassLike>>>
127+
* @return array<string, list<FetchedNode<Node\Stmt\ClassLike>>>
128128
*/
129129
public function getClassNodes(): array
130130
{
131131
return $this->classNodes;
132132
}
133133

134134
/**
135-
* @return array<string, array<FetchedNode<Node\Stmt\Function_>>>
135+
* @return array<string, list<FetchedNode<Node\Stmt\Function_>>>
136136
*/
137137
public function getFunctionNodes(): array
138138
{
139139
return $this->functionNodes;
140140
}
141141

142142
/**
143-
* @return array<string, array<FetchedNode<Node\Stmt\Const_|Node\Expr\FuncCall>>>
143+
* @return array<string, list<FetchedNode<Node\Stmt\Const_|Node\Expr\FuncCall>>>
144144
*/
145145
public function getConstantNodes(): array
146146
{

src/Reflection/BetterReflection/SourceLocator/FetchedNodesResult.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ final class FetchedNodesResult
88
{
99

1010
/**
11-
* @param array<string, array<FetchedNode<Node\Stmt\ClassLike>>> $classNodes
12-
* @param array<string, array<FetchedNode<Node\Stmt\Function_>>> $functionNodes
13-
* @param array<string, array<FetchedNode<Node\Stmt\Const_|Node\Expr\FuncCall>>> $constantNodes
11+
* @param array<string, list<FetchedNode<Node\Stmt\ClassLike>>> $classNodes
12+
* @param array<string, list<FetchedNode<Node\Stmt\Function_>>> $functionNodes
13+
* @param array<string, list<FetchedNode<Node\Stmt\Const_|Node\Expr\FuncCall>>> $constantNodes
1414
*/
1515
public function __construct(
1616
private array $classNodes,
@@ -21,23 +21,23 @@ public function __construct(
2121
}
2222

2323
/**
24-
* @return array<string, array<FetchedNode<Node\Stmt\ClassLike>>>
24+
* @return array<string, list<FetchedNode<Node\Stmt\ClassLike>>>
2525
*/
2626
public function getClassNodes(): array
2727
{
2828
return $this->classNodes;
2929
}
3030

3131
/**
32-
* @return array<string, array<FetchedNode<Node\Stmt\Function_>>>
32+
* @return array<string, list<FetchedNode<Node\Stmt\Function_>>>
3333
*/
3434
public function getFunctionNodes(): array
3535
{
3636
return $this->functionNodes;
3737
}
3838

3939
/**
40-
* @return array<string, array<FetchedNode<Node\Stmt\Const_|Node\Expr\FuncCall>>>
40+
* @return array<string, list<FetchedNode<Node\Stmt\Const_|Node\Expr\FuncCall>>>
4141
*/
4242
public function getConstantNodes(): array
4343
{

src/Reflection/SignatureMap/Php8SignatureMapProvider.php

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ final class Php8SignatureMapProvider implements SignatureMapProvider
4141

4242
private const DIRECTORY = __DIR__ . '/../../../vendor/phpstan/php-8-stubs';
4343

44-
/** @var array<string, array<string, array{ClassMethod, string}>> */
44+
/** @var array<lowercase-string, array<lowercase-string, array{ClassMethod, string}>> */
4545
private array $methodNodes = [];
4646

47-
/** @var array<string, array<string, Type|null>> */
47+
/** @var array<lowercase-string, array<lowercase-string, Type|null>> */
4848
private array $constantTypes = [];
4949

5050
private Php8StubsMap $map;
@@ -82,10 +82,26 @@ private function findMethodNode(string $className, string $methodName): ?array
8282
{
8383
$lowerClassName = strtolower($className);
8484
$lowerMethodName = strtolower($methodName);
85+
86+
$this->findClassStubs($className);
8587
if (isset($this->methodNodes[$lowerClassName][$lowerMethodName])) {
8688
return $this->methodNodes[$lowerClassName][$lowerMethodName];
8789
}
8890

91+
return null;
92+
}
93+
94+
private function findClassStubs(string $className): void
95+
{
96+
$lowerClassName = strtolower($className);
97+
98+
if (
99+
isset($this->methodNodes[$lowerClassName])
100+
|| isset($this->constantTypes[$lowerClassName])
101+
) {
102+
return;
103+
}
104+
89105
$stubFile = self::DIRECTORY . '/' . $this->map->classes[$lowerClassName];
90106
$nodes = $this->fileNodesFetcher->fetchNodes($stubFile);
91107
$classes = $nodes->getClassNodes();
@@ -98,20 +114,37 @@ private function findMethodNode(string $className, string $methodName): ?array
98114
throw new ShouldNotHappenException(sprintf('Class %s stub not found in %s.', $className, $stubFile));
99115
}
100116

117+
$this->methodNodes[$lowerClassName] = [];
118+
$this->constantTypes[$lowerClassName] = [];
119+
120+
// find and remember all methods/constants within the stubFile
101121
foreach ($class[0]->getNode()->stmts as $stmt) {
102-
if (!$stmt instanceof ClassMethod) {
122+
if ($stmt instanceof ClassMethod) {
123+
if (!$this->isForCurrentVersion($stmt->attrGroups)) {
124+
continue;
125+
}
126+
127+
$this->methodNodes[$lowerClassName][$stmt->name->toLowerString()] = [$stmt, $stubFile];
128+
103129
continue;
104130
}
105131

106-
if ($stmt->name->toLowerString() === $lowerMethodName) {
132+
if (!$stmt instanceof ClassConst) {
133+
continue;
134+
}
135+
136+
foreach ($stmt->consts as $const) {
137+
if ($stmt->type === null) {
138+
continue;
139+
}
140+
107141
if (!$this->isForCurrentVersion($stmt->attrGroups)) {
108142
continue;
109143
}
110-
return $this->methodNodes[$lowerClassName][$lowerMethodName] = [$stmt, $stubFile];
144+
145+
$this->constantTypes[$lowerClassName][$const->name->toLowerString()] = ParserNodeTypeToPHPStanType::resolve($stmt->type, null);
111146
}
112147
}
113-
114-
return null;
115148
}
116149

117150
/**
@@ -481,44 +514,12 @@ private function findConstantType(string $className, string $constantName): ?Typ
481514
{
482515
$lowerClassName = strtolower($className);
483516
$lowerConstantName = strtolower($constantName);
517+
518+
$this->findClassStubs($className);
484519
if (isset($this->constantTypes[$lowerClassName][$lowerConstantName])) {
485520
return $this->constantTypes[$lowerClassName][$lowerConstantName];
486521
}
487522

488-
$stubFile = self::DIRECTORY . '/' . $this->map->classes[$lowerClassName];
489-
$nodes = $this->fileNodesFetcher->fetchNodes($stubFile);
490-
$classes = $nodes->getClassNodes();
491-
if (count($classes) !== 1) {
492-
throw new ShouldNotHappenException(sprintf('Class %s stub not found in %s.', $className, $stubFile));
493-
}
494-
495-
$class = $classes[$lowerClassName];
496-
if (count($class) !== 1) {
497-
throw new ShouldNotHappenException(sprintf('Class %s stub not found in %s.', $className, $stubFile));
498-
}
499-
500-
foreach ($class[0]->getNode()->stmts as $stmt) {
501-
if (!$stmt instanceof ClassConst) {
502-
continue;
503-
}
504-
505-
foreach ($stmt->consts as $const) {
506-
if ($const->name->toString() !== $constantName) {
507-
continue;
508-
}
509-
510-
if (!$this->isForCurrentVersion($stmt->attrGroups)) {
511-
continue;
512-
}
513-
514-
if ($stmt->type === null) {
515-
return null;
516-
}
517-
518-
return $this->constantTypes[$lowerClassName][$lowerConstantName] = ParserNodeTypeToPHPStanType::resolve($stmt->type, null);
519-
}
520-
}
521-
522523
return null;
523524
}
524525

0 commit comments

Comments
 (0)