Test Setup Failed
Push — test ( 528f91...abcbcc )
by Jonathan
03:20
created

CallFinder::getFunctionCalls()   D

Complexity

Conditions 49
Paths 24

Size

Total Lines 239
Code Lines 146

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 49
eloc 146
nc 24
nop 3
dl 0
loc 239
rs 4.1818
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Kint;
4
5
class CallFinder
0 ignored issues
show
Coding Style introduced by
CallFinder does not seem to conform to the naming convention (Utils?$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
6
{
7
    private static $ignore = array(
8
        T_CLOSE_TAG => true,
9
        T_COMMENT => true,
10
        T_DOC_COMMENT => true,
11
        T_INLINE_HTML => true,
12
        T_OPEN_TAG => true,
13
        T_OPEN_TAG_WITH_ECHO => true,
14
        T_WHITESPACE => true,
15
    );
16
17
    /**
18
     * Things we need to do specially for operator tokens:
19
     * - Refuse to strip spaces around them
20
     * - Wrap the access path in parentheses if there
21
     *   are any of these in the final short parameter.
22
     */
23
    private static $operator = array(
24
        T_AND_EQUAL => true,
25
        T_BOOLEAN_AND => true,
26
        T_BOOLEAN_OR => true,
27
        T_ARRAY_CAST => true,
28
        T_BOOL_CAST => true,
29
        T_CLONE => true,
30
        T_CONCAT_EQUAL => true,
31
        T_DEC => true,
32
        T_DIV_EQUAL => true,
33
        T_DOUBLE_CAST => true,
34
        T_INC => true,
35
        T_INCLUDE => true,
36
        T_INCLUDE_ONCE => true,
37
        T_INSTANCEOF => true,
38
        T_INT_CAST => true,
39
        T_IS_EQUAL => true,
40
        T_IS_GREATER_OR_EQUAL => true,
41
        T_IS_IDENTICAL => true,
42
        T_IS_NOT_EQUAL => true,
43
        T_IS_NOT_IDENTICAL => true,
44
        T_IS_SMALLER_OR_EQUAL => true,
45
        T_LOGICAL_AND => true,
46
        T_LOGICAL_OR => true,
47
        T_LOGICAL_XOR => true,
48
        T_MINUS_EQUAL => true,
49
        T_MOD_EQUAL => true,
50
        T_MUL_EQUAL => true,
51
        T_NEW => true,
52
        T_OBJECT_CAST => true,
53
        T_OR_EQUAL => true,
54
        T_PLUS_EQUAL => true,
55
        T_REQUIRE => true,
56
        T_REQUIRE_ONCE => true,
57
        T_SL => true,
58
        T_SL_EQUAL => true,
59
        T_SR => true,
60
        T_SR_EQUAL => true,
61
        T_STRING_CAST => true,
62
        T_UNSET_CAST => true,
63
        T_XOR_EQUAL => true,
64
        '!' => true,
65
        '%' => true,
66
        '&' => true,
67
        '*' => true,
68
        '+' => true,
69
        '-' => true,
70
        '.' => true,
71
        '/' => true,
72
        ':' => true,
73
        '<' => true,
74
        '=' => true,
75
        '>' => true,
76
        '?' => true,
77
        '^' => true,
78
        '|' => true,
79
        '~' => true,
80
    );
81
82
    private static $strip = array(
83
        '(' => true,
84
        ')' => true,
85
        '[' => true,
86
        ']' => true,
87
        '{' => true,
88
        '}' => true,
89
        T_OBJECT_OPERATOR => true,
90
        T_DOUBLE_COLON => true,
91
        T_NS_SEPARATOR => true,
92
    );
93
94
    private static $identifier = array(
95
        T_DOUBLE_COLON => true,
96
        T_STRING => true,
97
        T_NS_SEPARATOR => true,
98
    );
99
100
    public static function getFunctionCalls($source, $line, $function)
101
    {
102
        static $up = array(
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $up. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
103
            '(' => true,
104
            '[' => true,
105
            '{' => true,
106
            T_CURLY_OPEN => true,
107
            T_DOLLAR_OPEN_CURLY_BRACES => true,
108
        );
109
        static $down = array(
110
            ')' => true,
111
            ']' => true,
112
            '}' => true,
113
        );
114
        static $modifiers = array(
115
            '!' => true,
116
            '@' => true,
117
            '~' => true,
118
            '+' => true,
119
            '-' => true,
120
        );
121
122
        if (KINT_PHP56) {
123
            self::$operator[T_POW] = true;
124
            self::$operator[T_POW_EQUAL] = true;
125
        }
126
127
        if (KINT_PHP70) {
128
            self::$operator[T_SPACESHIP] = true;
129
        }
130
131
        $tokens = token_get_all($source);
132
        $cursor = 1;
133
        $function_calls = array();
0 ignored issues
show
Coding Style introduced by
$function_calls does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
134
        $prev_tokens = array(null, null, null);
0 ignored issues
show
Coding Style introduced by
$prev_tokens does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
135
136
        if (is_array($function)) {
137
            $class = explode('\\', $function[0]);
138
            $class = strtolower(end($class));
139
            $function = strtolower($function[1]);
140
        } else {
141
            $class = null;
142
            $function = strtolower($function);
143
        }
144
145
        // Loop through tokens
146
        foreach ($tokens as $index => $token) {
147
            if (!is_array($token)) {
148
                continue;
149
            }
150
151
            // Count newlines for line number instead of using $token[2]
152
            // since certain situations (String tokens after whitespace) may
153
            // not have the correct line number unless you do this manually
154
            $cursor += substr_count($token[1], "\n");
155
            if ($cursor > $line) {
156
                break;
157
            }
158
159
            // Store the last real tokens for later
160
            if (isset(self::$ignore[$token[0]])) {
161
                continue;
162
            } else {
163
                $prev_tokens = array($prev_tokens[1], $prev_tokens[2], $token);
0 ignored issues
show
Coding Style introduced by
$prev_tokens does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
164
            }
165
166
            // Check if it's the right type to be the function we're looking for
167
            if ($token[0] !== T_STRING || strtolower($token[1]) !== $function) {
168
                continue;
169
            }
170
171
            // Check if it's a function call
172
            $nextReal = self::realTokenIndex($tokens, $index);
173
            if (!isset($nextReal, $tokens[$nextReal]) || $tokens[$nextReal] !== '(') {
174
                continue;
175
            }
176
177
            // Check if it matches the signature
178
            if ($class === null) {
179
                if ($prev_tokens[1] && in_array($prev_tokens[1][0], array(T_DOUBLE_COLON, T_OBJECT_OPERATOR))) {
0 ignored issues
show
Coding Style introduced by
$prev_tokens does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
180
                    continue;
181
                }
182
            } else {
183
                if (!$prev_tokens[1] || $prev_tokens[1][0] !== T_DOUBLE_COLON) {
0 ignored issues
show
Coding Style introduced by
$prev_tokens does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
184
                    continue;
185
                }
186
187
                if (!$prev_tokens[0] || $prev_tokens[0][0] !== T_STRING || strtolower($prev_tokens[0][1]) !== $class) {
0 ignored issues
show
Coding Style introduced by
$prev_tokens does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
188
                    continue;
189
                }
190
            }
191
192
            $inner_cursor = $cursor;
0 ignored issues
show
Coding Style introduced by
$inner_cursor does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
193
            $depth = 0; // The depth respective to the function call
194
            $offset = 1; // The offset from the function call
195
            $instring = false; // Whether we're in a string or not
196
            $realtokens = false; // Whether the string contains anything meaningful or not
197
            $params = array(); // All our collected parameters
198
            $shortparam = array(); // The short version of the parameter
199
            $param_start = 1; // The distance to the start of the parameter
0 ignored issues
show
Coding Style introduced by
$param_start does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
200
201
            // Loop through the following tokens until the function call ends
202
            while (isset($tokens[$index + $offset])) {
203
                $token = $tokens[$index + $offset];
204
205
                // Ensure that the $inner_cursor is correct and
206
                // that $token is either a T_ constant or a string
207
                if (is_array($token)) {
208
                    $inner_cursor += substr_count($token[1], "\n");
0 ignored issues
show
Coding Style introduced by
$inner_cursor does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
209
                }
210
211
                if (!isset(self::$ignore[$token[0]]) && !isset($down[$token[0]])) {
212
                    $realtokens = true;
213
                }
214
215
                // If it's a token that makes us to up a level, increase the depth
216
                if (isset($up[$token[0]])) {
217
                    // If this is the first paren set the start of the param to just after it
218
                    if ($depth === 0) {
219
                        $param_start = $offset + 1;
0 ignored issues
show
Coding Style introduced by
$param_start does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
220
                        $realtokens = false;
221
                    } elseif ($depth === 1) {
222
                        $shortparam[] = $token;
223
                        $realtokens = false;
224
                    }
225
226
                    ++$depth;
227
                } elseif (isset($down[$token[0]])) {
228
                    --$depth;
229
230
                    // If this brings us down to the parameter level, and we've had
231
                    // real tokens since going up, fill the $shortparam with an ellipsis
232
                    if ($depth === 1) {
233
                        if ($realtokens) {
234
                            $shortparam[] = '...';
235
                        }
236
                        $shortparam[] = $token;
237
                    }
238
                } elseif ($token[0] === '"') {
239
                    // Strings use the same symbol for up and down, but we can
240
                    // only ever be inside one string, so just use a bool for that
241
                    if ($instring) {
242
                        --$depth;
243
                        if ($depth === 1) {
244
                            $shortparam[] = '...';
245
                        }
246
                    } else {
247
                        ++$depth;
248
                    }
249
250
                    $instring = !$instring;
251
252
                    $shortparam[] = '"';
253
                } elseif ($depth === 1) {
254
                    if ($token[0] === ',') {
255
                        $params[] = array(
256
                            'full' => array_slice($tokens, $index + $param_start, $offset - $param_start),
0 ignored issues
show
Coding Style introduced by
$param_start does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
257
                            'short' => $shortparam,
258
                        );
259
                        $shortparam = array();
260
                        $param_start = $offset + 1;
0 ignored issues
show
Coding Style introduced by
$param_start does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
261
                    } elseif ($token[0] === T_CONSTANT_ENCAPSED_STRING && strlen($token[1]) > 2) {
262
                        $shortparam[] = $token[1][0].'...'.$token[1][0];
263
                    } else {
264
                        $shortparam[] = $token;
265
                    }
266
                }
267
268
                // Depth has dropped to 0 (So we've hit the closing paren)
269
                if ($depth <= 0) {
270
                    if ($realtokens) {
271
                        $params[] = array(
272
                            'full' => array_slice($tokens, $index + $param_start, $offset - $param_start),
0 ignored issues
show
Coding Style introduced by
$param_start does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
273
                            'short' => $shortparam,
274
                        );
275
                    }
276
277
                    break;
278
                }
279
280
                ++$offset;
281
            }
282
283
            // If we're not passed (or at) the line at the end
284
            // of the function call, we're too early so skip it
285
            if ($inner_cursor < $line) {
0 ignored issues
show
Coding Style introduced by
$inner_cursor does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
286
                continue;
287
            }
288
289
            // Format the final output parameters
290
            foreach ($params as &$param) {
291
                $name = self::tokensFormatted($param['short']);
292
                $expression = false;
293
                foreach ($name as $token) {
294
                    if (self::tokenIsOperator($token)) {
295
                        $expression = true;
296
                        break;
297
                    }
298
                }
299
300
                $param = array(
301
                    'name' => self::tokensToString($name),
302
                    'path' => self::tokensToString(self::tokensTrim($param['full'])),
303
                    'expression' => $expression,
304
                );
305
            }
306
307
            // Get the modifiers
308
            $mods = array();
309
            --$index;
310
311
            while (isset($tokens[$index])) {
312
                if (isset(self::$ignore[$tokens[$index][0]])) {
313
                    --$index;
314
                    continue;
315
                } elseif (is_array($tokens[$index]) && empty($mods)) {
316
                    if (isset(self::$identifier[$tokens[$index][0]])) {
317
                        --$index;
318
                        continue;
319
                    } else {
320
                        break;
321
                    }
322
                } elseif (isset($modifiers[$tokens[$index][0]])) {
323
                    $mods[] = $tokens[$index];
324
                    --$index;
325
                    continue;
326
                } else {
327
                    break;
328
                }
329
            }
330
331
            $function_calls[] = array(
0 ignored issues
show
Coding Style introduced by
$function_calls does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
332
                'parameters' => $params,
333
                'modifiers' => $mods,
334
            );
335
        }
336
337
        return $function_calls;
0 ignored issues
show
Coding Style introduced by
$function_calls does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
338
    }
339
340
    private static function realTokenIndex(array $tokens, $index)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
341
    {
342
        ++$index;
343
344
        while (isset($tokens[$index])) {
345
            if (!isset(self::$ignore[$tokens[$index][0]])) {
346
                return $index;
347
            }
348
349
            ++$index;
350
        }
351
352
        return null;
353
    }
354
355
    /**
356
     * We need a separate method to check if tokens are operators because we
357
     * occasionally add "..." to short parameter versions. If we simply check
358
     * for `$token[0]` then "..." will incorrectly match the "." operator.
359
     *
360
     * @param array|string $token The token to check
361
     *
362
     * @return bool
363
     */
364
    private static function tokenIsOperator($token)
0 ignored issues
show
Coding Style introduced by
function tokenIsOperator() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
365
    {
366
        return $token !== '...' && isset(self::$operator[$token[0]]);
367
    }
368
369
    private static function tokensToString(array $tokens)
370
    {
371
        $out = '';
372
373
        foreach ($tokens as $token) {
374
            if (is_string($token)) {
375
                $out .= $token;
376
            } elseif (is_array($token)) {
377
                $out .= $token[1];
378
            }
379
        }
380
381
        return $out;
382
    }
383
384
    private static function tokensTrim(array $tokens)
385
    {
386 View Code Duplication
        foreach ($tokens as $index => $token) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
387
            if (isset(self::$ignore[$token[0]])) {
388
                unset($tokens[$index]);
389
            } else {
390
                break;
391
            }
392
        }
393
394
        $tokens = array_reverse($tokens);
395
396 View Code Duplication
        foreach ($tokens as $index => $token) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
397
            if (isset(self::$ignore[$token[0]])) {
398
                unset($tokens[$index]);
399
            } else {
400
                break;
401
            }
402
        }
403
404
        return array_reverse($tokens);
405
    }
406
407
    private static function tokensFormatted(array $tokens)
408
    {
409
        $space = false;
410
411
        $tokens = self::tokensTrim($tokens);
412
413
        $output = array();
414
        $last = null;
415
416
        foreach ($tokens as $index => $token) {
417
            if (isset(self::$ignore[$token[0]])) {
418
                if ($space) {
419
                    continue;
420
                }
421
422
                $next = $tokens[self::realTokenIndex($tokens, $index)];
423
424
                if (isset(self::$strip[$last[0]]) && !self::tokenIsOperator($next)) {
425
                    continue;
426
                } elseif (isset(self::$strip[$next[0]]) && $last && !self::tokenIsOperator($last)) {
427
                    continue;
428
                }
429
430
                $token = ' ';
431
                $space = true;
432
            } else {
433
                $space = false;
434
                $last = $token;
435
            }
436
437
            $output[] = $token;
438
        }
439
440
        return $output;
441
    }
442
}
443