1: | <?php declare(strict_types = 1); |
2: | |
3: | namespace PHPStan\Analyser; |
4: | |
5: | use PhpParser\Node\Scalar\LNumber; |
6: | use PhpParser\Node\Stmt; |
7: | |
8: | |
9: | |
10: | |
11: | |
12: | class StatementResult |
13: | { |
14: | |
15: | |
16: | |
17: | |
18: | |
19: | |
20: | |
21: | public function __construct( |
22: | private MutatingScope $scope, |
23: | private bool $hasYield, |
24: | private bool $isAlwaysTerminating, |
25: | private array $exitPoints, |
26: | private array $throwPoints, |
27: | private array $impurePoints, |
28: | private array $endStatements = [], |
29: | ) |
30: | { |
31: | } |
32: | |
33: | public function getScope(): MutatingScope |
34: | { |
35: | return $this->scope; |
36: | } |
37: | |
38: | public function hasYield(): bool |
39: | { |
40: | return $this->hasYield; |
41: | } |
42: | |
43: | public function isAlwaysTerminating(): bool |
44: | { |
45: | return $this->isAlwaysTerminating; |
46: | } |
47: | |
48: | public function filterOutLoopExitPoints(): self |
49: | { |
50: | if (!$this->isAlwaysTerminating) { |
51: | return $this; |
52: | } |
53: | |
54: | foreach ($this->exitPoints as $exitPoint) { |
55: | $statement = $exitPoint->getStatement(); |
56: | if (!$statement instanceof Stmt\Break_ && !$statement instanceof Stmt\Continue_) { |
57: | continue; |
58: | } |
59: | |
60: | $num = $statement->num; |
61: | if (!$num instanceof LNumber) { |
62: | return new self($this->scope, $this->hasYield, false, $this->exitPoints, $this->throwPoints, $this->impurePoints); |
63: | } |
64: | |
65: | if ($num->value !== 1) { |
66: | continue; |
67: | } |
68: | |
69: | return new self($this->scope, $this->hasYield, false, $this->exitPoints, $this->throwPoints, $this->impurePoints); |
70: | } |
71: | |
72: | return $this; |
73: | } |
74: | |
75: | |
76: | |
77: | |
78: | public function getExitPoints(): array |
79: | { |
80: | return $this->exitPoints; |
81: | } |
82: | |
83: | |
84: | |
85: | |
86: | |
87: | public function getExitPointsByType(string $stmtClass): array |
88: | { |
89: | $exitPoints = []; |
90: | foreach ($this->exitPoints as $exitPoint) { |
91: | $statement = $exitPoint->getStatement(); |
92: | if (!$statement instanceof $stmtClass) { |
93: | continue; |
94: | } |
95: | |
96: | $value = $statement->num; |
97: | if ($value === null) { |
98: | $exitPoints[] = $exitPoint; |
99: | continue; |
100: | } |
101: | |
102: | if (!$value instanceof LNumber) { |
103: | $exitPoints[] = $exitPoint; |
104: | continue; |
105: | } |
106: | |
107: | $value = $value->value; |
108: | if ($value !== 1) { |
109: | continue; |
110: | } |
111: | |
112: | $exitPoints[] = $exitPoint; |
113: | } |
114: | |
115: | return $exitPoints; |
116: | } |
117: | |
118: | |
119: | |
120: | |
121: | public function getExitPointsForOuterLoop(): array |
122: | { |
123: | $exitPoints = []; |
124: | foreach ($this->exitPoints as $exitPoint) { |
125: | $statement = $exitPoint->getStatement(); |
126: | if (!$statement instanceof Stmt\Continue_ && !$statement instanceof Stmt\Break_) { |
127: | $exitPoints[] = $exitPoint; |
128: | continue; |
129: | } |
130: | if ($statement->num === null) { |
131: | continue; |
132: | } |
133: | if (!$statement->num instanceof LNumber) { |
134: | continue; |
135: | } |
136: | $value = $statement->num->value; |
137: | if ($value === 1) { |
138: | continue; |
139: | } |
140: | |
141: | $newNode = null; |
142: | if ($value > 2) { |
143: | $newNode = new LNumber($value - 1); |
144: | } |
145: | if ($statement instanceof Stmt\Continue_) { |
146: | $newStatement = new Stmt\Continue_($newNode); |
147: | } else { |
148: | $newStatement = new Stmt\Break_($newNode); |
149: | } |
150: | |
151: | $exitPoints[] = new StatementExitPoint($newStatement, $exitPoint->getScope()); |
152: | } |
153: | |
154: | return $exitPoints; |
155: | } |
156: | |
157: | |
158: | |
159: | |
160: | public function getThrowPoints(): array |
161: | { |
162: | return $this->throwPoints; |
163: | } |
164: | |
165: | |
166: | |
167: | |
168: | public function getImpurePoints(): array |
169: | { |
170: | return $this->impurePoints; |
171: | } |
172: | |
173: | |
174: | |
175: | |
176: | |
177: | |
178: | |
179: | |
180: | |
181: | |
182: | |
183: | |
184: | |
185: | |
186: | |
187: | |
188: | |
189: | public function getEndStatements(): array |
190: | { |
191: | return $this->endStatements; |
192: | } |
193: | |
194: | } |
195: | |