Skip to content

Commit d7241b6

Browse files
committed
fix assignments
1 parent f090c27 commit d7241b6

File tree

3 files changed

+48
-3
lines changed

3 files changed

+48
-3
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -929,12 +929,14 @@ private function processStmtNode(
929929
$hasYield = $result->hasYield();
930930
$throwPoints = $result->getThrowPoints();
931931
$impurePoints = $result->getImpurePoints();
932+
$isAlwaysTerminating = $result->isAlwaysTerminating();
933+
932934
if ($earlyTerminationExpr !== null) {
933935
return new StatementResult($scope, $hasYield, true, [
934936
new StatementExitPoint($stmt, $scope),
935937
], $overridingThrowPoints ?? $throwPoints, $impurePoints);
936938
}
937-
return new StatementResult($scope, $hasYield, false, [], $overridingThrowPoints ?? $throwPoints, $impurePoints);
939+
return new StatementResult($scope, $hasYield, $isAlwaysTerminating, [], $overridingThrowPoints ?? $throwPoints, $impurePoints);
938940
} elseif ($stmt instanceof Node\Stmt\Namespace_) {
939941
if ($stmt->name !== null) {
940942
$scope = $scope->enterNamespace($stmt->name->toString());
@@ -2466,20 +2468,22 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context): Exp
24662468
$hasYield = $result->hasYield();
24672469
$throwPoints = $result->getThrowPoints();
24682470
$impurePoints = array_merge($impurePoints, $result->getImpurePoints());
2471+
$isAlwaysTerminating = $result->isAlwaysTerminating();
24692472
$scope = $result->getScope();
24702473

24712474
if ($expr instanceof AssignRef) {
24722475
$scope = $scope->exitExpressionAssign($expr->expr);
24732476
}
24742477

2475-
return new ExpressionResult($scope, $hasYield, $throwPoints, $impurePoints);
2478+
return new ExpressionResult($scope, $hasYield, $throwPoints, $impurePoints, isAlwaysTerminating: $isAlwaysTerminating);
24762479
},
24772480
true,
24782481
);
24792482
$scope = $result->getScope();
24802483
$hasYield = $result->hasYield();
24812484
$throwPoints = $result->getThrowPoints();
24822485
$impurePoints = $result->getImpurePoints();
2486+
$isAlwaysTerminating = $result->isAlwaysTerminating();
24832487
$vars = $this->getAssignedVariables($expr->var);
24842488
if (count($vars) > 0) {
24852489
$varChangedScope = false;
@@ -2511,6 +2515,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context): Exp
25112515
$result->hasYield(),
25122516
$result->getThrowPoints(),
25132517
$result->getImpurePoints(),
2518+
isAlwaysTerminating: $result->isAlwaysTerminating(),
25142519
);
25152520
}
25162521

@@ -2522,6 +2527,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context): Exp
25222527
$hasYield = $result->hasYield();
25232528
$throwPoints = $result->getThrowPoints();
25242529
$impurePoints = $result->getImpurePoints();
2530+
$isAlwaysTerminating = $result->isAlwaysTerminating();
25252531
if (
25262532
($expr instanceof Expr\AssignOp\Div || $expr instanceof Expr\AssignOp\Mod) &&
25272533
!$scope->getType($expr->expr)->toNumber()->isSuperTypeOf(new ConstantIntegerType(0))->no()
@@ -5382,12 +5388,14 @@ private function processAssignVar(
53825388
$hasYield = false;
53835389
$throwPoints = [];
53845390
$impurePoints = [];
5391+
$isAlwaysTerminating = false;
53855392
$isAssignOp = $assignedExpr instanceof Expr\AssignOp && !$enterExpressionAssign;
53865393
if ($var instanceof Variable && is_string($var->name)) {
53875394
$result = $processExprCallback($scope);
53885395
$hasYield = $result->hasYield();
53895396
$throwPoints = $result->getThrowPoints();
53905397
$impurePoints = $result->getImpurePoints();
5398+
$isAlwaysTerminating = $result->isAlwaysTerminating();
53915399
if (in_array($var->name, Scope::SUPERGLOBAL_VARIABLES, true)) {
53925400
$impurePoints[] = new ImpurePoint($scope, $var, 'superglobal', 'assign to superglobal variable', true);
53935401
}
@@ -5472,6 +5480,7 @@ private function processAssignVar(
54725480
$hasYield = $result->hasYield();
54735481
$throwPoints = $result->getThrowPoints();
54745482
$impurePoints = $result->getImpurePoints();
5483+
$isAlwaysTerminating = $result->isAlwaysTerminating();
54755484
$scope = $result->getScope();
54765485
if ($enterExpressionAssign) {
54775486
$scope = $scope->exitExpressionAssign($var);
@@ -5523,6 +5532,7 @@ private function processAssignVar(
55235532
$hasYield = $hasYield || $result->hasYield();
55245533
$throwPoints = array_merge($throwPoints, $result->getThrowPoints());
55255534
$impurePoints = array_merge($impurePoints, $result->getImpurePoints());
5535+
$isAlwaysTerminating = $isAlwaysTerminating || $result->isAlwaysTerminating();
55265536
$scope = $result->getScope();
55275537

55285538
$varType = $scope->getType($var);
@@ -5628,6 +5638,7 @@ static function (): void {
56285638
$hasYield = $objectResult->hasYield();
56295639
$throwPoints = $objectResult->getThrowPoints();
56305640
$impurePoints = $objectResult->getImpurePoints();
5641+
$isAlwaysTerminating = $objectResult->isAlwaysTerminating();
56315642
$scope = $objectResult->getScope();
56325643

56335644
$propertyName = null;
@@ -5638,6 +5649,7 @@ static function (): void {
56385649
$hasYield = $hasYield || $propertyNameResult->hasYield();
56395650
$throwPoints = array_merge($throwPoints, $propertyNameResult->getThrowPoints());
56405651
$impurePoints = array_merge($impurePoints, $propertyNameResult->getImpurePoints());
5652+
$isAlwaysTerminating = $isAlwaysTerminating || $propertyNameResult->isAlwaysTerminating();
56415653
$scope = $propertyNameResult->getScope();
56425654
}
56435655

@@ -5646,6 +5658,7 @@ static function (): void {
56465658
$hasYield = $hasYield || $result->hasYield();
56475659
$throwPoints = array_merge($throwPoints, $result->getThrowPoints());
56485660
$impurePoints = array_merge($impurePoints, $result->getImpurePoints());
5661+
$isAlwaysTerminating = $isAlwaysTerminating || $result->isAlwaysTerminating();
56495662
$scope = $result->getScope();
56505663

56515664
if ($var->name instanceof Expr && $this->phpVersion->supportsPropertyHooks()) {
@@ -5733,6 +5746,7 @@ static function (): void {
57335746
$hasYield = $propertyNameResult->hasYield();
57345747
$throwPoints = $propertyNameResult->getThrowPoints();
57355748
$impurePoints = $propertyNameResult->getImpurePoints();
5749+
$isAlwaysTerminating = $propertyNameResult->isAlwaysTerminating();
57365750
$scope = $propertyNameResult->getScope();
57375751
}
57385752

@@ -5741,6 +5755,7 @@ static function (): void {
57415755
$hasYield = $hasYield || $result->hasYield();
57425756
$throwPoints = array_merge($throwPoints, $result->getThrowPoints());
57435757
$impurePoints = array_merge($impurePoints, $result->getImpurePoints());
5758+
$isAlwaysTerminating = $isAlwaysTerminating || $result->isAlwaysTerminating();
57445759
$scope = $result->getScope();
57455760

57465761
if ($propertyName !== null) {
@@ -5785,6 +5800,7 @@ static function (): void {
57855800
$hasYield = $result->hasYield();
57865801
$throwPoints = array_merge($throwPoints, $result->getThrowPoints());
57875802
$impurePoints = array_merge($impurePoints, $result->getImpurePoints());
5803+
$isAlwaysTerminating = $isAlwaysTerminating || $result->isAlwaysTerminating();
57885804
$scope = $result->getScope();
57895805
foreach ($var->items as $i => $arrayItem) {
57905806
if ($arrayItem === null) {
@@ -5802,13 +5818,15 @@ static function (): void {
58025818
$hasYield = $hasYield || $keyResult->hasYield();
58035819
$throwPoints = array_merge($throwPoints, $keyResult->getThrowPoints());
58045820
$impurePoints = array_merge($impurePoints, $keyResult->getImpurePoints());
5821+
$isAlwaysTerminating = $isAlwaysTerminating || $keyResult->isAlwaysTerminating();
58055822
$itemScope = $keyResult->getScope();
58065823
}
58075824

58085825
$valueResult = $this->processExprNode($stmt, $arrayItem->value, $itemScope, $nodeCallback, $context->enterDeep());
58095826
$hasYield = $hasYield || $valueResult->hasYield();
58105827
$throwPoints = array_merge($throwPoints, $valueResult->getThrowPoints());
58115828
$impurePoints = array_merge($impurePoints, $valueResult->getImpurePoints());
5829+
$isAlwaysTerminating = $isAlwaysTerminating || $valueResult->isAlwaysTerminating();
58125830

58135831
if ($arrayItem->key === null) {
58145832
$dimExpr = new Node\Scalar\Int_($i);
@@ -5829,6 +5847,7 @@ static function (): void {
58295847
$hasYield = $hasYield || $result->hasYield();
58305848
$throwPoints = array_merge($throwPoints, $result->getThrowPoints());
58315849
$impurePoints = array_merge($impurePoints, $result->getImpurePoints());
5850+
$isAlwaysTerminating = $isAlwaysTerminating || $result->isAlwaysTerminating();
58325851
}
58335852
} elseif ($var instanceof ExistingArrayDimFetch) {
58345853
$dimFetchStack = [];
@@ -5907,7 +5926,7 @@ static function (): void {
59075926
}
59085927
}
59095928

5910-
return new ExpressionResult($scope, $hasYield, $throwPoints, $impurePoints);
5929+
return new ExpressionResult($scope, $hasYield, $throwPoints, $impurePoints, isAlwaysTerminating: $isAlwaysTerminating);
59115930
}
59125931

59135932
/**

tests/PHPStan/Rules/DeadCode/UnreachableStatementRuleTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,4 +277,15 @@ public function testBug13232c(): void
277277
]);
278278
}
279279

280+
public function testBug13232d(): void
281+
{
282+
$this->treatPhpDocTypesAsCertain = false;
283+
$this->analyse([__DIR__ . '/data/bug-13232d.php'], [
284+
[
285+
'Unreachable statement - code above always terminates.',
286+
11,
287+
],
288+
]);
289+
}
290+
280291
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace Bug13232d;
4+
5+
final class HelloWorld
6+
{
7+
public function sayHi(): void
8+
{
9+
$x = 'Hello, ' . neverReturns()
10+
. ' no way';
11+
$x .= 'this will never happen';
12+
}
13+
}
14+
function neverReturns(): never {}
15+

0 commit comments

Comments
 (0)