Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
91.55% |
195 / 213 |
|
84.62% |
22 / 26 |
CRAP | |
0.00% |
0 / 1 |
MethodLinks | |
91.55% |
195 / 213 |
|
84.62% |
22 / 26 |
122.98 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
newEmpty | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getForDim | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
4 | |||
asValueFirstLevel | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
asKeyForForeach | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
setAtDim | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
addKeysLinks | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
asCollapsed | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
mergeWith | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
9 | |||
asMergedWith | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
withAddedOffset | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
asMaybeMovedAtOffset | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
asMergedForAssignment | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
8 | |||
normalize | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
12 | |||
__clone | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
getLinksCollapsing | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
4 | |||
getMethodAndParamTuples | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
7 | |||
isEmpty | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
8 | |||
hasDataForFuncAndParam | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
10 | |||
initializeParamForFunc | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
filterPreservedFlags | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getAllPreservedFlags | |
80.00% |
8 / 10 |
|
0.00% |
0 / 1 |
5.20 | |||
asPreservedTaintednessForFuncParam | |
100.00% |
19 / 19 |
|
100.00% |
1 / 1 |
9 | |||
asFilteredForFuncAndParam | |
86.67% |
13 / 15 |
|
0.00% |
0 / 1 |
6.09 | |||
toString | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
42 | |||
__toString | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php declare( strict_types=1 ); |
2 | |
3 | namespace SecurityCheckPlugin; |
4 | |
5 | use ast\Node; |
6 | use Phan\Language\Element\FunctionInterface; |
7 | |
8 | /** |
9 | * Value object that represents method links. |
10 | * @todo We might store links inside Taintedness, but the memory usage might skyrocket |
11 | */ |
12 | class MethodLinks { |
13 | /** @var LinksSet */ |
14 | private $links; |
15 | |
16 | /** @var self[] */ |
17 | private $dimLinks = []; |
18 | |
19 | /** @var self|null */ |
20 | private $unknownDimLinks; |
21 | |
22 | /** @var LinksSet|null */ |
23 | private $keysLinks; |
24 | |
25 | /** |
26 | * @param LinksSet|null $links |
27 | */ |
28 | public function __construct( LinksSet $links = null ) { |
29 | $this->links = $links ?? new LinksSet(); |
30 | } |
31 | |
32 | /** |
33 | * @return self |
34 | */ |
35 | public static function newEmpty(): self { |
36 | return new self( new LinksSet ); |
37 | } |
38 | |
39 | /** |
40 | * @note This returns a clone |
41 | * @param mixed $dim |
42 | * @return self |
43 | */ |
44 | public function getForDim( $dim ): self { |
45 | if ( !is_scalar( $dim ) ) { |
46 | return $this->asValueFirstLevel()->withAddedOffset( $dim ); |
47 | } |
48 | if ( isset( $this->dimLinks[$dim] ) ) { |
49 | $ret = clone $this->dimLinks[$dim]; |
50 | $ret->mergeWith( $this->unknownDimLinks ?? self::newEmpty() ); |
51 | $ret->links->mergeWith( $this->links ); |
52 | return $ret->withAddedOffset( $dim ); |
53 | } |
54 | $ret = $this->unknownDimLinks ? clone $this->unknownDimLinks : self::newEmpty(); |
55 | $ret->links->mergeWith( $this->links ); |
56 | return $ret->withAddedOffset( $dim ); |
57 | } |
58 | |
59 | /** |
60 | * @return self |
61 | */ |
62 | public function asValueFirstLevel(): self { |
63 | $ret = new self( clone $this->links ); |
64 | $ret->mergeWith( $this->unknownDimLinks ?? self::newEmpty() ); |
65 | foreach ( $this->dimLinks as $links ) { |
66 | $ret->mergeWith( $links ); |
67 | } |
68 | return $ret; |
69 | } |
70 | |
71 | /** |
72 | * @return self |
73 | */ |
74 | public function asKeyForForeach(): self { |
75 | if ( $this->keysLinks ) { |
76 | $links = $this->keysLinks->asMergedWith( $this->links ); |
77 | } else { |
78 | $links = $this->links; |
79 | } |
80 | return new self( $links->asAllMovedToKeys() ); |
81 | } |
82 | |
83 | /** |
84 | * @param mixed $dim |
85 | * @param MethodLinks $links |
86 | */ |
87 | public function setAtDim( $dim, self $links ): void { |
88 | if ( is_scalar( $dim ) ) { |
89 | $this->dimLinks[$dim] = $links; |
90 | } else { |
91 | $this->unknownDimLinks ??= self::newEmpty(); |
92 | $this->unknownDimLinks->mergeWith( $links ); |
93 | } |
94 | } |
95 | |
96 | /** |
97 | * @param LinksSet $links |
98 | */ |
99 | public function addKeysLinks( LinksSet $links ): void { |
100 | if ( !$this->keysLinks ) { |
101 | $this->keysLinks = $links; |
102 | } else { |
103 | $this->keysLinks->mergeWith( $links ); |
104 | } |
105 | } |
106 | |
107 | /** |
108 | * @return self |
109 | */ |
110 | public function asCollapsed(): self { |
111 | $ret = new self( $this->links ); |
112 | foreach ( $this->dimLinks as $links ) { |
113 | $ret->mergeWith( $links->asCollapsed() ); |
114 | } |
115 | if ( $this->unknownDimLinks ) { |
116 | $ret->mergeWith( $this->unknownDimLinks->asCollapsed() ); |
117 | } |
118 | return $ret; |
119 | } |
120 | |
121 | /** |
122 | * Merge this object with $other, recursively and without creating a copy. |
123 | * |
124 | * @param self $other |
125 | */ |
126 | public function mergeWith( self $other ): void { |