Skip to content

Commit da3e0e6

Browse files
committed
More expr handlers implement resolveType
1 parent a11b86d commit da3e0e6

23 files changed

+717
-496
lines changed

src/Analyser/ExprHandler/ArrayHandler.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use PHPStan\DependencyInjection\AutowiredService;
1515
use PHPStan\Node\LiteralArrayItem;
1616
use PHPStan\Node\LiteralArrayNode;
17+
use PHPStan\Reflection\InitializerExprTypeResolver;
18+
use PHPStan\Type\Type;
1719
use function array_merge;
1820

1921
/**
@@ -23,11 +25,25 @@
2325
final class ArrayHandler implements ExprHandler
2426
{
2527

28+
public function __construct(
29+
private InitializerExprTypeResolver $initializerExprTypeResolver,
30+
)
31+
{
32+
}
33+
2634
public function supports(Expr $expr): bool
2735
{
2836
return $expr instanceof Array_;
2937
}
3038

39+
/**
40+
* @param Array_ $expr
41+
*/
42+
public function resolveType(MutatingScope $scope, Expr $expr): Type
43+
{
44+
return $this->initializerExprTypeResolver->getArrayType($expr, static fn (Expr $expr): Type => $scope->getType($expr));
45+
}
46+
3147
public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Expr $expr, MutatingScope $scope, ExpressionResultStorage $storage, callable $nodeCallback, ExpressionContext $context): ExpressionResult
3248
{
3349
$itemNodes = [];

src/Analyser/ExprHandler/AssignHandler.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use PHPStan\Analyser\MutatingScope;
1919
use PHPStan\Analyser\NodeScopeResolver;
2020
use PHPStan\DependencyInjection\AutowiredService;
21+
use PHPStan\Type\Type;
2122
use function array_merge;
2223
use function count;
2324
use function is_string;
@@ -34,6 +35,14 @@ public function supports(Expr $expr): bool
3435
return $expr instanceof Assign || $expr instanceof AssignRef;
3536
}
3637

38+
/**
39+
* @param Assign|AssignRef $expr
40+
*/
41+
public function resolveType(MutatingScope $scope, Expr $expr): Type
42+
{
43+
return $scope->getType($expr->expr);
44+
}
45+
3746
public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Expr $expr, MutatingScope $scope, ExpressionResultStorage $storage, callable $nodeCallback, ExpressionContext $context): ExpressionResult
3847
{
3948
$result = $nodeScopeResolver->processAssignVar(

src/Analyser/ExprHandler/AssignOpHandler.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,13 @@
1717
use PHPStan\Analyser\MutatingScope;
1818
use PHPStan\Analyser\NodeScopeResolver;
1919
use PHPStan\DependencyInjection\AutowiredService;
20+
use PHPStan\Reflection\InitializerExprTypeResolver;
21+
use PHPStan\ShouldNotHappenException;
2022
use PHPStan\Type\Constant\ConstantIntegerType;
2123
use PHPStan\Type\ObjectType;
24+
use PHPStan\Type\Type;
25+
use function get_class;
26+
use function sprintf;
2227

2328
/**
2429
* @implements ExprHandler<AssignOp>
@@ -27,6 +32,12 @@
2732
final class AssignOpHandler implements ExprHandler
2833
{
2934

35+
public function __construct(
36+
private InitializerExprTypeResolver $initializerExprTypeResolver,
37+
)
38+
{
39+
}
40+
3041
public function supports(Expr $expr): bool
3142
{
3243
return $expr instanceof AssignOp;
@@ -89,4 +100,66 @@ static function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $contex
89100
);
90101
}
91102

103+
/**
104+
* @param AssignOp $expr
105+
*/
106+
public function resolveType(MutatingScope $scope, Expr $expr): Type
107+
{
108+
$getType = static fn (Expr $expr): Type => $scope->getType($expr);
109+
110+
if ($expr instanceof Expr\AssignOp\Coalesce) {
111+
return $scope->getType(new BinaryOp\Coalesce($expr->var, $expr->expr, $expr->getAttributes()));
112+
}
113+
114+
if ($expr instanceof Expr\AssignOp\Concat) {
115+
return $this->initializerExprTypeResolver->getConcatType($expr->var, $expr->expr, $getType);
116+
}
117+
118+
if ($expr instanceof Expr\AssignOp\BitwiseAnd) {
119+
return $this->initializerExprTypeResolver->getBitwiseAndType($expr->var, $expr->expr, $getType);
120+
}
121+
122+
if ($expr instanceof Expr\AssignOp\BitwiseOr) {
123+
return $this->initializerExprTypeResolver->getBitwiseOrType($expr->var, $expr->expr, $getType);
124+
}
125+
126+
if ($expr instanceof Expr\AssignOp\BitwiseXor) {
127+
return $this->initializerExprTypeResolver->getBitwiseXorType($expr->var, $expr->expr, $getType);
128+
}
129+
130+
if ($expr instanceof Expr\AssignOp\Div) {
131+
return $this->initializerExprTypeResolver->getDivType($expr->var, $expr->expr, $getType);
132+
}
133+
134+
if ($expr instanceof Expr\AssignOp\Mod) {
135+
return $this->initializerExprTypeResolver->getModType($expr->var, $expr->expr, $getType);
136+
}
137+
138+
if ($expr instanceof Expr\AssignOp\Plus) {
139+
return $this->initializerExprTypeResolver->getPlusType($expr->var, $expr->expr, $getType);
140+
}
141+
142+
if ($expr instanceof Expr\AssignOp\Minus) {
143+
return $this->initializerExprTypeResolver->getMinusType($expr->var, $expr->expr, $getType);
144+
}
145+
146+
if ($expr instanceof Expr\AssignOp\Mul) {
147+
return $this->initializerExprTypeResolver->getMulType($expr->var, $expr->expr, $getType);
148+
}
149+
150+
if ($expr instanceof Expr\AssignOp\Pow) {
151+
return $this->initializerExprTypeResolver->getPowType($expr->var, $expr->expr, $getType);
152+
}
153+
154+
if ($expr instanceof Expr\AssignOp\ShiftLeft) {
155+
return $this->initializerExprTypeResolver->getShiftLeftType($expr->var, $expr->expr, $getType);
156+
}
157+
158+
if ($expr instanceof Expr\AssignOp\ShiftRight) {
159+
return $this->initializerExprTypeResolver->getShiftRightType($expr->var, $expr->expr, $getType);
160+
}
161+
162+
throw new ShouldNotHappenException(sprintf('Unhandled %s', get_class($expr)));
163+
}
164+
92165
}

src/Analyser/ExprHandler/BinaryOpHandler.php

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PhpParser\Node\Expr\BinaryOp;
88
use PhpParser\Node\Expr\BinaryOp\BooleanAnd;
99
use PhpParser\Node\Expr\BinaryOp\BooleanOr;
10+
use PhpParser\Node\Expr\Variable;
1011
use PhpParser\Node\Stmt;
1112
use PHPStan\Analyser\ExpressionContext;
1213
use PHPStan\Analyser\ExpressionResult;
@@ -15,10 +16,20 @@
1516
use PHPStan\Analyser\InternalThrowPoint;
1617
use PHPStan\Analyser\MutatingScope;
1718
use PHPStan\Analyser\NodeScopeResolver;
19+
use PHPStan\Analyser\RicherScopeGetTypeHelper;
1820
use PHPStan\DependencyInjection\AutowiredService;
21+
use PHPStan\Php\PhpVersion;
22+
use PHPStan\Reflection\InitializerExprTypeResolver;
23+
use PHPStan\ShouldNotHappenException;
24+
use PHPStan\Type\BooleanType;
25+
use PHPStan\Type\Constant\ConstantBooleanType;
1926
use PHPStan\Type\Constant\ConstantIntegerType;
2027
use PHPStan\Type\ObjectType;
28+
use PHPStan\Type\Type;
2129
use function array_merge;
30+
use function get_class;
31+
use function is_string;
32+
use function sprintf;
2233

2334
/**
2435
* @implements ExprHandler<BinaryOp>
@@ -27,6 +38,14 @@
2738
final class BinaryOpHandler implements ExprHandler
2839
{
2940

41+
public function __construct(
42+
private InitializerExprTypeResolver $initializerExprTypeResolver,
43+
private RicherScopeGetTypeHelper $richerScopeGetTypeHelper,
44+
private PhpVersion $phpVersion,
45+
)
46+
{
47+
}
48+
3049
public function supports(Expr $expr): bool
3150
{
3251
return $expr instanceof BinaryOp
@@ -70,4 +89,127 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex
7089
);
7190
}
7291

92+
/**
93+
* @param BinaryOp $expr
94+
*/
95+
public function resolveType(MutatingScope $scope, Expr $expr): Type
96+
{
97+
$getType = static fn (Expr $expr): Type => $scope->getType($expr);
98+
99+
if ($expr instanceof BinaryOp\Smaller) {
100+
return $scope->getType($expr->left)->isSmallerThan($scope->getType($expr->right), $this->phpVersion)->toBooleanType();
101+
}
102+
103+
if ($expr instanceof BinaryOp\SmallerOrEqual) {
104+
return $scope->getType($expr->left)->isSmallerThanOrEqual($scope->getType($expr->right), $this->phpVersion)->toBooleanType();
105+
}
106+
107+
if ($expr instanceof BinaryOp\Greater) {
108+
return $scope->getType($expr->right)->isSmallerThan($scope->getType($expr->left), $this->phpVersion)->toBooleanType();
109+
}
110+
111+
if ($expr instanceof BinaryOp\GreaterOrEqual) {
112+
return $scope->getType($expr->right)->isSmallerThanOrEqual($scope->getType($expr->left), $this->phpVersion)->toBooleanType();
113+
}
114+
115+
if ($expr instanceof BinaryOp\Equal) {
116+
if (
117+
$expr->left instanceof Variable
118+
&& is_string($expr->left->name)
119+
&& $expr->right instanceof Variable
120+
&& is_string($expr->right->name)
121+
&& $expr->left->name === $expr->right->name
122+
) {
123+
return new ConstantBooleanType(true);
124+
}
125+
126+
$leftType = $scope->getType($expr->left);
127+
$rightType = $scope->getType($expr->right);
128+
129+
return $this->initializerExprTypeResolver->resolveEqualType($leftType, $rightType)->type;
130+
}
131+
132+
if ($expr instanceof BinaryOp\NotEqual) {
133+
return $scope->getType(new Expr\BooleanNot(new BinaryOp\Equal($expr->left, $expr->right)));
134+
}
135+
136+
if ($expr instanceof BinaryOp\Identical) {
137+
return $this->richerScopeGetTypeHelper->getIdenticalResult($scope, $expr)->type;
138+
}
139+
140+
if ($expr instanceof BinaryOp\NotIdentical) {
141+
return $this->richerScopeGetTypeHelper->getNotIdenticalResult($scope, $expr)->type;
142+
}
143+
144+
if ($expr instanceof BinaryOp\LogicalXor) {
145+
$leftBooleanType = $scope->getType($expr->left)->toBoolean();
146+
$rightBooleanType = $scope->getType($expr->right)->toBoolean();
147+
148+
if (
149+
$leftBooleanType instanceof ConstantBooleanType
150+
&& $rightBooleanType instanceof ConstantBooleanType
151+
) {
152+
return new ConstantBooleanType(
153+
$leftBooleanType->getValue() xor $rightBooleanType->getValue(),
154+
);
155+
}
156+
157+
return new BooleanType();
158+
}
159+
160+
if ($expr instanceof BinaryOp\Spaceship) {
161+
return $this->initializerExprTypeResolver->getSpaceshipType($expr->left, $expr->right, $getType);
162+
}
163+
164+
if ($expr instanceof BinaryOp\Concat) {
165+
return $this->initializerExprTypeResolver->getConcatType($expr->left, $expr->right, $getType);
166+
}
167+
168+
if ($expr instanceof BinaryOp\BitwiseAnd) {
169+
return $this->initializerExprTypeResolver->getBitwiseAndType($expr->left, $expr->right, $getType);
170+
}
171+
172+
if ($expr instanceof BinaryOp\BitwiseOr) {
173+
return $this->initializerExprTypeResolver->getBitwiseOrType($expr->left, $expr->right, $getType);
174+
}
175+
176+
if ($expr instanceof BinaryOp\BitwiseXor) {
177+
return $this->initializerExprTypeResolver->getBitwiseXorType($expr->left, $expr->right, $getType);
178+
}
179+
180+
if ($expr instanceof BinaryOp\Div) {
181+
return $this->initializerExprTypeResolver->getDivType($expr->left, $expr->right, $getType);
182+
}
183+
184+
if ($expr instanceof BinaryOp\Mod) {
185+
return $this->initializerExprTypeResolver->getModType($expr->left, $expr->right, $getType);
186+
}
187+
188+
if ($expr instanceof BinaryOp\Plus) {
189+
return $this->initializerExprTypeResolver->getPlusType($expr->left, $expr->right, $getType);
190+
}
191+
192+
if ($expr instanceof BinaryOp\Minus) {
193+
return $this->initializerExprTypeResolver->getMinusType($expr->left, $expr->right, $getType);
194+
}
195+
196+
if ($expr instanceof BinaryOp\Mul) {
197+
return $this->initializerExprTypeResolver->getMulType($expr->left, $expr->right, $getType);
198+
}
199+
200+
if ($expr instanceof BinaryOp\Pow) {
201+
return $this->initializerExprTypeResolver->getPowType($expr->left, $expr->right, $getType);
202+
}
203+
204+
if ($expr instanceof BinaryOp\ShiftLeft) {
205+
return $this->initializerExprTypeResolver->getShiftLeftType($expr->left, $expr->right, $getType);
206+
}
207+
208+
if ($expr instanceof BinaryOp\ShiftRight) {
209+
return $this->initializerExprTypeResolver->getShiftRightType($expr->left, $expr->right, $getType);
210+
}
211+
212+
throw new ShouldNotHappenException(sprintf('Unhandled %s', get_class($expr)));
213+
}
214+
73215
}

src/Analyser/ExprHandler/BitwiseNotHandler.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
use PHPStan\Analyser\MutatingScope;
1313
use PHPStan\Analyser\NodeScopeResolver;
1414
use PHPStan\DependencyInjection\AutowiredService;
15+
use PHPStan\Reflection\InitializerExprTypeResolver;
16+
use PHPStan\Type\Type;
1517

1618
/**
1719
* @implements ExprHandler<BitwiseNot>
@@ -20,6 +22,12 @@
2022
final class BitwiseNotHandler implements ExprHandler
2123
{
2224

25+
public function __construct(
26+
private InitializerExprTypeResolver $initializerExprTypeResolver,
27+
)
28+
{
29+
}
30+
2331
public function supports(Expr $expr): bool
2432
{
2533
return $expr instanceof BitwiseNot;
@@ -41,4 +49,12 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex
4149
);
4250
}
4351

52+
/**
53+
* @param BitwiseNot $expr
54+
*/
55+
public function resolveType(MutatingScope $scope, Expr $expr): Type
56+
{
57+
return $this->initializerExprTypeResolver->getBitwiseNotType($expr->expr, static fn (Expr $expr): Type => $scope->getType($expr));
58+
}
59+
4460
}

src/Analyser/ExprHandler/BooleanNotHandler.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
use PHPStan\Analyser\MutatingScope;
1313
use PHPStan\Analyser\NodeScopeResolver;
1414
use PHPStan\DependencyInjection\AutowiredService;
15+
use PHPStan\Type\BooleanType;
16+
use PHPStan\Type\Constant\ConstantBooleanType;
17+
use PHPStan\Type\Type;
1518

1619
/**
1720
* @implements ExprHandler<BooleanNot>
@@ -41,4 +44,17 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex
4144
);
4245
}
4346

47+
/**
48+
* @param BooleanNot $expr
49+
*/
50+
public function resolveType(MutatingScope $scope, Expr $expr): Type
51+
{
52+
$exprBooleanType = $scope->getType($expr->expr)->toBoolean();
53+
if ($exprBooleanType instanceof ConstantBooleanType) {
54+
return new ConstantBooleanType(!$exprBooleanType->getValue());
55+
}
56+
57+
return new BooleanType();
58+
}
59+
4460
}

0 commit comments

Comments
 (0)