Skip to content

Commit 3e51899

Browse files
committed
ConstExprNodeResolver - support ConstFetchNode for class constants
1 parent 524913e commit 3e51899

File tree

3 files changed

+75
-8
lines changed

3 files changed

+75
-8
lines changed

src/PhpDoc/ConstExprNodeResolver.php

+73-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\PhpDoc;
44

5+
use PHPStan\Analyser\NameScope;
56
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprArrayNode;
67
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFalseNode;
78
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFloatNode;
@@ -10,22 +11,35 @@
1011
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNullNode;
1112
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
1213
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprTrueNode;
14+
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
15+
use PHPStan\Reflection\InitializerExprContext;
16+
use PHPStan\Reflection\InitializerExprTypeResolver;
17+
use PHPStan\Reflection\ReflectionProvider;
1318
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
1419
use PHPStan\Type\Constant\ConstantBooleanType;
1520
use PHPStan\Type\Constant\ConstantFloatType;
1621
use PHPStan\Type\Constant\ConstantIntegerType;
1722
use PHPStan\Type\Constant\ConstantStringType;
18-
use PHPStan\Type\MixedType;
23+
use PHPStan\Type\Enum\EnumCaseObjectType;
24+
use PHPStan\Type\ErrorType;
1925
use PHPStan\Type\NullType;
2026
use PHPStan\Type\Type;
27+
use function strtolower;
2128

2229
final class ConstExprNodeResolver
2330
{
2431

25-
public function resolve(ConstExprNode $node): Type
32+
public function __construct(
33+
private ReflectionProvider\ReflectionProviderProvider $reflectionProviderProvider,
34+
private InitializerExprTypeResolver $initializerExprTypeResolver,
35+
)
36+
{
37+
}
38+
39+
public function resolve(ConstExprNode $node, NameScope $nameScope): Type
2640
{
2741
if ($node instanceof ConstExprArrayNode) {
28-
return $this->resolveArrayNode($node);
42+
return $this->resolveArrayNode($node, $nameScope);
2943
}
3044

3145
if ($node instanceof ConstExprFalseNode) {
@@ -52,22 +66,74 @@ public function resolve(ConstExprNode $node): Type
5266
return new ConstantStringType($node->value);
5367
}
5468

55-
return new MixedType();
69+
if ($node instanceof ConstFetchNode) {
70+
if ($nameScope->getClassName() !== null) {
71+
switch (strtolower($node->className)) {
72+
case 'static':
73+
case 'self':
74+
$className = $nameScope->getClassName();
75+
break;
76+
77+
case 'parent':
78+
if ($this->getReflectionProvider()->hasClass($nameScope->getClassName())) {
79+
$classReflection = $this->getReflectionProvider()->getClass($nameScope->getClassName());
80+
if ($classReflection->getParentClass() === null) {
81+
return new ErrorType();
82+
83+
}
84+
85+
$className = $classReflection->getParentClass()->getName();
86+
}
87+
break;
88+
}
89+
}
90+
if (!isset($className)) {
91+
$className = $nameScope->resolveStringName($node->className);
92+
}
93+
if (!$this->getReflectionProvider()->hasClass($className)) {
94+
return new ErrorType();
95+
}
96+
$classReflection = $this->getReflectionProvider()->getClass($className);
97+
if (!$classReflection->hasConstant($node->name)) {
98+
return new ErrorType();
99+
}
100+
if ($classReflection->isEnum() && $classReflection->hasEnumCase($node->name)) {
101+
return new EnumCaseObjectType($classReflection->getName(), $node->name);
102+
}
103+
104+
$reflectionConstant = $classReflection->getNativeReflection()->getReflectionConstant($node->name);
105+
if ($reflectionConstant === false) {
106+
return new ErrorType();
107+
}
108+
$declaringClass = $reflectionConstant->getDeclaringClass();
109+
110+
return $this->initializerExprTypeResolver->getType(
111+
$reflectionConstant->getValueExpression(),
112+
InitializerExprContext::fromClass($declaringClass->getName(), $declaringClass->getFileName() ?: null),
113+
);
114+
}
115+
116+
return new ErrorType();
56117
}
57118

58-
private function resolveArrayNode(ConstExprArrayNode $node): Type
119+
private function resolveArrayNode(ConstExprArrayNode $node, NameScope $nameScope): Type
59120
{
60121
$arrayBuilder = ConstantArrayTypeBuilder::createEmpty();
61122
foreach ($node->items as $item) {
62123
if ($item->key === null) {
63124
$key = null;
64125
} else {
65-
$key = $this->resolve($item->key);
126+
$key = $this->resolve($item->key, $nameScope);
66127
}
67-
$arrayBuilder->setOffsetValueType($key, $this->resolve($item->value));
128+
$arrayBuilder->setOffsetValueType($key, $this->resolve($item->value, $nameScope));
68129
}
69130

70131
return $arrayBuilder->getArray();
71132
}
72133

134+
private function getReflectionProvider(): ReflectionProvider
135+
{
136+
return $this->reflectionProviderProvider->getReflectionProvider();
137+
}
138+
73139
}

src/PhpDoc/PhpDocNodeResolver.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ public function resolveMethodTags(PhpDocNode $phpDocNode, NameScope $nameScope):
196196
}
197197
$defaultValue = null;
198198
if ($parameterNode->defaultValue !== null) {
199-
$defaultValue = $this->constExprNodeResolver->resolve($parameterNode->defaultValue);
199+
$defaultValue = $this->constExprNodeResolver->resolve($parameterNode->defaultValue, $nameScope);
200200
}
201201

202202
$parameters[$parameterName] = new MethodTagParameter(

src/PhpDoc/TypeNodeResolver.php

+1
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,7 @@ private function resolveConstTypeNode(ConstTypeNode $typeNode, NameScope $nameSc
10591059

10601060
$className = $classReflection->getParentClass()->getName();
10611061
}
1062+
break;
10621063
}
10631064
}
10641065

0 commit comments

Comments
 (0)