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