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