9
9
*/
10
10
namespace SebastianBergmann \CodeCoverage \StaticAnalysis ;
11
11
12
- use function array_unique ;
13
- use function sort ;
14
12
use PhpParser \Node ;
13
+ use PhpParser \Node \Expr \BinaryOp ;
14
+ use PhpParser \Node \Expr \CallLike ;
15
+ use PhpParser \Node \Scalar ;
15
16
use PhpParser \Node \Stmt \Break_ ;
16
17
use PhpParser \Node \Stmt \Case_ ;
17
18
use PhpParser \Node \Stmt \Catch_ ;
26
27
use PhpParser \Node \Stmt \Foreach_ ;
27
28
use PhpParser \Node \Stmt \Goto_ ;
28
29
use PhpParser \Node \Stmt \If_ ;
30
+ use PhpParser \Node \Stmt \Property ;
29
31
use PhpParser \Node \Stmt \Return_ ;
30
32
use PhpParser \Node \Stmt \Switch_ ;
31
33
use PhpParser \Node \Stmt \Throw_ ;
40
42
final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
41
43
{
42
44
/**
43
- * @psalm-var list< int>
45
+ * @psalm-var array<int, int>
44
46
*/
45
47
private array $ executableLines = [];
46
48
49
+ /**
50
+ * @psalm-var array<int, int>
51
+ */
52
+ private $ propertyLines = [];
53
+
47
54
public function enterNode (Node $ node ): void
48
55
{
56
+ $ this ->savePropertyLines ($ node );
57
+
49
58
if (!$ this ->isExecutable ($ node )) {
50
59
return ;
51
60
}
52
61
53
- $ this ->executableLines [] = $ node ->getStartLine ();
62
+ $ line = $ this ->getLine ($ node );
63
+
64
+ if (isset ($ this ->propertyLines [$ line ])) {
65
+ return ;
66
+ }
67
+
68
+ $ this ->executableLines [$ line ] = $ line ;
54
69
}
55
70
56
71
/**
57
- * @psalm-return list< int>
72
+ * @psalm-return array<int, int>
58
73
*/
59
74
public function executableLines (): array
60
75
{
61
- $ executableLines = array_unique ($ this ->executableLines );
76
+ return $ this ->executableLines ;
77
+ }
78
+
79
+ private function savePropertyLines (Node $ node ): void
80
+ {
81
+ if (!$ node instanceof Property && !$ node instanceof Node \Stmt \ClassConst) {
82
+ return ;
83
+ }
62
84
63
- sort ($ executableLines );
85
+ foreach (range ($ node ->getStartLine (), $ node ->getEndLine ()) as $ index ) {
86
+ $ this ->propertyLines [$ index ] = $ index ;
87
+ }
88
+ }
89
+
90
+ private function getLine (Node $ node ): int
91
+ {
92
+ if (
93
+ $ node instanceof Node \Expr \PropertyFetch ||
94
+ $ node instanceof Node \Expr \NullsafePropertyFetch ||
95
+ $ node instanceof Node \Expr \StaticPropertyFetch
96
+ ) {
97
+ return $ node ->getEndLine ();
98
+ }
64
99
65
- return $ executableLines ;
100
+ return $ node -> getStartLine () ;
66
101
}
67
102
68
103
private function isExecutable (Node $ node ): bool
69
104
{
70
- return $ node instanceof Break_ ||
105
+ return $ node instanceof BinaryOp ||
106
+ $ node instanceof Break_ ||
107
+ $ node instanceof CallLike ||
71
108
$ node instanceof Case_ ||
72
109
$ node instanceof Catch_ ||
73
110
$ node instanceof Continue_ ||
@@ -82,10 +119,15 @@ private function isExecutable(Node $node): bool
82
119
$ node instanceof Goto_ ||
83
120
$ node instanceof If_ ||
84
121
$ node instanceof Return_ ||
122
+ $ node instanceof Scalar ||
85
123
$ node instanceof Switch_ ||
86
124
$ node instanceof Throw_ ||
87
125
$ node instanceof TryCatch ||
88
126
$ node instanceof Unset_ ||
127
+ $ node instanceof Node \Expr \Assign ||
128
+ $ node instanceof Node \Expr \PropertyFetch ||
129
+ $ node instanceof Node \Expr \NullsafePropertyFetch ||
130
+ $ node instanceof Node \Expr \StaticPropertyFetch ||
89
131
$ node instanceof While_;
90
132
}
91
133
}
0 commit comments