1010namespace SebastianBergmann \CodeCoverage \StaticAnalysis ;
1111
1212use function array_diff_key ;
13- use function array_search ;
13+ use function assert ;
1414use function count ;
1515use function current ;
1616use function end ;
2727 */
2828final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
2929{
30- private $ nextBranch = 1 ;
30+ private $ nextBranch = 0 ;
3131
3232 /**
3333 * @var string
@@ -50,59 +50,58 @@ public function enterNode(Node $node): void
5050 {
5151 if ($ node instanceof Node \Stmt \Declare_ ||
5252 $ node instanceof Node \Stmt \DeclareDeclare ||
53+ $ node instanceof Node \Stmt \Else_ ||
54+ $ node instanceof Node \Stmt \Finally_ ||
5355 $ node instanceof Node \Stmt \Interface_ ||
56+ $ node instanceof Node \Stmt \Label ||
5457 $ node instanceof Node \Stmt \Namespace_ ||
5558 $ node instanceof Node \Stmt \Nop ||
59+ $ node instanceof Node \Stmt \Switch_ ||
60+ $ node instanceof Node \Stmt \Throw_ ||
61+ $ node instanceof Node \Stmt \TryCatch ||
5662 $ node instanceof Node \Stmt \Use_ ||
5763 $ node instanceof Node \Stmt \UseUse ||
5864 $ node instanceof Node \Expr \Variable ||
65+ $ node instanceof Node \Const_ ||
66+ $ node instanceof Node \Identifier ||
5967 $ node instanceof Node \Name ||
6068 $ node instanceof Node \Param ||
61- $ node instanceof Node \Const_ ||
62- $ node instanceof Node \Scalar ||
63- $ node instanceof Node \Identifier
69+ $ node instanceof Node \Scalar
6470 ) {
6571 return ;
6672 }
6773
68- if ($ node instanceof Node \Stmt \Class_ ||
74+ if ($ node instanceof Node \Stmt \Function_ ||
75+ $ node instanceof Node \Stmt \Class_ ||
76+ $ node instanceof Node \Stmt \ClassMethod ||
77+ $ node instanceof Node \Expr \Closure ||
6978 $ node instanceof Node \Stmt \Trait_
7079 ) {
71- foreach ($ node ->stmts as $ stmt ) {
72- if ($ stmt instanceof Node \Stmt \ClassMethod ||
73- $ stmt instanceof Node \Stmt \Nop
74- ) {
75- continue ;
76- }
77-
78- foreach (range ($ stmt ->getStartLine (), $ stmt ->getEndLine ()) as $ line ) {
79- $ this ->unsets [$ line ] = true ;
80+ $ isConcreteClassLike = $ node instanceof Node \Stmt \Class_ || $ node instanceof Node \Stmt \Trait_;
81+
82+ if (null !== $ node ->stmts ) {
83+ foreach ($ node ->stmts as $ stmt ) {
84+ if ($ stmt instanceof Node \Stmt \Nop) {
85+ continue ;
86+ }
87+
88+ foreach (range ($ stmt ->getStartLine (), $ stmt ->getEndLine ()) as $ line ) {
89+ unset($ this ->executableLinesGroupedByBranch [$ line ]);
90+
91+ if (
92+ $ isConcreteClassLike &&
93+ !$ stmt instanceof Node \Stmt \ClassMethod
94+ ) {
95+ $ this ->unsets [$ line ] = true ;
96+ }
97+ }
8098 }
8199 }
82100
83- return ;
84- }
85-
86- if ($ node instanceof Node \Expr \ArrowFunction) {
87- $ startLine = max (
88- $ node ->getStartLine () + 1 ,
89- $ node ->expr ->getStartLine ()
90- );
91- $ endLine = $ node ->expr ->getEndLine ();
92-
93- if ($ endLine < $ startLine ) {
101+ if ($ isConcreteClassLike ) {
94102 return ;
95103 }
96104
97- $ this ->setLineBranch ($ startLine , $ endLine , ++$ this ->nextBranch );
98-
99- return ;
100- }
101-
102- if ($ node instanceof Node \Stmt \Function_ ||
103- $ node instanceof Node \Stmt \ClassMethod ||
104- $ node instanceof Node \Expr \Closure
105- ) {
106105 $ hasEmptyBody = [] === $ node ->stmts ||
107106 null === $ node ->stmts ||
108107 (
@@ -120,22 +119,22 @@ public function enterNode(Node $node): void
120119 return ;
121120 }
122121
123- if ($ node instanceof Node \Expr \Closure &&
124- $ node ->getEndLine () === $ node ->getStartLine ()
125- ) {
126- return ;
127- }
128-
129- $ branch = ++$ this ->nextBranch ;
122+ return ;
123+ }
130124
131- foreach ($ node ->stmts as $ stmt ) {
132- if ($ stmt instanceof Node \Stmt \Nop) {
133- continue ;
134- }
125+ if ($ node instanceof Node \Expr \ArrowFunction) {
126+ $ startLine = max (
127+ $ node ->getStartLine () + 1 ,
128+ $ node ->expr ->getStartLine ()
129+ );
130+ $ endLine = $ node ->expr ->getEndLine ();
135131
136- $ this ->setLineBranch ($ stmt ->getStartLine (), $ stmt ->getEndLine (), $ branch );
132+ if ($ endLine < $ startLine ) {
133+ return ;
137134 }
138135
136+ $ this ->setLineBranch ($ startLine , $ endLine , ++$ this ->nextBranch );
137+
139138 return ;
140139 }
141140
@@ -163,87 +162,80 @@ public function enterNode(Node $node): void
163162
164163 if ($ node instanceof Node \Stmt \If_ ||
165164 $ node instanceof Node \Stmt \ElseIf_ ||
166- $ node instanceof Node \Stmt \Else_ ||
167- $ node instanceof Node \Stmt \Case_ ||
168- $ node instanceof Node \Stmt \For_ ||
169- $ node instanceof Node \Stmt \Foreach_ ||
170- $ node instanceof Node \Stmt \While_ ||
171- $ node instanceof Node \Stmt \TryCatch ||
172- $ node instanceof Node \Stmt \Catch_ ||
173- $ node instanceof Node \Stmt \Finally_
165+ $ node instanceof Node \Stmt \Case_
174166 ) {
175- $ incrementNextBranch = false ;
167+ if (null === $ node ->cond ) {
168+ return ;
169+ }
176170
177- if (isset ($ this ->executableLinesGroupedByBranch [$ node ->getStartLine ()])) {
178- $ stmtBranch = 1 + $ this ->executableLinesGroupedByBranch [$ node ->getStartLine ()];
171+ $ this ->setLineBranch (
172+ $ node ->cond ->getStartLine (),
173+ $ node ->cond ->getStartLine (),
174+ ++$ this ->nextBranch
175+ );
179176
180- if (false !== array_search ($ stmtBranch , $ this ->executableLinesGroupedByBranch , true )) {
181- $ stmtBranch = 1 + $ this ->nextBranch ;
182- $ incrementNextBranch = true ;
183- }
184- } else {
185- $ stmtBranch = 1 + $ this ->nextBranch ;
186- $ incrementNextBranch = true ;
187- }
177+ return ;
178+ }
179+
180+ if ($ node instanceof Node \Stmt \For_) {
181+ $ startLine = null ;
182+ $ endLine = null ;
188183
189- $ endLine = $ node ->getEndLine ();
184+ if ([] !== $ node ->init ) {
185+ $ startLine = $ node ->init [0 ]->getStartLine ();
186+ end ($ node ->init );
187+ $ endLine = current ($ node ->init )->getEndLine ();
188+ reset ($ node ->init );
189+ }
190190
191- if ($ node instanceof Node \Stmt \If_) {
192- if ([] !== $ node ->elseifs ) {
193- $ endLine = $ node ->elseifs [0 ]->getStartLine ();
194- } elseif (null !== $ node ->else ) {
195- $ endLine = $ node ->else ->getStartLine ();
191+ if ([] !== $ node ->cond ) {
192+ if (null === $ startLine ) {
193+ $ startLine = $ node ->cond [0 ]->getStartLine ();
196194 }
195+ end ($ node ->cond );
196+ $ endLine = current ($ node ->cond )->getEndLine ();
197+ reset ($ node ->cond );
197198 }
198199
199- if (!isset ($ this ->executableLinesGroupedByBranch [$ node ->getStartLine ()])) {
200- $ this ->setLineBranch ($ node ->getStartLine (), $ endLine , 1 );
200+ if ([] !== $ node ->loop ) {
201+ if (null === $ startLine ) {
202+ $ startLine = $ node ->loop [0 ]->getStartLine ();
203+ }
204+ end ($ node ->loop );
205+ $ endLine = current ($ node ->loop )->getEndLine ();
206+ reset ($ node ->loop );
201207 }
202208
203- if ([] === $ node -> stmts ) {
209+ if (null === $ startLine || null === $ endLine ) {
204210 return ;
205211 }
206212
207- $ contentStart = max (
208- $ node ->getStartLine () + 1 ,
209- $ node ->stmts [0 ]->getStartLine ()
213+ $ this ->setLineBranch (
214+ $ startLine ,
215+ $ endLine ,
216+ ++$ this ->nextBranch
210217 );
211- $ contentEnd = $ endLine ;
212-
213- if (
214- $ node instanceof Node \Stmt \Catch_ ||
215- $ node instanceof Node \Stmt \Finally_
216- ) {
217- $ contentStart = $ node ->getStartLine ();
218- }
219218
220- if ($ node instanceof Node \Stmt \Case_) {
221- $ contentEnd ++;
222- }
223-
224- end ($ node ->stmts );
225- $ lastNode = current ($ node ->stmts );
226- reset ($ node ->stmts );
227-
228- if (
229- $ lastNode instanceof Node \Stmt \Nop ||
230- $ lastNode instanceof Node \Stmt \Break_
231- ) {
232- $ contentEnd = $ lastNode ->getEndLine () + 1 ;
233- }
219+ return ;
220+ }
234221
235- if (1 > ($ contentEnd - $ contentStart )) {
236- return ;
237- }
222+ if ($ node instanceof Node \Stmt \Foreach_) {
223+ $ this ->setLineBranch (
224+ $ node ->expr ->getStartLine (),
225+ $ node ->valueVar ->getEndLine (),
226+ ++$ this ->nextBranch
227+ );
238228
239- if ($ incrementNextBranch ) {
240- $ this ->nextBranch ++;
241- }
229+ return ;
230+ }
242231
232+ if ($ node instanceof Node \Stmt \While_ ||
233+ $ node instanceof Node \Stmt \Do_
234+ ) {
243235 $ this ->setLineBranch (
244- $ contentStart ,
245- $ contentEnd - 1 ,
246- $ stmtBranch
236+ $ node -> cond -> getStartLine () ,
237+ $ node -> cond -> getEndLine () ,
238+ ++ $ this -> nextBranch
247239 );
248240
249241 return ;
@@ -261,43 +253,38 @@ public function enterNode(Node $node): void
261253 return ;
262254 }
263255
264- if (
265- $ node instanceof Node \Stmt \Return_ ||
266- $ node instanceof Node \Stmt \Continue_ ||
267- $ node instanceof Node \Stmt \Break_ ||
268- $ node instanceof Node \Stmt \Goto_ ||
269- $ node instanceof Node \Stmt \Throw_ ||
270- $ node instanceof Node \Stmt \Label ||
271- $ node instanceof Node \Expr \CallLike
272- ) {
273- $ returnBranch = $ this ->executableLinesGroupedByBranch [$ node ->getStartLine ()];
274- $ returnEndLine = $ node ->getEndLine ();
275- $ nextBranch = null ;
256+ if ($ node instanceof Node \Stmt \Catch_) {
257+ assert ([] !== $ node ->types );
258+ $ startLine = $ node ->types [0 ]->getStartLine ();
259+ end ($ node ->types );
260+ $ endLine = current ($ node ->types )->getEndLine ();
276261
277- if ($ node instanceof Node \Stmt \Label) {
278- $ returnEndLine = $ node ->getStartLine () - 1 ;
279- }
280-
281- foreach ($ this ->executableLinesGroupedByBranch as $ line => $ branch ) {
282- if ($ line <= $ returnEndLine || $ branch !== $ returnBranch ) {
283- continue ;
284- }
262+ $ this ->setLineBranch (
263+ $ startLine ,
264+ $ endLine ,
265+ ++$ this ->nextBranch
266+ );
285267
286- if (null === $ nextBranch ) {
287- $ nextBranch = ++$ this ->nextBranch ;
288- }
268+ return ;
269+ }
289270
290- $ this ->executableLinesGroupedByBranch [$ line ] = $ nextBranch ;
271+ if ($ node instanceof Node \Expr \CallLike) {
272+ if (isset ($ this ->executableLinesGroupedByBranch [$ node ->getStartLine ()])) {
273+ $ branch = $ this ->executableLinesGroupedByBranch [$ node ->getStartLine ()];
274+ } else {
275+ $ branch = ++$ this ->nextBranch ;
291276 }
292277
278+ $ this ->setLineBranch ($ node ->getStartLine (), $ node ->getEndLine (), $ branch );
279+
293280 return ;
294281 }
295282
296283 if (isset ($ this ->executableLinesGroupedByBranch [$ node ->getStartLine ()])) {
297284 return ;
298285 }
299286
300- $ this ->setLineBranch ($ node ->getStartLine (), $ node ->getEndLine (), 1 );
287+ $ this ->setLineBranch ($ node ->getStartLine (), $ node ->getEndLine (), ++ $ this -> nextBranch );
301288 }
302289
303290 public function afterTraverse (array $ nodes ): void
0 commit comments