Skip to content

Commit 6bdc25a

Browse files
committed
Fix Rector
1 parent cfe3b1f commit 6bdc25a

File tree

5 files changed

+385
-12
lines changed

5 files changed

+385
-12
lines changed

phpstan-baseline.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,11 @@ parameters:
305305
count: 1
306306
path: src/Reflection/BetterReflection/SourceLocator/FileReadTrapStreamWrapper.php
307307

308+
-
309+
message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\ClassLike\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_ given\\.$#"
310+
count: 1
311+
path: src/Reflection/BetterReflection/SourceLocator/NewOptimizedDirectorySourceLocator.php
312+
308313
-
309314
message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\ClassLike\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_ given\\.$#"
310315
count: 1
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Reflection\BetterReflection\SourceLocator;
4+
5+
use PhpParser\Node;
6+
use PHPStan\BetterReflection\Identifier\Identifier;
7+
use PHPStan\BetterReflection\Identifier\IdentifierType;
8+
use PHPStan\BetterReflection\Reflection\Reflection;
9+
use PHPStan\BetterReflection\Reflector\Reflector;
10+
use PHPStan\BetterReflection\SourceLocator\Ast\Strategy\NodeToReflection;
11+
use PHPStan\BetterReflection\SourceLocator\Type\SourceLocator;
12+
use PHPStan\Reflection\ConstantNameHelper;
13+
use PHPStan\ShouldNotHappenException;
14+
use function array_key_exists;
15+
use function array_values;
16+
use function current;
17+
use function strtolower;
18+
19+
class NewOptimizedDirectorySourceLocator implements SourceLocator
20+
{
21+
22+
/**
23+
* @param array<string, string> $classToFile
24+
* @param array<string, array<int, string>> $functionToFiles
25+
* @param array<string, string> $constantToFile
26+
*/
27+
public function __construct(
28+
private FileNodesFetcher $fileNodesFetcher,
29+
private array $classToFile,
30+
private array $functionToFiles,
31+
private array $constantToFile,
32+
)
33+
{
34+
}
35+
36+
public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection
37+
{
38+
if ($identifier->isClass()) {
39+
$className = strtolower($identifier->getName());
40+
$file = $this->findFileByClass($className);
41+
if ($file === null) {
42+
return null;
43+
}
44+
45+
$fetchedClassNodes = $this->fileNodesFetcher->fetchNodes($file)->getClassNodes();
46+
47+
if (!array_key_exists($className, $fetchedClassNodes)) {
48+
return null;
49+
}
50+
51+
/** @var FetchedNode<Node\Stmt\ClassLike> $fetchedClassNode */
52+
$fetchedClassNode = current($fetchedClassNodes[$className]);
53+
54+
return $this->nodeToReflection($reflector, $fetchedClassNode);
55+
}
56+
57+
if ($identifier->isFunction()) {
58+
$functionName = strtolower($identifier->getName());
59+
$files = $this->findFilesByFunction($functionName);
60+
61+
$fetchedFunctionNode = null;
62+
foreach ($files as $file) {
63+
$fetchedFunctionNodes = $this->fileNodesFetcher->fetchNodes($file)->getFunctionNodes();
64+
65+
if (!array_key_exists($functionName, $fetchedFunctionNodes)) {
66+
continue;
67+
}
68+
69+
/** @var FetchedNode<Node\Stmt\Function_> $fetchedFunctionNode */
70+
$fetchedFunctionNode = current($fetchedFunctionNodes[$functionName]);
71+
}
72+
73+
if ($fetchedFunctionNode === null) {
74+
return null;
75+
}
76+
77+
return $this->nodeToReflection($reflector, $fetchedFunctionNode);
78+
}
79+
80+
if ($identifier->isConstant()) {
81+
$constantName = ConstantNameHelper::normalize($identifier->getName());
82+
$file = $this->findFileByConstant($constantName);
83+
84+
if ($file === null) {
85+
return null;
86+
}
87+
88+
$fetchedConstantNodes = $this->fileNodesFetcher->fetchNodes($file)->getConstantNodes();
89+
90+
if (!array_key_exists($constantName, $fetchedConstantNodes)) {
91+
return null;
92+
}
93+
94+
/** @var FetchedNode<Node\Stmt\Const_|Node\Expr\FuncCall> $fetchedConstantNode */
95+
$fetchedConstantNode = current($fetchedConstantNodes[$constantName]);
96+
97+
return $this->nodeToReflection(
98+
$reflector,
99+
$fetchedConstantNode,
100+
$this->findConstantPositionInConstNode($fetchedConstantNode->getNode(), $constantName),
101+
);
102+
}
103+
104+
return null;
105+
}
106+
107+
/**
108+
* @param FetchedNode<Node\Stmt\ClassLike>|FetchedNode<Node\Stmt\Function_>|FetchedNode<Node\Stmt\Const_|Node\Expr\FuncCall> $fetchedNode
109+
*/
110+
private function nodeToReflection(Reflector $reflector, FetchedNode $fetchedNode, ?int $positionInNode = null): Reflection
111+
{
112+
$nodeToReflection = new NodeToReflection();
113+
return $nodeToReflection->__invoke(
114+
$reflector,
115+
$fetchedNode->getNode(),
116+
$fetchedNode->getLocatedSource(),
117+
$fetchedNode->getNamespace(),
118+
$positionInNode,
119+
);
120+
}
121+
122+
private function findFileByClass(string $className): ?string
123+
{
124+
if (!array_key_exists($className, $this->classToFile)) {
125+
return null;
126+
}
127+
128+
return $this->classToFile[$className];
129+
}
130+
131+
private function findFileByConstant(string $constantName): ?string
132+
{
133+
if (!array_key_exists($constantName, $this->constantToFile)) {
134+
return null;
135+
}
136+
137+
return $this->constantToFile[$constantName];
138+
}
139+
140+
/**
141+
* @return string[]
142+
*/
143+
private function findFilesByFunction(string $functionName): array
144+
{
145+
if (!array_key_exists($functionName, $this->functionToFiles)) {
146+
return [];
147+
}
148+
149+
return $this->functionToFiles[$functionName];
150+
}
151+
152+
/**
153+
* @return list<Reflection>
154+
*/
155+
public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array
156+
{
157+
$reflections = [];
158+
if ($identifierType->isClass()) {
159+
foreach ($this->classToFile as $file) {
160+
$fetchedNodesResult = $this->fileNodesFetcher->fetchNodes($file);
161+
foreach ($fetchedNodesResult->getClassNodes() as $identifierName => $fetchedClassNodes) {
162+
foreach ($fetchedClassNodes as $fetchedClassNode) {
163+
$reflections[$identifierName] = $this->nodeToReflection($reflector, $fetchedClassNode);
164+
}
165+
}
166+
}
167+
} elseif ($identifierType->isFunction()) {
168+
foreach ($this->functionToFiles as $files) {
169+
foreach ($files as $file) {
170+
$fetchedNodesResult = $this->fileNodesFetcher->fetchNodes($file);
171+
foreach ($fetchedNodesResult->getFunctionNodes() as $identifierName => $fetchedFunctionNodes) {
172+
foreach ($fetchedFunctionNodes as $fetchedFunctionNode) {
173+
$reflections[$identifierName] = $this->nodeToReflection($reflector, $fetchedFunctionNode);
174+
continue 2;
175+
}
176+
}
177+
}
178+
}
179+
} elseif ($identifierType->isConstant()) {
180+
foreach ($this->constantToFile as $file) {
181+
$fetchedNodesResult = $this->fileNodesFetcher->fetchNodes($file);
182+
foreach ($fetchedNodesResult->getConstantNodes() as $identifierName => $fetchedConstantNodes) {
183+
foreach ($fetchedConstantNodes as $fetchedConstantNode) {
184+
$reflections[$identifierName] = $this->nodeToReflection(
185+
$reflector,
186+
$fetchedConstantNode,
187+
$this->findConstantPositionInConstNode($fetchedConstantNode->getNode(), $identifierName),
188+
);
189+
}
190+
}
191+
}
192+
}
193+
194+
return array_values($reflections);
195+
}
196+
197+
private function findConstantPositionInConstNode(Node\Stmt\Const_|Node\Expr\FuncCall $constantNode, string $constantName): ?int
198+
{
199+
if ($constantNode instanceof Node\Expr\FuncCall) {
200+
return null;
201+
}
202+
203+
/** @var int $position */
204+
foreach ($constantNode->consts as $position => $const) {
205+
if ($const->namespacedName === null) {
206+
throw new ShouldNotHappenException();
207+
}
208+
209+
if (ConstantNameHelper::normalize($const->namespacedName->toString()) === $constantName) {
210+
return $position;
211+
}
212+
}
213+
214+
throw new ShouldNotHappenException();
215+
}
216+
217+
}

0 commit comments

Comments
 (0)