Skip to content

Commit 4463d60

Browse files
committed
Preserve variable flow through declare blocks
1 parent 61f6fe5 commit 4463d60

4 files changed

Lines changed: 75 additions & 2 deletions

File tree

‎src/Analyser/StmtHandler/DeclareHandler.php‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public function processStmt(
4444
$impurePoints = [];
4545
$alwaysTerminating = false;
4646
$exitPoints = [];
47+
$variableFlow = null;
4748
foreach ($stmt->declares as $declare) {
4849
$nodeScopeResolver->callNodeCallback($nodeCallback, $declare, $scope, $storage);
4950
// the value is a constant scalar - process it so its result is stored
@@ -69,9 +70,10 @@ public function processStmt(
6970
$impurePoints = $result->getImpurePoints();
7071
$alwaysTerminating = $result->isAlwaysTerminating();
7172
$exitPoints = $result->getExitPoints();
73+
$variableFlow = $result->getVariableFlow();
7274
}
7375

74-
return new InternalStatementResult($scope, hasYield: $hasYield, isAlwaysTerminating: $alwaysTerminating, exitPoints: $exitPoints, throwPoints: $throwPoints, impurePoints: $impurePoints, dependencies: Dependencies::merge(...$dependencies));
76+
return new InternalStatementResult($scope, hasYield: $hasYield, isAlwaysTerminating: $alwaysTerminating, exitPoints: $exitPoints, throwPoints: $throwPoints, impurePoints: $impurePoints, variableFlow: $variableFlow, dependencies: Dependencies::merge(...$dependencies));
7577
}
7678

7779
}

‎tests/PHPStan/Rules/DeadCode/UnusedVariableRuleTest.php‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ public function testBug15411(): void
2323
$this->analyse([__DIR__ . '/data/bug-15411.php'], []);
2424
}
2525

26+
public function testBug15394(): void
27+
{
28+
$this->analyse([__DIR__ . '/data/bug-15394.php'], [
29+
['Variable $unused is never read.', 34],
30+
['Value assigned to variable $value is never read before being overwritten.', 40],
31+
]);
32+
}
33+
2634
public function testThrowableCatchAfterDocumentedException(): void
2735
{
2836
$this->analyse([__DIR__ . '/data/unused-variable-throwable-catch.php'], []);
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug15394;
4+
5+
function readInBlock(): void
6+
{
7+
$value = 1;
8+
declare(ticks=1) {
9+
echo $value;
10+
}
11+
}
12+
13+
function writeInBlock(): void
14+
{
15+
declare(ticks=1) {
16+
$value = 1;
17+
}
18+
echo $value;
19+
}
20+
21+
function readInNestedBlock(): void
22+
{
23+
$value = 1;
24+
declare(ticks=1) {
25+
declare(ticks=2) {
26+
echo $value;
27+
}
28+
}
29+
}
30+
31+
function unusedInBlock(): void
32+
{
33+
declare(ticks=1) {
34+
$unused = 1;
35+
}
36+
}
37+
38+
function overwrittenInBlock(): void
39+
{
40+
$value = 1;
41+
declare(ticks=1) {
42+
$value = 2;
43+
}
44+
echo $value;
45+
}
46+
47+
function readAfterDeclareStatement(): void
48+
{
49+
$value = 1;
50+
declare(ticks=1);
51+
echo $value;
52+
}
53+
54+
function readInAlternativeBlock(): void
55+
{
56+
$value = 1;
57+
declare(ticks=1):
58+
echo $value;
59+
enddeclare;
60+
}

‎turbo-ext/src/DeclareHandler.cpp‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ class DeclareHandler
122122
zv::Val exitPointsHold;
123123
zval *exitPoints = pt_internal_statement_result_exit_points(result.raw(), exitPointsHold);
124124
if (UNEXPECTED(exitPoints == NULL)) return zv::Val();
125+
zv::Val variableFlowHold;
126+
zval *variableFlow = pt_internal_statement_result_variable_flow(result.raw(), variableFlowHold);
127+
if (UNEXPECTED(variableFlow == NULL)) return zv::Val();
125128
{
126129
zv::Val hold;
127130
zval *resultDependencies = pt_internal_statement_result_dependencies(result.raw(), hold);
@@ -130,7 +133,7 @@ class DeclareHandler
130133
}
131134
zv::Val mergedDependencies = pt_dependencies_merge_list(dependencies.table());
132135
if (UNEXPECTED(mergedDependencies.isUndef())) return zv::Val();
133-
return pt_internal_statement_result_new(resultScope, hasYield, alwaysTerminating, exitPoints, throwPoints, impurePoints, NULL, NULL, -1, mergedDependencies.raw());
136+
return pt_internal_statement_result_new(resultScope, hasYield, alwaysTerminating, exitPoints, throwPoints, impurePoints, NULL, variableFlow, -1, mergedDependencies.raw());
134137
}
135138

136139
/* the statement-handler entry (Engine.h) */

0 commit comments

Comments
 (0)