Skip to content

Commit 5a44b21

Browse files
authored
Merge branch refs/heads/2.1.x into 2.2.x
2 parents b52ca09 + da3e0e6 commit 5a44b21

29 files changed

+761
-498
lines changed

src/Analyser/DirectInternalScopeFactory.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PhpParser\Node;
66
use PHPStan\Analyser\Fiber\FiberScope;
7+
use PHPStan\DependencyInjection\Container;
78
use PHPStan\DependencyInjection\Type\DynamicReturnTypeExtensionRegistryProvider;
89
use PHPStan\DependencyInjection\Type\ExpressionTypeResolverExtensionRegistryProvider;
910
use PHPStan\Node\Printer\ExprPrinter;
@@ -24,6 +25,7 @@ final class DirectInternalScopeFactory implements InternalScopeFactory
2425
* @param callable(Node $node, Scope $scope): void|null $nodeCallback
2526
*/
2627
public function __construct(
28+
private Container $container,
2729
private ReflectionProvider $reflectionProvider,
2830
private InitializerExprTypeResolver $initializerExprTypeResolver,
2931
private DynamicReturnTypeExtensionRegistryProvider $dynamicReturnTypeExtensionRegistryProvider,
@@ -69,6 +71,7 @@ public function create(
6971
}
7072

7173
return new $className(
74+
$this->container,
7275
$this,
7376
$this->reflectionProvider,
7477
$this->initializerExprTypeResolver,
@@ -107,6 +110,7 @@ public function create(
107110
public function toFiberFactory(): InternalScopeFactory
108111
{
109112
return new self(
113+
$this->container,
110114
$this->reflectionProvider,
111115
$this->initializerExprTypeResolver,
112116
$this->dynamicReturnTypeExtensionRegistryProvider,
@@ -129,6 +133,7 @@ public function toFiberFactory(): InternalScopeFactory
129133
public function toMutatingFactory(): InternalScopeFactory
130134
{
131135
return new self(
136+
$this->container,
132137
$this->reflectionProvider,
133138
$this->initializerExprTypeResolver,
134139
$this->dynamicReturnTypeExtensionRegistryProvider,

src/Analyser/DirectInternalScopeFactoryFactory.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Analyser;
44

55
use PhpParser\Node;
6+
use PHPStan\DependencyInjection\Container;
67
use PHPStan\DependencyInjection\Type\DynamicReturnTypeExtensionRegistryProvider;
78
use PHPStan\DependencyInjection\Type\ExpressionTypeResolverExtensionRegistryProvider;
89
use PHPStan\Node\Printer\ExprPrinter;
@@ -20,6 +21,7 @@ final class DirectInternalScopeFactoryFactory implements InternalScopeFactoryFac
2021
* @param int|array{min: int, max: int}|null $configPhpVersion
2122
*/
2223
public function __construct(
24+
private Container $container,
2325
private ReflectionProvider $reflectionProvider,
2426
private InitializerExprTypeResolver $initializerExprTypeResolver,
2527
private DynamicReturnTypeExtensionRegistryProvider $dynamicReturnTypeExtensionRegistryProvider,
@@ -44,6 +46,7 @@ public function __construct(
4446
public function create(?callable $nodeCallback): DirectInternalScopeFactory
4547
{
4648
return new DirectInternalScopeFactory(
49+
$this->container,
4750
$this->reflectionProvider,
4851
$this->initializerExprTypeResolver,
4952
$this->dynamicReturnTypeExtensionRegistryProvider,

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
}

0 commit comments

Comments
 (0)