Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
72.55% |
37 / 51 |
|
57.69% |
15 / 26 |
CRAP | |
0.00% |
0 / 1 |
ReturnObjectsCollectVisitor | |
72.55% |
37 / 51 |
|
57.69% |
15 / 26 |
78.49 | |
0.00% |
0 / 1 |
collectFromNode | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
visitProp | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
visitNullsafeProp | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
visitStaticProp | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
visitVar | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
visitClosureVar | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
handleVarNode | |
66.67% |
4 / 6 |
|
0.00% |
0 / 1 |
3.33 | |||
visitEncapsList | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
visitArray | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
visitArrayElem | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
visitCast | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
visitDim | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
visitUnaryOp | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
visitBinaryOp | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
visitConditional | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
visitCall | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
visitMethodCall | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
visitStaticCall | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
visitNullsafeMethodCall | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
handleCall | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
visitPreDec | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
visitPreInc | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
visitPostDec | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
visitPostInc | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
handleIncOrDec | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
handleReturnedObject | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace SecurityCheckPlugin; |
4 | |
5 | use ast\Node; |
6 | use Phan\Exception\IssueException; |
7 | use Phan\Exception\NodeException; |
8 | use Phan\Language\Element\TypedElementInterface; |
9 | use Phan\Language\Element\Variable; |
10 | use Phan\PluginV3\PluginAwareBaseAnalysisVisitor; |
11 | |
12 | /** |
13 | * Given a return statements, return a list of phan objects that are returned by it. |
14 | * |
15 | * @todo This should also do what matchTaintToParam currently does |
16 | */ |
17 | class ReturnObjectsCollectVisitor extends PluginAwareBaseAnalysisVisitor { |
18 | use TaintednessBaseVisitor; |
19 | |
20 | /** @var TypedElementInterface[] */ |
21 | private $buffer = []; |
22 | |
23 | /** |
24 | * @param Node $node |
25 | * @return TypedElementInterface[] |
26 | */ |
27 | public function collectFromNode( Node $node ): array { |
28 | assert( $node->kind === \ast\AST_RETURN ); |
29 | $this->buffer = []; |
30 | $this( $node->children['expr'] ); |
31 | return $this->buffer; |
32 | } |
33 | |
34 | /** |
35 | * @inheritDoc |
36 | */ |
37 | public function visitProp( Node $node ): void { |
38 | $this->handleReturnedObject( $this->getPropFromNode( $node ) ); |
39 | } |
40 | |
41 | /** |
42 | * @inheritDoc |
43 | */ |
44 | public function visitNullsafeProp( Node $node ): void { |
45 | $this->handleReturnedObject( $this->getPropFromNode( $node ) ); |
46 | } |
47 | |
48 | /** |
49 | * @inheritDoc |
50 | */ |
51 | public function visitStaticProp( Node $node ): void { |
52 | $this->handleReturnedObject( $this->getPropFromNode( $node ) ); |
53 | } |
54 | |
55 | /** |
56 | * @inheritDoc |
57 | */ |
58 | public function visitVar( Node $node ): void { |
59 | $this->handleVarNode( $node ); |
60 | } |
61 | |
62 | /** |
63 | * @inheritDoc |
64 | */ |
65 | public function visitClosureVar( Node $node ): void { |
66 | // FIXME Is this needed? |
67 | $this->handleVarNode( $node ); |
68 | } |
69 | |
70 | /** |
71 | * @param Node $node |
72 | */ |
73 | private function handleVarNode( Node $node ): void { |
74 | $cn = $this->getCtxN( $node ); |
75 | if ( Variable::isHardcodedGlobalVariableWithName( $cn->getVariableName() ) ) { |
76 | return; |
77 | } |
78 | try { |
79 | $this->handleReturnedObject( $cn->getVariable() ); |
80 | } catch ( NodeException | IssueException $e ) { |
81 | $this->debug( __METHOD__, "variable not in scope?? " . $this->getDebugInfo( $e ) ); |
82 | } |
83 | } |
84 | |
85 | /** |
86 | * @inheritDoc |
87 | */ |
88 | public function visitEncapsList( Node $node ): void { |
89 | foreach ( $node->children as $child ) { |
90 | if ( $child instanceof Node ) { |
91 | $this( $child ); |
92 | } |
93 | } |
94 | } |
95 | |
96 | /** |
97 | * @inheritDoc |
98 | */ |
99 | public function visitArray( Node $node ): void { |
100 | foreach ( $node->children as $child ) { |
101 | if ( $child instanceof Node ) { |
102 | $this( $child ); |
103 | } |
104 | } |
105 | } |
106 | |
107 | /** |
108 | * @inheritDoc |
109 | */ |
110 | public function visitArrayElem( Node $node ): void { |
111 | if ( $node->children['key'] instanceof Node ) { |
112 | $this( $node->children['key'] ); |
113 | } |
114 | if ( $node->children['value'] instanceof Node ) { |
115 | $this( $node->children['value'] ); |
116 | } |
117 | } |
118 | |
119 | /** |
120 | * @inheritDoc |
121 | */ |
122 | public function visitCast( Node $node ): void { |
123 | // Future todo might be to ignore casts to ints, since |
124 | // such things should be safe. Unclear if that makes |
125 | // sense in all circumstances. |
126 | if ( $node->children['expr'] instanceof Node ) { |
127 | $this( $node->children['expr'] ); |
128 | } |
129 | } |
130 | |
131 | /** |
132 | * @inheritDoc |
133 | */ |
134 | public function visitDim( Node $node ): void { |
135 | if ( $node->children['expr'] instanceof Node ) { |
136 | // For now just consider the outermost array. |
137 | // FIXME. doesn't handle tainted array keys! |
138 | $this( $node->children['expr'] ); |
139 | } |
140 | } |
141 | |
142 | /** |
143 | * @inheritDoc |
144 | */ |
145 | public function visitUnaryOp( Node $node ): void { |
146 | if ( $node->children['expr'] instanceof Node ) { |
147 | $this( $node->children['expr'] ); |
148 | } |
149 | } |
150 | |
151 | /** |
152 | * @inheritDoc |
153 | */ |
154 | public function visitBinaryOp( Node $node ): void { |
155 | if ( $node->children['left'] instanceof Node ) { |
156 | $this( $node->children['left'] ); |
157 | } |
158 | if ( $node->children['right'] instanceof Node ) { |
159 | $this( $node->children['right'] ); |
160 | } |
161 | } |
162 | |
163 | /** |
164 | * @inheritDoc |
165 | */ |
166 | public function visitConditional( Node $node ): void { |
167 | if ( $node->children['true'] instanceof Node ) { |
168 | $this( $node->children['true'] ); |
169 | } |
170 | if ( $node->children['false'] instanceof Node ) { |
171 | $this( $node->children['false'] ); |
172 | } |
173 | } |
174 | |
175 | /** |
176 | * @inheritDoc |
177 | */ |
178 | public function visitCall( Node $node ): void { |
179 | $this->handleCall( $node ); |
180 | } |
181 | |
182 | /** |
183 | * @inheritDoc |
184 | */ |
185 | public function visitMethodCall( Node $node ): void { |
186 | $this->handleCall( $node ); |
187 | } |
188 | |
189 | /** |
190 | * @inheritDoc |
191 | */ |
192 | public function visitStaticCall( Node $node ): void { |
193 | $this->handleCall( $node ); |
194 | } |
195 | |
196 | /** |
197 | * @inheritDoc |
198 | */ |
199 | public function visitNullsafeMethodCall( Node $node ): void { |
200 | $this->handleCall( $node ); |
201 | } |
202 | |
203 | /** |
204 | * @param Node $node @phan-unused-param |
205 | */ |
206 | private function handleCall( Node $node ): void { |
207 | // TODO If the func being called already has retObjs, we might add them. |
208 | } |
209 | |
210 | /** |
211 | * @inheritDoc |
212 | */ |
213 | public function visitPreDec( Node $node ): void { |
214 | $this->handleIncOrDec( $node ); |
215 | } |
216 | |
217 | /** |
218 | * @inheritDoc |
219 | */ |
220 | public function visitPreInc( Node $node ): void { |
221 | $this->handleIncOrDec( $node ); |
222 | } |
223 | |
224 | /** |
225 | * @inheritDoc |
226 | */ |
227 | public function visitPostDec( Node $node ): void { |
228 | $this->handleIncOrDec( $node ); |
229 | } |
230 | |
231 | /** |
232 | * @inheritDoc |
233 | */ |
234 | public function visitPostInc( Node $node ): void { |
235 | $this->handleIncOrDec( $node ); |
236 | } |
237 | |
238 | /** |
239 | * @param Node $node |
240 | */ |
241 | private function handleIncOrDec( Node $node ): void { |
242 | $children = $node->children; |
243 | assert( count( $children ) === 1 ); |
244 | $this( reset( $children ) ); |
245 | } |
246 | |
247 | /** |
248 | * @param TypedElementInterface|null $el |
249 | */ |
250 | private function handleReturnedObject( ?TypedElementInterface $el ): void { |
251 | if ( $el ) { |
252 | $this->buffer[] = $el; |
253 | } |
254 | } |
255 | } |