Skip to content

Commit 2681a90

Browse files
committed
resolveType in ConstFetchHandler
1 parent e330a18 commit 2681a90

File tree

2 files changed

+57
-40
lines changed

2 files changed

+57
-40
lines changed

src/Analyser/ExprHandler/ConstFetchHandler.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,21 @@
44

55
use PhpParser\Node\Expr;
66
use PhpParser\Node\Expr\ConstFetch;
7+
use PhpParser\Node\Name\FullyQualified;
78
use PhpParser\Node\Stmt;
9+
use PHPStan\Analyser\ConstantResolver;
810
use PHPStan\Analyser\ExpressionContext;
911
use PHPStan\Analyser\ExpressionResult;
1012
use PHPStan\Analyser\ExpressionResultStorage;
1113
use PHPStan\Analyser\ExprHandler;
1214
use PHPStan\Analyser\MutatingScope;
1315
use PHPStan\Analyser\NodeScopeResolver;
1416
use PHPStan\DependencyInjection\AutowiredService;
17+
use PHPStan\Type\Constant\ConstantBooleanType;
18+
use PHPStan\Type\ErrorType;
19+
use PHPStan\Type\NullType;
20+
use PHPStan\Type\Type;
21+
use function strtolower;
1522

1623
/**
1724
* @implements ExprHandler<ConstFetch>
@@ -20,6 +27,12 @@
2027
final class ConstFetchHandler implements ExprHandler
2128
{
2229

30+
public function __construct(
31+
private ConstantResolver $constantResolver,
32+
)
33+
{
34+
}
35+
2336
public function supports(Expr $expr): bool
2437
{
2538
return $expr instanceof ConstFetch;
@@ -40,4 +53,46 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex
4053
);
4154
}
4255

56+
/**
57+
* @param ConstFetch $expr
58+
*/
59+
public function resolveType(MutatingScope $scope, Expr $expr): Type
60+
{
61+
$constName = (string) $expr->name;
62+
$loweredConstName = strtolower($constName);
63+
if ($loweredConstName === 'true') {
64+
return new ConstantBooleanType(true);
65+
} elseif ($loweredConstName === 'false') {
66+
return new ConstantBooleanType(false);
67+
} elseif ($loweredConstName === 'null') {
68+
return new NullType();
69+
}
70+
71+
$namespacedName = null;
72+
if (!$expr->name->isFullyQualified() && $scope->getNamespace() !== null) {
73+
$namespacedName = new FullyQualified([$scope->getNamespace(), $expr->name->toString()]);
74+
}
75+
$globalName = new FullyQualified($expr->name->toString());
76+
77+
foreach ([$namespacedName, $globalName] as $name) {
78+
if ($name === null) {
79+
continue;
80+
}
81+
$constFetch = new ConstFetch($name);
82+
if ($scope->hasExpressionType($constFetch)->yes()) {
83+
return $this->constantResolver->resolveConstantType(
84+
$name->toString(),
85+
$scope->expressionTypes[$scope->getNodeKey($constFetch)]->getType(),
86+
);
87+
}
88+
}
89+
90+
$constantType = $this->constantResolver->resolveConstant($expr->name, $scope);
91+
if ($constantType !== null) {
92+
return $constantType;
93+
}
94+
95+
return new ErrorType();
96+
}
97+
4398
}

src/Analyser/MutatingScope.php

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ public function __construct(
220220
private bool $declareStrictTypes = false,
221221
private PhpFunctionFromParserNodeReflection|null $function = null,
222222
?string $namespace = null,
223-
protected array $expressionTypes = [],
223+
public array $expressionTypes = [],
224224
protected array $nativeExpressionTypes = [],
225225
protected array $conditionalExpressions = [],
226226
protected array $inClosureBindScopeClasses = [],
@@ -1005,7 +1005,7 @@ public function getScopeNativeType(Expr $expr): Type
10051005
return $this->getNativeType($expr);
10061006
}
10071007

1008-
private function getNodeKey(Expr $node): string
1008+
public function getNodeKey(Expr $node): string
10091009
{
10101010
// perf optimize for the most common path
10111011
if ($node instanceof Variable && !$node->name instanceof Expr) {
@@ -1096,44 +1096,6 @@ private function resolveType(string $exprString, Expr $node): Type
10961096
return new NullType();
10971097
}
10981098

1099-
if ($node instanceof ConstFetch) {
1100-
$constName = (string) $node->name;
1101-
$loweredConstName = strtolower($constName);
1102-
if ($loweredConstName === 'true') {
1103-
return new ConstantBooleanType(true);
1104-
} elseif ($loweredConstName === 'false') {
1105-
return new ConstantBooleanType(false);
1106-
} elseif ($loweredConstName === 'null') {
1107-
return new NullType();
1108-
}
1109-
1110-
$namespacedName = null;
1111-
if (!$node->name->isFullyQualified() && $this->getNamespace() !== null) {
1112-
$namespacedName = new FullyQualified([$this->getNamespace(), $node->name->toString()]);
1113-
}
1114-
$globalName = new FullyQualified($node->name->toString());
1115-
1116-
foreach ([$namespacedName, $globalName] as $name) {
1117-
if ($name === null) {
1118-
continue;
1119-
}
1120-
$constFetch = new ConstFetch($name);
1121-
if ($this->hasExpressionType($constFetch)->yes()) {
1122-
return $this->constantResolver->resolveConstantType(
1123-
$name->toString(),
1124-
$this->expressionTypes[$this->getNodeKey($constFetch)]->getType(),
1125-
);
1126-
}
1127-
}
1128-
1129-
$constantType = $this->constantResolver->resolveConstant($node->name, $this);
1130-
if ($constantType !== null) {
1131-
return $constantType;
1132-
}
1133-
1134-
return new ErrorType();
1135-
}
1136-
11371099
if ($node instanceof MethodCall) {
11381100
$callType = $this->getMethodCallType($node);
11391101
if ($callType !== null) {

0 commit comments

Comments
 (0)