Skip to content

Commit 135ab50

Browse files
committed
ConstFetch handler
1 parent 0f966f8 commit 135ab50

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser\Generator\ExprHandler;
4+
5+
use Generator;
6+
use PhpParser\Node\Expr;
7+
use PhpParser\Node\Expr\ConstFetch;
8+
use PhpParser\Node\Name\FullyQualified;
9+
use PhpParser\Node\Stmt;
10+
use PHPStan\Analyser\ConstantResolver;
11+
use PHPStan\Analyser\ExpressionContext;
12+
use PHPStan\Analyser\Generator\ExprAnalysisResult;
13+
use PHPStan\Analyser\Generator\ExprHandler;
14+
use PHPStan\Analyser\Generator\GeneratorScope;
15+
use PHPStan\Analyser\Generator\NodeCallbackRequest;
16+
use PHPStan\Analyser\Generator\SpecifiedTypesHelper;
17+
use PHPStan\Analyser\SpecifiedTypes;
18+
use PHPStan\DependencyInjection\AutowiredService;
19+
use PHPStan\Type\Constant\ConstantBooleanType;
20+
use PHPStan\Type\ErrorType;
21+
use PHPStan\Type\NullType;
22+
use PHPStan\Type\Type;
23+
use function strtolower;
24+
25+
/**
26+
* @implements ExprHandler<ConstFetch>
27+
*/
28+
#[AutowiredService]
29+
final class ConstFetchHandler implements ExprHandler
30+
{
31+
32+
public function __construct(
33+
private ConstantResolver $constantResolver,
34+
private SpecifiedTypesHelper $specifiedTypesHelper,
35+
)
36+
{
37+
}
38+
39+
public function supports(Expr $expr): bool
40+
{
41+
return $expr instanceof ConstFetch;
42+
}
43+
44+
public function analyseExpr(Stmt $stmt, Expr $expr, GeneratorScope $scope, ExpressionContext $context, ?callable $alternativeNodeCallback): Generator
45+
{
46+
yield new NodeCallbackRequest($expr->name, $scope, $alternativeNodeCallback);
47+
48+
$type = $this->getConstFetchType($expr, $scope);
49+
50+
return new ExprAnalysisResult(
51+
$type,
52+
$type,
53+
$scope,
54+
hasYield: false,
55+
isAlwaysTerminating: false,
56+
throwPoints: [],
57+
impurePoints: [],
58+
specifiedTruthyTypes: $this->specifiedTypesHelper->createDefaultSpecifiedTruthyTypes($expr),
59+
specifiedFalseyTypes: $this->specifiedTypesHelper->createDefaultSpecifiedFalseyTypes($expr),
60+
specifiedNullTypes: new SpecifiedTypes(),
61+
);
62+
}
63+
64+
private function getConstFetchType(ConstFetch $expr, GeneratorScope $scope): Type
65+
{
66+
$constName = (string) $expr->name;
67+
$loweredConstName = strtolower($constName);
68+
if ($loweredConstName === 'true') {
69+
return new ConstantBooleanType(true);
70+
} elseif ($loweredConstName === 'false') {
71+
return new ConstantBooleanType(false);
72+
} elseif ($loweredConstName === 'null') {
73+
return new NullType();
74+
}
75+
76+
$namespacedName = null;
77+
if (!$expr->name->isFullyQualified() && $scope->getNamespace() !== null) {
78+
$namespacedName = new FullyQualified([$scope->getNamespace(), $expr->name->toString()]);
79+
}
80+
$globalName = new FullyQualified($expr->name->toString());
81+
82+
foreach ([$namespacedName, $globalName] as $name) {
83+
if ($name === null) {
84+
continue;
85+
}
86+
$constFetch = new ConstFetch($name);
87+
$exprType = $scope->getExpressionType($constFetch);
88+
if ($exprType !== null) {
89+
return $this->constantResolver->resolveConstantType(
90+
$name->toString(),
91+
$exprType,
92+
);
93+
}
94+
}
95+
96+
$constantType = $this->constantResolver->resolveConstant($expr->name, $scope);
97+
if ($constantType !== null) {
98+
return $constantType;
99+
}
100+
101+
return new ErrorType();
102+
}
103+
104+
}

tests/PHPStan/Analyser/Generator/data/gnsr.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use DivisionByZeroError;
99
use function PHPStan\Testing\assertNativeType;
1010
use function PHPStan\Testing\assertType;
11+
use const PHP_VERSION_ID;
1112

1213
class Foo
1314
{
@@ -470,3 +471,7 @@ function doFoo(): void {
470471
assertType('470', __LINE__);
471472
}
472473
}
474+
475+
function (): void {
476+
assertType('int<50207, 80599>', PHP_VERSION_ID);
477+
};

0 commit comments

Comments
 (0)