Chris@0
|
1 <?php
|
Chris@0
|
2 /**
|
Chris@0
|
3 * This file is part of the VariableAnalysis addon for PHP_CodeSniffer.
|
Chris@0
|
4 *
|
Chris@0
|
5 * @category PHP
|
Chris@0
|
6 * @package PHP_CodeSniffer
|
Chris@0
|
7 * @author Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
|
Chris@0
|
8 * @copyright 2011-2012 Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
|
Chris@0
|
9 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
|
Chris@0
|
10 * @link http://pear.php.net/package/PHP_CodeSniffer
|
Chris@0
|
11 */
|
Chris@0
|
12
|
Chris@17
|
13 namespace DrupalPractice\Sniffs\CodeAnalysis;
|
Chris@17
|
14
|
Chris@17
|
15 use PHP_CodeSniffer\Files\File;
|
Chris@17
|
16 use PHP_CodeSniffer\Sniffs\Sniff;
|
Chris@17
|
17
|
Chris@0
|
18 /**
|
Chris@0
|
19 * Holds details of a scope.
|
Chris@0
|
20 *
|
Chris@0
|
21 * @category PHP
|
Chris@0
|
22 * @package PHP_CodeSniffer
|
Chris@0
|
23 * @author Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
|
Chris@0
|
24 * @copyright 2011-2012 Sam Graham <php-codesniffer-plugins BLAHBLAH illusori.co.uk>
|
Chris@0
|
25 * @link http://pear.php.net/package/PHP_CodeSniffer
|
Chris@0
|
26 */
|
Chris@0
|
27 class ScopeInfo
|
Chris@0
|
28 {
|
Chris@0
|
29 public $owner;
|
Chris@0
|
30 public $opener;
|
Chris@0
|
31 public $closer;
|
Chris@0
|
32 public $variables = array();
|
Chris@0
|
33
|
Chris@0
|
34
|
Chris@0
|
35 /**
|
Chris@0
|
36 * Constructor.
|
Chris@0
|
37 *
|
Chris@0
|
38 * @param int $currScope
|
Chris@0
|
39 */
|
Chris@0
|
40 function __construct($currScope)
|
Chris@0
|
41 {
|
Chris@0
|
42 // TODO: extract opener/closer.
|
Chris@0
|
43 $this->owner = $currScope;
|
Chris@0
|
44
|
Chris@0
|
45 }//end __construct()
|
Chris@0
|
46
|
Chris@0
|
47
|
Chris@0
|
48 }//end class
|
Chris@0
|
49
|
Chris@0
|
50
|
Chris@0
|
51 /**
|
Chris@0
|
52 * Holds details of a variable within a scope.
|
Chris@0
|
53 *
|
Chris@0
|
54 * @category PHP
|
Chris@0
|
55 * @package PHP_CodeSniffer
|
Chris@0
|
56 * @author Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
|
Chris@0
|
57 * @copyright 2011 Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
|
Chris@0
|
58 * @link http://pear.php.net/package/PHP_CodeSniffer
|
Chris@0
|
59 */
|
Chris@0
|
60 class VariableInfo
|
Chris@0
|
61 {
|
Chris@0
|
62 public $name;
|
Chris@0
|
63 /**
|
Chris@0
|
64 * What scope the variable has: local, param, static, global, bound
|
Chris@0
|
65 */
|
Chris@0
|
66 public $scopeType;
|
Chris@0
|
67 public $typeHint;
|
Chris@0
|
68 public $passByReference = false;
|
Chris@0
|
69 public $firstDeclared;
|
Chris@0
|
70 public $firstInitialized;
|
Chris@0
|
71 public $firstRead;
|
Chris@0
|
72 public $ignoreUnused = false;
|
Chris@0
|
73 public $lastAssignment;
|
Chris@0
|
74
|
Chris@0
|
75 static $scopeTypeDescriptions = array(
|
Chris@0
|
76 'local' => 'variable',
|
Chris@0
|
77 'param' => 'function parameter',
|
Chris@0
|
78 'static' => 'static variable',
|
Chris@0
|
79 'global' => 'global variable',
|
Chris@0
|
80 'bound' => 'bound variable',
|
Chris@0
|
81 );
|
Chris@0
|
82
|
Chris@0
|
83
|
Chris@0
|
84 /**
|
Chris@0
|
85 * Constructor.
|
Chris@0
|
86 *
|
Chris@0
|
87 * @param string $varName
|
Chris@0
|
88 */
|
Chris@0
|
89 function __construct($varName)
|
Chris@0
|
90 {
|
Chris@0
|
91 $this->name = $varName;
|
Chris@0
|
92
|
Chris@0
|
93 }//end __construct()
|
Chris@0
|
94
|
Chris@0
|
95
|
Chris@0
|
96 }//end class
|
Chris@0
|
97
|
Chris@0
|
98
|
Chris@0
|
99 /**
|
Chris@0
|
100 * Checks the for undefined function variables.
|
Chris@0
|
101 *
|
Chris@0
|
102 * This sniff checks that all function variables
|
Chris@0
|
103 * are defined in the function body.
|
Chris@0
|
104 *
|
Chris@0
|
105 * @category PHP
|
Chris@0
|
106 * @package PHP_CodeSniffer
|
Chris@0
|
107 * @author Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
|
Chris@0
|
108 * @copyright 2011 Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
|
Chris@0
|
109 * @link http://pear.php.net/package/PHP_CodeSniffer
|
Chris@0
|
110 */
|
Chris@17
|
111 class VariableAnalysisSniff implements Sniff
|
Chris@0
|
112 {
|
Chris@0
|
113 /**
|
Chris@0
|
114 * The current phpcsFile being checked.
|
Chris@0
|
115 *
|
Chris@0
|
116 * @var phpcsFile
|
Chris@0
|
117 */
|
Chris@0
|
118 protected $currentFile = null;
|
Chris@0
|
119
|
Chris@0
|
120 /**
|
Chris@0
|
121 * A list of scopes encountered so far and the variables within them.
|
Chris@0
|
122 */
|
Chris@0
|
123 private $_scopes = array();
|
Chris@0
|
124
|
Chris@0
|
125 /**
|
Chris@0
|
126 * A regexp for matching variable names in double-quoted strings.
|
Chris@0
|
127 */
|
Chris@0
|
128 private $_double_quoted_variable_regexp = '|(?<!\\\\)(?:\\\\{2})*\${?([a-zA-Z0-9_]+)}?|';
|
Chris@0
|
129
|
Chris@0
|
130 /**
|
Chris@0
|
131 * Array of known pass-by-reference functions and the argument(s) which are passed
|
Chris@0
|
132 * by reference, the arguments are numbered starting from 1 and an elipsis '...'
|
Chris@0
|
133 * means all argument numbers after the previous should be considered pass-by-reference.
|
Chris@0
|
134 */
|
Chris@0
|
135 private $_passByRefFunctions = array(
|
Chris@0
|
136 '__soapCall' => array(5),
|
Chris@0
|
137 'addFunction' => array(3),
|
Chris@0
|
138 'addTask' => array(3),
|
Chris@0
|
139 'addTaskBackground' => array(3),
|
Chris@0
|
140 'addTaskHigh' => array(3),
|
Chris@0
|
141 'addTaskHighBackground' => array(3),
|
Chris@0
|
142 'addTaskLow' => array(3),
|
Chris@0
|
143 'addTaskLowBackground' => array(3),
|
Chris@0
|
144 'addTaskStatus' => array(2),
|
Chris@0
|
145 'apc_dec' => array(3),
|
Chris@0
|
146 'apc_fetch' => array(2),
|
Chris@0
|
147 'apc_inc' => array(3),
|
Chris@0
|
148 'areConfusable' => array(3),
|
Chris@0
|
149 'array_multisort' => array(1),
|
Chris@0
|
150 'array_pop' => array(1),
|
Chris@0
|
151 'array_push' => array(1),
|
Chris@0
|
152 'array_replace' => array(1),
|
Chris@0
|
153 'array_replace_recursive' => array(
|
Chris@0
|
154 1,
|
Chris@0
|
155 2,
|
Chris@0
|
156 3,
|
Chris@0
|
157 '...',
|
Chris@0
|
158 ),
|
Chris@0
|
159 'array_shift' => array(1),
|
Chris@0
|
160 'array_splice' => array(1),
|
Chris@0
|
161 'array_unshift' => array(1),
|
Chris@0
|
162 'array_walk' => array(1),
|
Chris@0
|
163 'array_walk_recursive' => array(1),
|
Chris@0
|
164 'arsort' => array(1),
|
Chris@0
|
165 'asort' => array(1),
|
Chris@0
|
166 'asort' => array(1),
|
Chris@0
|
167 'bindColumn' => array(2),
|
Chris@0
|
168 'bindParam' => array(2),
|
Chris@0
|
169 'bind_param' => array(
|
Chris@0
|
170 2,
|
Chris@0
|
171 3,
|
Chris@0
|
172 '...',
|
Chris@0
|
173 ),
|
Chris@0
|
174 'bind_result' => array(
|
Chris@0
|
175 1,
|
Chris@0
|
176 2,
|
Chris@0
|
177 '...',
|
Chris@0
|
178 ),
|
Chris@0
|
179 'call_user_method' => array(2),
|
Chris@0
|
180 'call_user_method_array' => array(2),
|
Chris@0
|
181 'curl_multi_exec' => array(2),
|
Chris@0
|
182 'curl_multi_info_read' => array(2),
|
Chris@0
|
183 'current' => array(1),
|
Chris@0
|
184 'dbplus_curr' => array(2),
|
Chris@0
|
185 'dbplus_first' => array(2),
|
Chris@0
|
186 'dbplus_info' => array(3),
|
Chris@0
|
187 'dbplus_last' => array(2),
|
Chris@0
|
188 'dbplus_next' => array(2),
|
Chris@0
|
189 'dbplus_prev' => array(2),
|
Chris@0
|
190 'dbplus_tremove' => array(3),
|
Chris@0
|
191 'dns_get_record' => array(
|
Chris@0
|
192 3,
|
Chris@0
|
193 4,
|
Chris@0
|
194 ),
|
Chris@0
|
195 'domxml_open_file' => array(3),
|
Chris@0
|
196 'domxml_open_mem' => array(3),
|
Chris@0
|
197 'each' => array(1),
|
Chris@0
|
198 'enchant_dict_quick_check' => array(3),
|
Chris@0
|
199 'end' => array(1),
|
Chris@0
|
200 'ereg' => array(3),
|
Chris@0
|
201 'eregi' => array(3),
|
Chris@0
|
202 'exec' => array(
|
Chris@0
|
203 2,
|
Chris@0
|
204 3,
|
Chris@0
|
205 ),
|
Chris@0
|
206 'exif_thumbnail' => array(
|
Chris@0
|
207 1,
|
Chris@0
|
208 2,
|
Chris@0
|
209 3,
|
Chris@0
|
210 ),
|
Chris@0
|
211 'expect_expectl' => array(3),
|
Chris@0
|
212 'extract' => array(1),
|
Chris@0
|
213 'filter' => array(3),
|
Chris@0
|
214 'flock' => array(
|
Chris@0
|
215 2,
|
Chris@0
|
216 3,
|
Chris@0
|
217 ),
|
Chris@0
|
218 'fscanf' => array(
|
Chris@0
|
219 2,
|
Chris@0
|
220 3,
|
Chris@0
|
221 '...',
|
Chris@0
|
222 ),
|
Chris@0
|
223 'fsockopen' => array(
|
Chris@0
|
224 3,
|
Chris@0
|
225 4,
|
Chris@0
|
226 ),
|
Chris@0
|
227 'ftp_alloc' => array(3),
|
Chris@0
|
228 'get' => array(
|
Chris@0
|
229 2,
|
Chris@0
|
230 3,
|
Chris@0
|
231 ),
|
Chris@0
|
232 'getByKey' => array(4),
|
Chris@0
|
233 'getMulti' => array(2),
|
Chris@0
|
234 'getMultiByKey' => array(3),
|
Chris@0
|
235 'getimagesize' => array(2),
|
Chris@0
|
236 'getmxrr' => array(
|
Chris@0
|
237 2,
|
Chris@0
|
238 3,
|
Chris@0
|
239 ),
|
Chris@0
|
240 'gnupg_decryptverify' => array(3),
|
Chris@0
|
241 'gnupg_verify' => array(4),
|
Chris@0
|
242 'grapheme_extract' => array(5),
|
Chris@0
|
243 'headers_sent' => array(
|
Chris@0
|
244 1,
|
Chris@0
|
245 2,
|
Chris@0
|
246 ),
|
Chris@0
|
247 'http_build_url' => array(4),
|
Chris@0
|
248 'http_get' => array(3),
|
Chris@0
|
249 'http_head' => array(3),
|
Chris@0
|
250 'http_negotiate_charset' => array(2),
|
Chris@0
|
251 'http_negotiate_content_type' => array(2),
|
Chris@0
|
252 'http_negotiate_language' => array(2),
|
Chris@0
|
253 'http_post_data' => array(4),
|
Chris@0
|
254 'http_post_fields' => array(5),
|
Chris@0
|
255 'http_put_data' => array(4),
|
Chris@0
|
256 'http_put_file' => array(4),
|
Chris@0
|
257 'http_put_stream' => array(4),
|
Chris@0
|
258 'http_request' => array(5),
|
Chris@0
|
259 'isSuspicious' => array(2),
|
Chris@0
|
260 'is_callable' => array(3),
|
Chris@0
|
261 'key' => array(1),
|
Chris@0
|
262 'krsort' => array(1),
|
Chris@0
|
263 'ksort' => array(1),
|
Chris@0
|
264 'ldap_get_option' => array(3),
|
Chris@0
|
265 'ldap_parse_reference' => array(3),
|
Chris@0
|
266 'ldap_parse_result' => array(
|
Chris@0
|
267 3,
|
Chris@0
|
268 4,
|
Chris@0
|
269 5,
|
Chris@0
|
270 6,
|
Chris@0
|
271 ),
|
Chris@0
|
272 'localtime' => array(2),
|
Chris@0
|
273 'm_completeauthorizations' => array(2),
|
Chris@0
|
274 'maxdb_stmt_bind_param' => array(
|
Chris@0
|
275 3,
|
Chris@0
|
276 4,
|
Chris@0
|
277 '...',
|
Chris@0
|
278 ),
|
Chris@0
|
279 'maxdb_stmt_bind_result' => array(
|
Chris@0
|
280 2,
|
Chris@0
|
281 3,
|
Chris@0
|
282 '...',
|
Chris@0
|
283 ),
|
Chris@0
|
284 'mb_convert_variables' => array(
|
Chris@0
|
285 3,
|
Chris@0
|
286 4,
|
Chris@0
|
287 '...',
|
Chris@0
|
288 ),
|
Chris@0
|
289 'mb_parse_str' => array(2),
|
Chris@0
|
290 'mqseries_back' => array(
|
Chris@0
|
291 2,
|
Chris@0
|
292 3,
|
Chris@0
|
293 ),
|
Chris@0
|
294 'mqseries_begin' => array(
|
Chris@0
|
295 3,
|
Chris@0
|
296 4,
|
Chris@0
|
297 ),
|
Chris@0
|
298 'mqseries_close' => array(
|
Chris@0
|
299 4,
|
Chris@0
|
300 5,
|
Chris@0
|
301 ),
|
Chris@0
|
302 'mqseries_cmit' => array(
|
Chris@0
|
303 2,
|
Chris@0
|
304 3,
|
Chris@0
|
305 ),
|
Chris@0
|
306 'mqseries_conn' => array(
|
Chris@0
|
307 2,
|
Chris@0
|
308 3,
|
Chris@0
|
309 4,
|
Chris@0
|
310 ),
|
Chris@0
|
311 'mqseries_connx' => array(
|
Chris@0
|
312 2,
|
Chris@0
|
313 3,
|
Chris@0
|
314 4,
|
Chris@0
|
315 5,
|
Chris@0
|
316 ),
|
Chris@0
|
317 'mqseries_disc' => array(
|
Chris@0
|
318 2,
|
Chris@0
|
319 3,
|
Chris@0
|
320 ),
|
Chris@0
|
321 'mqseries_get' => array(
|
Chris@0
|
322 3,
|
Chris@0
|
323 4,
|
Chris@0
|
324 5,
|
Chris@0
|
325 6,
|
Chris@0
|
326 7,
|
Chris@0
|
327 8,
|
Chris@0
|
328 9,
|
Chris@0
|
329 ),
|
Chris@0
|
330 'mqseries_inq' => array(
|
Chris@0
|
331 6,
|
Chris@0
|
332 8,
|
Chris@0
|
333 9,
|
Chris@0
|
334 10,
|
Chris@0
|
335 ),
|
Chris@0
|
336 'mqseries_open' => array(
|
Chris@0
|
337 2,
|
Chris@0
|
338 4,
|
Chris@0
|
339 5,
|
Chris@0
|
340 6,
|
Chris@0
|
341 ),
|
Chris@0
|
342 'mqseries_put' => array(
|
Chris@0
|
343 3,
|
Chris@0
|
344 4,
|
Chris@0
|
345 6,
|
Chris@0
|
346 7,
|
Chris@0
|
347 ),
|
Chris@0
|
348 'mqseries_put1' => array(
|
Chris@0
|
349 2,
|
Chris@0
|
350 3,
|
Chris@0
|
351 4,
|
Chris@0
|
352 6,
|
Chris@0
|
353 7,
|
Chris@0
|
354 ),
|
Chris@0
|
355 'mqseries_set' => array(
|
Chris@0
|
356 9,
|
Chris@0
|
357 10,
|
Chris@0
|
358 ),
|
Chris@0
|
359 'msg_receive' => array(
|
Chris@0
|
360 3,
|
Chris@0
|
361 5,
|
Chris@0
|
362 8,
|
Chris@0
|
363 ),
|
Chris@0
|
364 'msg_send' => array(6),
|
Chris@0
|
365 'mssql_bind' => array(3),
|
Chris@0
|
366 'natcasesort' => array(1),
|
Chris@0
|
367 'natsort' => array(1),
|
Chris@0
|
368 'ncurses_color_content' => array(
|
Chris@0
|
369 2,
|
Chris@0
|
370 3,
|
Chris@0
|
371 4,
|
Chris@0
|
372 ),
|
Chris@0
|
373 'ncurses_getmaxyx' => array(
|
Chris@0
|
374 2,
|
Chris@0
|
375 3,
|
Chris@0
|
376 ),
|
Chris@0
|
377 'ncurses_getmouse' => array(1),
|
Chris@0
|
378 'ncurses_getyx' => array(
|
Chris@0
|
379 2,
|
Chris@0
|
380 3,
|
Chris@0
|
381 ),
|
Chris@0
|
382 'ncurses_instr' => array(1),
|
Chris@0
|
383 'ncurses_mouse_trafo' => array(
|
Chris@0
|
384 1,
|
Chris@0
|
385 2,
|
Chris@0
|
386 ),
|
Chris@0
|
387 'ncurses_mousemask' => array(2),
|
Chris@0
|
388 'ncurses_pair_content' => array(
|
Chris@0
|
389 2,
|
Chris@0
|
390 3,
|
Chris@0
|
391 ),
|
Chris@0
|
392 'ncurses_wmouse_trafo' => array(
|
Chris@0
|
393 2,
|
Chris@0
|
394 3,
|
Chris@0
|
395 ),
|
Chris@0
|
396 'newt_button_bar' => array(1),
|
Chris@0
|
397 'newt_form_run' => array(2),
|
Chris@0
|
398 'newt_get_screen_size' => array(
|
Chris@0
|
399 1,
|
Chris@0
|
400 2,
|
Chris@0
|
401 ),
|
Chris@0
|
402 'newt_grid_get_size' => array(
|
Chris@0
|
403 2,
|
Chris@0
|
404 3,
|
Chris@0
|
405 ),
|
Chris@0
|
406 'newt_reflow_text' => array(
|
Chris@0
|
407 5,
|
Chris@0
|
408 6,
|
Chris@0
|
409 ),
|
Chris@0
|
410 'newt_win_entries' => array(7),
|
Chris@0
|
411 'newt_win_menu' => array(8),
|
Chris@0
|
412 'next' => array(1),
|
Chris@0
|
413 'oci_bind_array_by_name' => array(3),
|
Chris@0
|
414 'oci_bind_by_name' => array(3),
|
Chris@0
|
415 'oci_define_by_name' => array(3),
|
Chris@0
|
416 'oci_fetch_all' => array(2),
|
Chris@0
|
417 'ocifetchinto' => array(2),
|
Chris@0
|
418 'odbc_fetch_into' => array(2),
|
Chris@0
|
419 'openssl_csr_export' => array(2),
|
Chris@0
|
420 'openssl_csr_new' => array(2),
|
Chris@0
|
421 'openssl_open' => array(2),
|
Chris@0
|
422 'openssl_pkcs12_export' => array(2),
|
Chris@0
|
423 'openssl_pkcs12_read' => array(2),
|
Chris@0
|
424 'openssl_pkey_export' => array(2),
|
Chris@0
|
425 'openssl_private_decrypt' => array(2),
|
Chris@0
|
426 'openssl_private_encrypt' => array(2),
|
Chris@0
|
427 'openssl_public_decrypt' => array(2),
|
Chris@0
|
428 'openssl_public_encrypt' => array(2),
|
Chris@0
|
429 'openssl_random_pseudo_bytes' => array(2),
|
Chris@0
|
430 'openssl_seal' => array(
|
Chris@0
|
431 2,
|
Chris@0
|
432 3,
|
Chris@0
|
433 ),
|
Chris@0
|
434 'openssl_sign' => array(2),
|
Chris@0
|
435 'openssl_x509_export' => array(2),
|
Chris@0
|
436 'ovrimos_fetch_into' => array(2),
|
Chris@0
|
437 'parse' => array(
|
Chris@0
|
438 2,
|
Chris@0
|
439 3,
|
Chris@0
|
440 ),
|
Chris@0
|
441 'parseCurrency' => array(
|
Chris@0
|
442 2,
|
Chris@0
|
443 3,
|
Chris@0
|
444 ),
|
Chris@0
|
445 'parse_str' => array(2),
|
Chris@0
|
446 'parsekit_compile_file' => array(2),
|
Chris@0
|
447 'parsekit_compile_string' => array(2),
|
Chris@0
|
448 'passthru' => array(2),
|
Chris@0
|
449 'pcntl_sigprocmask' => array(3),
|
Chris@0
|
450 'pcntl_sigtimedwait' => array(2),
|
Chris@0
|
451 'pcntl_sigwaitinfo' => array(2),
|
Chris@0
|
452 'pcntl_wait' => array(1),
|
Chris@0
|
453 'pcntl_waitpid' => array(2),
|
Chris@0
|
454 'pfsockopen' => array(
|
Chris@0
|
455 3,
|
Chris@0
|
456 4,
|
Chris@0
|
457 ),
|
Chris@0
|
458 'php_check_syntax' => array(2),
|
Chris@0
|
459 'poll' => array(
|
Chris@0
|
460 1,
|
Chris@0
|
461 2,
|
Chris@0
|
462 3,
|
Chris@0
|
463 ),
|
Chris@0
|
464 'preg_filter' => array(5),
|
Chris@0
|
465 'preg_match' => array(3),
|
Chris@0
|
466 'preg_match_all' => array(3),
|
Chris@0
|
467 'preg_replace' => array(5),
|
Chris@0
|
468 'preg_replace_callback' => array(5),
|
Chris@0
|
469 'prev' => array(1),
|
Chris@0
|
470 'proc_open' => array(3),
|
Chris@0
|
471 'query' => array(3),
|
Chris@0
|
472 'queryExec' => array(2),
|
Chris@0
|
473 'reset' => array(1),
|
Chris@0
|
474 'rsort' => array(1),
|
Chris@0
|
475 'settype' => array(1),
|
Chris@0
|
476 'shuffle' => array(1),
|
Chris@0
|
477 'similar_text' => array(3),
|
Chris@0
|
478 'socket_create_pair' => array(4),
|
Chris@0
|
479 'socket_getpeername' => array(
|
Chris@0
|
480 2,
|
Chris@0
|
481 3,
|
Chris@0
|
482 ),
|
Chris@0
|
483 'socket_getsockname' => array(
|
Chris@0
|
484 2,
|
Chris@0
|
485 3,
|
Chris@0
|
486 ),
|
Chris@0
|
487 'socket_recv' => array(2),
|
Chris@0
|
488 'socket_recvfrom' => array(
|
Chris@0
|
489 2,
|
Chris@0
|
490 5,
|
Chris@0
|
491 6,
|
Chris@0
|
492 ),
|
Chris@0
|
493 'socket_select' => array(
|
Chris@0
|
494 1,
|
Chris@0
|
495 2,
|
Chris@0
|
496 3,
|
Chris@0
|
497 ),
|
Chris@0
|
498 'sort' => array(1),
|
Chris@0
|
499 'sortWithSortKeys' => array(1),
|
Chris@0
|
500 'sqlite_exec' => array(3),
|
Chris@0
|
501 'sqlite_factory' => array(3),
|
Chris@0
|
502 'sqlite_open' => array(3),
|
Chris@0
|
503 'sqlite_popen' => array(3),
|
Chris@0
|
504 'sqlite_query' => array(4),
|
Chris@0
|
505 'sqlite_query' => array(4),
|
Chris@0
|
506 'sqlite_unbuffered_query' => array(4),
|
Chris@0
|
507 'sscanf' => array(
|
Chris@0
|
508 3,
|
Chris@0
|
509 '...',
|
Chris@0
|
510 ),
|
Chris@0
|
511 'str_ireplace' => array(4),
|
Chris@0
|
512 'str_replace' => array(4),
|
Chris@0
|
513 'stream_open' => array(4),
|
Chris@0
|
514 'stream_select' => array(
|
Chris@0
|
515 1,
|
Chris@0
|
516 2,
|
Chris@0
|
517 3,
|
Chris@0
|
518 ),
|
Chris@0
|
519 'stream_socket_accept' => array(3),
|
Chris@0
|
520 'stream_socket_client' => array(
|
Chris@0
|
521 2,
|
Chris@0
|
522 3,
|
Chris@0
|
523 ),
|
Chris@0
|
524 'stream_socket_recvfrom' => array(4),
|
Chris@0
|
525 'stream_socket_server' => array(
|
Chris@0
|
526 2,
|
Chris@0
|
527 3,
|
Chris@0
|
528 ),
|
Chris@0
|
529 'system' => array(2),
|
Chris@0
|
530 'uasort' => array(1),
|
Chris@0
|
531 'uksort' => array(1),
|
Chris@0
|
532 'unbufferedQuery' => array(3),
|
Chris@0
|
533 'usort' => array(1),
|
Chris@0
|
534 'wincache_ucache_dec' => array(3),
|
Chris@0
|
535 'wincache_ucache_get' => array(2),
|
Chris@0
|
536 'wincache_ucache_inc' => array(3),
|
Chris@0
|
537 'xdiff_string_merge3' => array(4),
|
Chris@0
|
538 'xdiff_string_patch' => array(4),
|
Chris@0
|
539 'xml_parse_into_struct' => array(
|
Chris@0
|
540 3,
|
Chris@0
|
541 4,
|
Chris@0
|
542 ),
|
Chris@0
|
543 'xml_set_object' => array(2),
|
Chris@0
|
544 'xmlrpc_decode_request' => array(2),
|
Chris@0
|
545 'xmlrpc_set_type' => array(1),
|
Chris@0
|
546 'xslt_set_object' => array(2),
|
Chris@0
|
547 'yaml_parse' => array(3),
|
Chris@0
|
548 'yaml_parse_file' => array(3),
|
Chris@0
|
549 'yaml_parse_url' => array(3),
|
Chris@0
|
550 'yaz_ccl_parse' => array(3),
|
Chris@0
|
551 'yaz_hits' => array(2),
|
Chris@0
|
552 'yaz_scan_result' => array(2),
|
Chris@0
|
553 'yaz_wait' => array(1),
|
Chris@0
|
554 );
|
Chris@0
|
555
|
Chris@0
|
556 /**
|
Chris@0
|
557 * Allows an install to extend the list of known pass-by-reference functions
|
Chris@0
|
558 * by defining generic.codeanalysis.variableanalysis.sitePassByRefFunctions.
|
Chris@0
|
559 */
|
Chris@0
|
560 public $sitePassByRefFunctions = null;
|
Chris@0
|
561
|
Chris@0
|
562 /**
|
Chris@0
|
563 * Allows exceptions in a catch block to be unused without provoking unused-var warning.
|
Chris@0
|
564 * Set generic.codeanalysis.variableanalysis.allowUnusedCaughtExceptions to a true value.
|
Chris@0
|
565 */
|
Chris@0
|
566 public $allowUnusedCaughtExceptions = true;
|
Chris@0
|
567
|
Chris@0
|
568 /**
|
Chris@0
|
569 * Allow function parameters to be unused without provoking unused-var warning.
|
Chris@0
|
570 * Set generic.codeanalysis.variableanalysis.allowUnusedFunctionParameters to a true value.
|
Chris@0
|
571 */
|
Chris@0
|
572 public $allowUnusedFunctionParameters = true;
|
Chris@0
|
573
|
Chris@0
|
574 /**
|
Chris@0
|
575 * A list of names of placeholder variables that you want to ignore from
|
Chris@0
|
576 * unused variable warnings, ie things like $junk.
|
Chris@0
|
577 */
|
Chris@0
|
578 public $validUnusedVariableNames = null;
|
Chris@0
|
579
|
Chris@0
|
580
|
Chris@0
|
581 /**
|
Chris@0
|
582 * Returns an array of tokens this test wants to listen for.
|
Chris@0
|
583 *
|
Chris@0
|
584 * @return array
|
Chris@0
|
585 */
|
Chris@0
|
586 public function register()
|
Chris@0
|
587 {
|
Chris@0
|
588 // Magic to modfy $_passByRefFunctions with any site-specific settings.
|
Chris@0
|
589 if (empty($this->sitePassByRefFunctions) === false) {
|
Chris@0
|
590 foreach (preg_split('/\s+/', trim($this->sitePassByRefFunctions)) as $line) {
|
Chris@0
|
591 list ($function, $args) = explode(':', $line);
|
Chris@0
|
592 $this->_passByRefFunctions[$function] = explode(',', $args);
|
Chris@0
|
593 }
|
Chris@0
|
594 }
|
Chris@0
|
595
|
Chris@0
|
596 if (empty($this->validUnusedVariableNames) === false) {
|
Chris@0
|
597 $this->validUnusedVariableNames = preg_split('/\s+/', trim($this->validUnusedVariableNames));
|
Chris@0
|
598 }
|
Chris@0
|
599
|
Chris@0
|
600 return array(
|
Chris@0
|
601 T_VARIABLE,
|
Chris@0
|
602 T_DOUBLE_QUOTED_STRING,
|
Chris@0
|
603 T_HEREDOC,
|
Chris@0
|
604 T_CLOSE_CURLY_BRACKET,
|
Chris@0
|
605 T_STRING,
|
Chris@0
|
606 );
|
Chris@0
|
607
|
Chris@0
|
608 }//end register()
|
Chris@0
|
609
|
Chris@0
|
610
|
Chris@0
|
611 /**
|
Chris@0
|
612 * Processes this test, when one of its tokens is encountered.
|
Chris@0
|
613 *
|
Chris@17
|
614 * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
|
Chris@17
|
615 * @param int $stackPtr The position of the current token
|
Chris@17
|
616 * in the stack passed in $tokens.
|
Chris@0
|
617 *
|
Chris@0
|
618 * @return void
|
Chris@0
|
619 */
|
Chris@17
|
620 public function process(File $phpcsFile, $stackPtr)
|
Chris@0
|
621 {
|
Chris@0
|
622 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
623 $token = $tokens[$stackPtr];
|
Chris@0
|
624
|
Chris@0
|
625 // Debug code.
|
Chris@0
|
626 // if ($token['content'] == '$param') {
|
Chris@0
|
627 // echo "Found token on line {$token['line']}.\n" . print_r($token, true);
|
Chris@0
|
628 // }
|
Chris@0
|
629 // End: Debug code.
|
Chris@0
|
630 if ($this->currentFile !== $phpcsFile) {
|
Chris@0
|
631 $this->currentFile = $phpcsFile;
|
Chris@0
|
632 }
|
Chris@0
|
633
|
Chris@0
|
634 if ($token['code'] === T_VARIABLE) {
|
Chris@0
|
635 return $this->processVariable($phpcsFile, $stackPtr);
|
Chris@0
|
636 }
|
Chris@0
|
637
|
Chris@0
|
638 if (($token['code'] === T_DOUBLE_QUOTED_STRING)
|
Chris@0
|
639 || ($token['code'] === T_HEREDOC)
|
Chris@0
|
640 ) {
|
Chris@0
|
641 return $this->processVariableInString($phpcsFile, $stackPtr);
|
Chris@0
|
642 }
|
Chris@0
|
643
|
Chris@0
|
644 if (($token['code'] === T_STRING) && ($token['content'] === 'compact')) {
|
Chris@0
|
645 return $this->processCompact($phpcsFile, $stackPtr);
|
Chris@0
|
646 }
|
Chris@0
|
647
|
Chris@0
|
648 if (($token['code'] === T_CLOSE_CURLY_BRACKET)
|
Chris@0
|
649 && isset($token['scope_condition']) === true
|
Chris@0
|
650 ) {
|
Chris@0
|
651 return $this->processScopeClose($phpcsFile, $token['scope_condition']);
|
Chris@0
|
652 }
|
Chris@0
|
653
|
Chris@0
|
654 }//end process()
|
Chris@0
|
655
|
Chris@0
|
656
|
Chris@0
|
657 /**
|
Chris@0
|
658 * Remove special characters from the variable name.
|
Chris@0
|
659 *
|
Chris@0
|
660 * @param string $varName
|
Chris@0
|
661 *
|
Chris@0
|
662 * @return string
|
Chris@0
|
663 */
|
Chris@0
|
664 function normalizeVarName($varName)
|
Chris@0
|
665 {
|
Chris@0
|
666 $varName = preg_replace('/[{}$]/', '', $varName);
|
Chris@0
|
667 return $varName;
|
Chris@0
|
668
|
Chris@0
|
669 }//end normalizeVarName()
|
Chris@0
|
670
|
Chris@0
|
671
|
Chris@0
|
672 /**
|
Chris@0
|
673 * Generate a scope key based on the current file.
|
Chris@0
|
674 *
|
Chris@0
|
675 * @param string $currScope
|
Chris@0
|
676 *
|
Chris@0
|
677 * @return string
|
Chris@0
|
678 */
|
Chris@0
|
679 function scopeKey($currScope)
|
Chris@0
|
680 {
|
Chris@0
|
681 if ($currScope === false) {
|
Chris@0
|
682 $currScope = 'file';
|
Chris@0
|
683 }
|
Chris@0
|
684
|
Chris@0
|
685 if (isset($this->currentFile) === true) {
|
Chris@0
|
686 return ($this->currentFile->getFilename()).':'.$currScope;
|
Chris@0
|
687 } else {
|
Chris@0
|
688 return ('unknown file').':'.$currScope;
|
Chris@0
|
689 }
|
Chris@0
|
690
|
Chris@0
|
691 }//end scopeKey()
|
Chris@0
|
692
|
Chris@0
|
693
|
Chris@0
|
694 /**
|
Chris@0
|
695 * Warning: this is an autovivifying get.
|
Chris@0
|
696 *
|
Chris@0
|
697 * @param string|false $currScope
|
Chris@0
|
698 * @param bool $autoCreate
|
Chris@0
|
699 *
|
Chris@0
|
700 * @return ScopeInfo
|
Chris@0
|
701 */
|
Chris@0
|
702 function getScopeInfo($currScope, $autoCreate = true)
|
Chris@0
|
703 {
|
Chris@0
|
704 $scopeKey = $this->scopeKey($currScope);
|
Chris@0
|
705 if (isset($this->_scopes[$scopeKey]) === false) {
|
Chris@0
|
706 if ($autoCreate === false) {
|
Chris@0
|
707 return null;
|
Chris@0
|
708 }
|
Chris@0
|
709
|
Chris@0
|
710 $this->_scopes[$scopeKey] = new ScopeInfo($currScope);
|
Chris@0
|
711 }
|
Chris@0
|
712
|
Chris@0
|
713 return $this->_scopes[$scopeKey];
|
Chris@0
|
714
|
Chris@0
|
715 }//end getScopeInfo()
|
Chris@0
|
716
|
Chris@0
|
717
|
Chris@0
|
718 /**
|
Chris@0
|
719 * Get variable information for a given variable name.
|
Chris@0
|
720 *
|
Chris@0
|
721 * @param string $varName
|
Chris@0
|
722 * Name of the variable.
|
Chris@0
|
723 * @param int $currScope
|
Chris@0
|
724 * Token stack pointer of the current scope.
|
Chris@0
|
725 * @param bool $autoCreate
|
Chris@0
|
726 * TRUE if the variable should be auto created.
|
Chris@0
|
727 *
|
Chris@0
|
728 * @return VariableInfo|null
|
Chris@0
|
729 * Information about the variable.
|
Chris@0
|
730 */
|
Chris@0
|
731 function getVariableInfo($varName, $currScope, $autoCreate = true)
|
Chris@0
|
732 {
|
Chris@0
|
733 $scopeInfo = $this->getScopeInfo($currScope, $autoCreate);
|
Chris@0
|
734 if (isset($scopeInfo->variables[$varName]) === false) {
|
Chris@0
|
735 if ($autoCreate === false) {
|
Chris@0
|
736 return null;
|
Chris@0
|
737 }
|
Chris@0
|
738
|
Chris@0
|
739 $scopeInfo->variables[$varName] = new VariableInfo($varName);
|
Chris@0
|
740 if (is_array($this->validUnusedVariableNames) === true
|
Chris@0
|
741 && in_array($varName, $this->validUnusedVariableNames) === true
|
Chris@0
|
742 ) {
|
Chris@0
|
743 $scopeInfo->variables[$varName]->ignoreUnused = true;
|
Chris@0
|
744 }
|
Chris@0
|
745 }
|
Chris@0
|
746
|
Chris@0
|
747 return $scopeInfo->variables[$varName];
|
Chris@0
|
748
|
Chris@0
|
749 }//end getVariableInfo()
|
Chris@0
|
750
|
Chris@0
|
751
|
Chris@0
|
752 /**
|
Chris@0
|
753 * Mark the given variable as being assigned.
|
Chris@0
|
754 *
|
Chris@0
|
755 * @param string $varName
|
Chris@0
|
756 * @param int $stackPtr
|
Chris@0
|
757 * @param string $currScope
|
Chris@0
|
758 *
|
Chris@0
|
759 * @return void
|
Chris@0
|
760 */
|
Chris@0
|
761 function markVariableAssignment($varName, $stackPtr, $currScope)
|
Chris@0
|
762 {
|
Chris@0
|
763 $varInfo = $this->getVariableInfo($varName, $currScope);
|
Chris@0
|
764 if (isset($varInfo->scopeType) === false) {
|
Chris@0
|
765 $varInfo->scopeType = 'local';
|
Chris@0
|
766 }
|
Chris@0
|
767
|
Chris@0
|
768 if (isset($varInfo->firstInitialized) === true && ($varInfo->firstInitialized <= $stackPtr)) {
|
Chris@0
|
769 $varInfo->lastAssignment = $stackPtr;
|
Chris@0
|
770 return;
|
Chris@0
|
771 }
|
Chris@0
|
772
|
Chris@0
|
773 $varInfo->firstInitialized = $stackPtr;
|
Chris@0
|
774
|
Chris@0
|
775 }//end markVariableAssignment()
|
Chris@0
|
776
|
Chris@0
|
777
|
Chris@0
|
778 /**
|
Chris@0
|
779 * Mark the given variable as being declared.
|
Chris@0
|
780 *
|
Chris@0
|
781 * @param string $varName
|
Chris@0
|
782 * @param string $scopeType
|
Chris@0
|
783 * @param string $typeHint
|
Chris@0
|
784 * @param int $stackPtr
|
Chris@0
|
785 * @param string $currScope
|
Chris@0
|
786 * @param bool $permitMatchingRedeclaration
|
Chris@0
|
787 *
|
Chris@0
|
788 * @return void
|
Chris@0
|
789 */
|
Chris@0
|
790 function markVariableDeclaration($varName, $scopeType, $typeHint, $stackPtr, $currScope, $permitMatchingRedeclaration = false)
|
Chris@0
|
791 {
|
Chris@0
|
792 $varInfo = $this->getVariableInfo($varName, $currScope);
|
Chris@0
|
793 if (isset($varInfo->scopeType) === true) {
|
Chris@0
|
794 if (($permitMatchingRedeclaration === false)
|
Chris@0
|
795 || ($varInfo->scopeType !== $scopeType)
|
Chris@0
|
796 ) {
|
Chris@0
|
797 // Issue redeclaration/reuse warning
|
Chris@0
|
798 // Note: we check off scopeType not firstDeclared, this is so that
|
Chris@0
|
799 // we catch declarations that come after implicit declarations like
|
Chris@0
|
800 // use of a variable as a local.
|
Chris@0
|
801 $this->currentFile->addWarning(
|
Chris@0
|
802 "Redeclaration of %s %s as %s.",
|
Chris@0
|
803 $stackPtr,
|
Chris@0
|
804 'VariableRedeclaration',
|
Chris@0
|
805 array(
|
Chris@0
|
806 VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType],
|
Chris@0
|
807 "\${$varName}",
|
Chris@0
|
808 VariableInfo::$scopeTypeDescriptions[$scopeType],
|
Chris@0
|
809 )
|
Chris@0
|
810 );
|
Chris@0
|
811 }
|
Chris@0
|
812 }
|
Chris@0
|
813
|
Chris@0
|
814 $varInfo->scopeType = $scopeType;
|
Chris@0
|
815 if (isset($typeHint) === true) {
|
Chris@0
|
816 $varInfo->typeHint = $typeHint;
|
Chris@0
|
817 }
|
Chris@0
|
818
|
Chris@0
|
819 if (isset($varInfo->firstDeclared) === true && ($varInfo->firstDeclared <= $stackPtr)) {
|
Chris@0
|
820 return;
|
Chris@0
|
821 }
|
Chris@0
|
822
|
Chris@0
|
823 // When a global variable is declared it also means we can consider it as
|
Chris@0
|
824 // being initialized.
|
Chris@0
|
825 if ($scopeType === 'global') {
|
Chris@0
|
826 $varInfo->firstInitialized = $stackPtr;
|
Chris@0
|
827 }
|
Chris@0
|
828
|
Chris@0
|
829 $varInfo->firstDeclared = $stackPtr;
|
Chris@0
|
830
|
Chris@0
|
831 }//end markVariableDeclaration()
|
Chris@0
|
832
|
Chris@0
|
833
|
Chris@0
|
834 /**
|
Chris@0
|
835 * Mark the given variable as being read.
|
Chris@0
|
836 *
|
Chris@0
|
837 * @param string $varName
|
Chris@0
|
838 * @param int $stackPtr
|
Chris@0
|
839 * @param string $currScope
|
Chris@0
|
840 *
|
Chris@0
|
841 * @return void
|
Chris@0
|
842 */
|
Chris@0
|
843 function markVariableRead($varName, $stackPtr, $currScope)
|
Chris@0
|
844 {
|
Chris@0
|
845 $varInfo = $this->getVariableInfo($varName, $currScope);
|
Chris@0
|
846 if (isset($varInfo->firstRead) === true && ($varInfo->firstRead <= $stackPtr)) {
|
Chris@0
|
847 return;
|
Chris@0
|
848 }
|
Chris@0
|
849
|
Chris@0
|
850 $varInfo->firstRead = $stackPtr;
|
Chris@0
|
851
|
Chris@0
|
852 }//end markVariableRead()
|
Chris@0
|
853
|
Chris@0
|
854
|
Chris@0
|
855 /**
|
Chris@0
|
856 * Checks if a variable has been initialized.
|
Chris@0
|
857 *
|
Chris@0
|
858 * @param string $varName
|
Chris@0
|
859 * @param int $stackPtr
|
Chris@0
|
860 * @param string $currScope
|
Chris@0
|
861 *
|
Chris@0
|
862 * @return bool
|
Chris@0
|
863 */
|
Chris@0
|
864 function isVariableInitialized($varName, $stackPtr, $currScope)
|
Chris@0
|
865 {
|
Chris@0
|
866 $varInfo = $this->getVariableInfo($varName, $currScope);
|
Chris@0
|
867 if (isset($varInfo->firstInitialized) === true && $varInfo->firstInitialized <= $stackPtr) {
|
Chris@0
|
868 return true;
|
Chris@0
|
869 }
|
Chris@0
|
870
|
Chris@0
|
871 return false;
|
Chris@0
|
872
|
Chris@0
|
873 }//end isVariableInitialized()
|
Chris@0
|
874
|
Chris@0
|
875
|
Chris@0
|
876 /**
|
Chris@0
|
877 * Checks if the given variable is undefined.
|
Chris@0
|
878 *
|
Chris@0
|
879 * @param string $varName
|
Chris@0
|
880 * @param int $stackPtr
|
Chris@0
|
881 * @param string $currScope
|
Chris@0
|
882 *
|
Chris@0
|
883 * @return bool
|
Chris@0
|
884 */
|
Chris@0
|
885 function isVariableUndefined($varName, $stackPtr, $currScope)
|
Chris@0
|
886 {
|
Chris@0
|
887 $varInfo = $this->getVariableInfo($varName, $currScope, false);
|
Chris@0
|
888 if (isset($varInfo->firstDeclared) === true && $varInfo->firstDeclared <= $stackPtr) {
|
Chris@0
|
889 // TODO: do we want to check scopeType here?
|
Chris@0
|
890 return false;
|
Chris@0
|
891 }
|
Chris@0
|
892
|
Chris@0
|
893 if (isset($varInfo->firstInitialized) === true && $varInfo->firstInitialized <= $stackPtr) {
|
Chris@0
|
894 return false;
|
Chris@0
|
895 }
|
Chris@0
|
896
|
Chris@0
|
897 return true;
|
Chris@0
|
898
|
Chris@0
|
899 }//end isVariableUndefined()
|
Chris@0
|
900
|
Chris@0
|
901
|
Chris@0
|
902 /**
|
Chris@0
|
903 * Marks a variable as read and throws a PHPCS warning if it is undefined.
|
Chris@0
|
904 *
|
Chris@17
|
905 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
906 * @param string $varName
|
Chris@17
|
907 * @param int $stackPtr
|
Chris@17
|
908 * @param string $currScope
|
Chris@0
|
909 *
|
Chris@0
|
910 * @return bool
|
Chris@0
|
911 */
|
Chris@17
|
912 function markVariableReadAndWarnIfUndefined(File $phpcsFile, $varName, $stackPtr, $currScope)
|
Chris@0
|
913 {
|
Chris@0
|
914 $this->markVariableRead($varName, $stackPtr, $currScope);
|
Chris@0
|
915
|
Chris@0
|
916 if ($this->isVariableUndefined($varName, $stackPtr, $currScope) === true) {
|
Chris@0
|
917 // We haven't been defined by this point.
|
Chris@0
|
918 $phpcsFile->addWarning(
|
Chris@0
|
919 "Variable %s is undefined.",
|
Chris@0
|
920 $stackPtr,
|
Chris@0
|
921 'UndefinedVariable',
|
Chris@0
|
922 array("\${$varName}")
|
Chris@0
|
923 );
|
Chris@0
|
924 }
|
Chris@0
|
925
|
Chris@0
|
926 return true;
|
Chris@0
|
927
|
Chris@0
|
928 }//end markVariableReadAndWarnIfUndefined()
|
Chris@0
|
929
|
Chris@0
|
930
|
Chris@0
|
931 /**
|
Chris@0
|
932 * Returns the function declaration pointer.
|
Chris@0
|
933 *
|
Chris@17
|
934 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
935 * @param int $stackPtr
|
Chris@0
|
936 *
|
Chris@0
|
937 * @return int|false
|
Chris@0
|
938 */
|
Chris@17
|
939 function findFunctionPrototype(File $phpcsFile, $stackPtr)
|
Chris@0
|
940 {
|
Chris@0
|
941 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
942
|
Chris@0
|
943 if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) {
|
Chris@0
|
944 return false;
|
Chris@0
|
945 }
|
Chris@0
|
946
|
Chris@0
|
947 // Function names are T_STRING, and return-by-reference is T_BITWISE_AND,
|
Chris@0
|
948 // so we look backwards from the opening bracket for the first thing that
|
Chris@0
|
949 // isn't a function name, reference sigil or whitespace and check if
|
Chris@0
|
950 // it's a function keyword.
|
Chris@0
|
951 $functionPtr = $phpcsFile->findPrevious(
|
Chris@0
|
952 array(
|
Chris@0
|
953 T_STRING,
|
Chris@0
|
954 T_WHITESPACE,
|
Chris@0
|
955 T_BITWISE_AND,
|
Chris@0
|
956 ),
|
Chris@0
|
957 ($openPtr - 1),
|
Chris@0
|
958 null,
|
Chris@0
|
959 true,
|
Chris@0
|
960 null,
|
Chris@0
|
961 true
|
Chris@0
|
962 );
|
Chris@0
|
963 if (($functionPtr !== false)
|
Chris@0
|
964 && ($tokens[$functionPtr]['code'] === T_FUNCTION)
|
Chris@0
|
965 ) {
|
Chris@0
|
966 return $functionPtr;
|
Chris@0
|
967 }
|
Chris@0
|
968
|
Chris@0
|
969 return false;
|
Chris@0
|
970
|
Chris@0
|
971 }//end findFunctionPrototype()
|
Chris@0
|
972
|
Chris@0
|
973
|
Chris@0
|
974 /**
|
Chris@0
|
975 * Find the scope the given pointer is in.
|
Chris@0
|
976 *
|
Chris@17
|
977 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
978 * @param int $stackPtr
|
Chris@0
|
979 *
|
Chris@0
|
980 * @return int|false
|
Chris@0
|
981 */
|
Chris@17
|
982 function findVariableScope(File $phpcsFile, $stackPtr)
|
Chris@0
|
983 {
|
Chris@0
|
984 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
985 $token = $tokens[$stackPtr];
|
Chris@0
|
986
|
Chris@0
|
987 $in_class = false;
|
Chris@0
|
988 if (empty($token['conditions']) === false) {
|
Chris@0
|
989 foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) {
|
Chris@0
|
990 if (($scopeCode === T_FUNCTION) || ($scopeCode === T_CLOSURE)) {
|
Chris@0
|
991 return $scopePtr;
|
Chris@0
|
992 }
|
Chris@0
|
993
|
Chris@0
|
994 if (($scopeCode === T_CLASS) || ($scopeCode === T_INTERFACE) || ($scopeCode === T_TRAIT)) {
|
Chris@0
|
995 $in_class = true;
|
Chris@0
|
996 }
|
Chris@0
|
997 }
|
Chris@0
|
998 }
|
Chris@0
|
999
|
Chris@0
|
1000 if (($scopePtr = $this->findFunctionPrototype($phpcsFile, $stackPtr)) !== false) {
|
Chris@0
|
1001 return $scopePtr;
|
Chris@0
|
1002 }
|
Chris@0
|
1003
|
Chris@0
|
1004 if ($in_class === true) {
|
Chris@0
|
1005 // Member var of a class, we don't care.
|
Chris@0
|
1006 return false;
|
Chris@0
|
1007 }
|
Chris@0
|
1008
|
Chris@0
|
1009 // File scope, hmm, lets use first token of file?
|
Chris@0
|
1010 return 0;
|
Chris@0
|
1011
|
Chris@0
|
1012 }//end findVariableScope()
|
Chris@0
|
1013
|
Chris@0
|
1014
|
Chris@0
|
1015 /**
|
Chris@0
|
1016 * Checks if the next token is an assignment.
|
Chris@0
|
1017 *
|
Chris@17
|
1018 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1019 * @param int $stackPtr
|
Chris@0
|
1020 *
|
Chris@0
|
1021 * @return bool
|
Chris@0
|
1022 */
|
Chris@17
|
1023 function isNextThingAnAssign(File $phpcsFile, $stackPtr)
|
Chris@0
|
1024 {
|
Chris@0
|
1025 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1026
|
Chris@0
|
1027 // Is the next non-whitespace an assignment?
|
Chris@0
|
1028 $nextPtr = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true, null, true);
|
Chris@0
|
1029 if ($nextPtr !== false) {
|
Chris@0
|
1030 if ($tokens[$nextPtr]['code'] === T_EQUAL) {
|
Chris@0
|
1031 return $nextPtr;
|
Chris@0
|
1032 }
|
Chris@0
|
1033
|
Chris@0
|
1034 // Special handling for initializing arrays on the fly, which is
|
Chris@0
|
1035 // also an assignment.
|
Chris@0
|
1036 if ($tokens[$nextPtr]['code'] === T_OPEN_SQUARE_BRACKET) {
|
Chris@0
|
1037 return $this->isNextThingAnAssign($phpcsFile, $tokens[$nextPtr]['bracket_closer']);
|
Chris@0
|
1038 }
|
Chris@0
|
1039 }
|
Chris@0
|
1040
|
Chris@0
|
1041 return false;
|
Chris@0
|
1042
|
Chris@0
|
1043 }//end isNextThingAnAssign()
|
Chris@0
|
1044
|
Chris@0
|
1045
|
Chris@0
|
1046 /**
|
Chris@0
|
1047 * Find the end of the assignment.
|
Chris@0
|
1048 *
|
Chris@17
|
1049 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1050 * @param int $stackPtr
|
Chris@0
|
1051 *
|
Chris@0
|
1052 * @return int
|
Chris@0
|
1053 */
|
Chris@17
|
1054 function findWhereAssignExecuted(File $phpcsFile, $stackPtr)
|
Chris@0
|
1055 {
|
Chris@0
|
1056 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1057
|
Chris@0
|
1058 // Write should be recorded at the next statement to ensure we treat
|
Chris@0
|
1059 // the assign as happening after the RHS execution.
|
Chris@0
|
1060 // eg: $var = $var + 1; -> RHS could still be undef.
|
Chris@0
|
1061 // However, if we're within a bracketed expression,
|
Chris@0
|
1062 // eg: echo (($var = 12) && ($var == 12));
|
Chris@0
|
1063 // we take place at the closing bracket, if that's first.
|
Chris@0
|
1064 $semicolonPtr = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1), null, false, null, true);
|
Chris@0
|
1065 $closePtr = false;
|
Chris@0
|
1066 if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) !== false) {
|
Chris@0
|
1067 if (isset($tokens[$openPtr]['parenthesis_closer']) === true) {
|
Chris@0
|
1068 $closePtr = $tokens[$openPtr]['parenthesis_closer'];
|
Chris@0
|
1069 }
|
Chris@0
|
1070 }
|
Chris@0
|
1071
|
Chris@0
|
1072 if ($semicolonPtr === false) {
|
Chris@0
|
1073 if ($closePtr === false) {
|
Chris@0
|
1074 // TODO: panic.
|
Chris@0
|
1075 return $stackPtr;
|
Chris@0
|
1076 }
|
Chris@0
|
1077
|
Chris@0
|
1078 return $closePtr;
|
Chris@0
|
1079 }
|
Chris@0
|
1080
|
Chris@0
|
1081 if ($closePtr !== false && $closePtr < $semicolonPtr) {
|
Chris@0
|
1082 return $closePtr;
|
Chris@0
|
1083 }
|
Chris@0
|
1084
|
Chris@0
|
1085 return $semicolonPtr;
|
Chris@0
|
1086
|
Chris@0
|
1087 }//end findWhereAssignExecuted()
|
Chris@0
|
1088
|
Chris@0
|
1089
|
Chris@0
|
1090 /**
|
Chris@0
|
1091 * Find the parenthesis if the pointer is in some.
|
Chris@0
|
1092 *
|
Chris@17
|
1093 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1094 * @param int $stackPtr
|
Chris@0
|
1095 *
|
Chris@0
|
1096 * @return int|false
|
Chris@0
|
1097 */
|
Chris@17
|
1098 function findContainingBrackets(File $phpcsFile, $stackPtr)
|
Chris@0
|
1099 {
|
Chris@0
|
1100 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1101
|
Chris@0
|
1102 if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) {
|
Chris@0
|
1103 $openPtrs = array_keys($tokens[$stackPtr]['nested_parenthesis']);
|
Chris@0
|
1104 return end($openPtrs);
|
Chris@0
|
1105 }
|
Chris@0
|
1106
|
Chris@0
|
1107 return false;
|
Chris@0
|
1108
|
Chris@0
|
1109 }//end findContainingBrackets()
|
Chris@0
|
1110
|
Chris@0
|
1111
|
Chris@0
|
1112 /**
|
Chris@0
|
1113 * Checks if the given pointer is in a function call.
|
Chris@0
|
1114 *
|
Chris@17
|
1115 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1116 * @param int $stackPtr
|
Chris@0
|
1117 *
|
Chris@0
|
1118 * @return int|false
|
Chris@0
|
1119 */
|
Chris@17
|
1120 function findFunctionCall(File $phpcsFile, $stackPtr)
|
Chris@0
|
1121 {
|
Chris@0
|
1122 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1123
|
Chris@0
|
1124 if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) !== false) {
|
Chris@0
|
1125 // First non-whitespace thing and see if it's a T_STRING function name.
|
Chris@0
|
1126 $functionPtr = $phpcsFile->findPrevious(
|
Chris@0
|
1127 T_WHITESPACE,
|
Chris@0
|
1128 ($openPtr - 1),
|
Chris@0
|
1129 null,
|
Chris@0
|
1130 true,
|
Chris@0
|
1131 null,
|
Chris@0
|
1132 true
|
Chris@0
|
1133 );
|
Chris@0
|
1134 if ($tokens[$functionPtr]['code'] === T_STRING) {
|
Chris@0
|
1135 return $functionPtr;
|
Chris@0
|
1136 }
|
Chris@0
|
1137 }
|
Chris@0
|
1138
|
Chris@0
|
1139 return false;
|
Chris@0
|
1140
|
Chris@0
|
1141 }//end findFunctionCall()
|
Chris@0
|
1142
|
Chris@0
|
1143
|
Chris@0
|
1144 /**
|
Chris@0
|
1145 * Get the arguments of a function call.
|
Chris@0
|
1146 *
|
Chris@17
|
1147 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1148 * @param int $stackPtr
|
Chris@0
|
1149 *
|
Chris@0
|
1150 * @return array|false
|
Chris@0
|
1151 */
|
Chris@17
|
1152 function findFunctionCallArguments(File $phpcsFile, $stackPtr)
|
Chris@0
|
1153 {
|
Chris@0
|
1154 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1155
|
Chris@0
|
1156 // Slight hack: also allow this to find args for array constructor.
|
Chris@0
|
1157 // TODO: probably should refactor into three functions: arg-finding and bracket-finding.
|
Chris@0
|
1158 if (($tokens[$stackPtr]['code'] !== T_STRING) && ($tokens[$stackPtr]['code'] !== T_ARRAY)) {
|
Chris@0
|
1159 // Assume $stackPtr is something within the brackets, find our function call.
|
Chris@0
|
1160 if (($stackPtr = $this->findFunctionCall($phpcsFile, $stackPtr)) === false) {
|
Chris@0
|
1161 return false;
|
Chris@0
|
1162 }
|
Chris@0
|
1163 }
|
Chris@0
|
1164
|
Chris@0
|
1165 // $stackPtr is the function name, find our brackets after it.
|
Chris@0
|
1166 $openPtr = $phpcsFile->findNext(
|
Chris@0
|
1167 T_WHITESPACE,
|
Chris@0
|
1168 ($stackPtr + 1),
|
Chris@0
|
1169 null,
|
Chris@0
|
1170 true,
|
Chris@0
|
1171 null,
|
Chris@0
|
1172 true
|
Chris@0
|
1173 );
|
Chris@0
|
1174 if (($openPtr === false) || ($tokens[$openPtr]['code'] !== T_OPEN_PARENTHESIS)) {
|
Chris@0
|
1175 return false;
|
Chris@0
|
1176 }
|
Chris@0
|
1177
|
Chris@0
|
1178 if (isset($tokens[$openPtr]['parenthesis_closer']) === false) {
|
Chris@0
|
1179 return false;
|
Chris@0
|
1180 }
|
Chris@0
|
1181
|
Chris@0
|
1182 $closePtr = $tokens[$openPtr]['parenthesis_closer'];
|
Chris@0
|
1183
|
Chris@0
|
1184 $argPtrs = array();
|
Chris@0
|
1185 $lastPtr = $openPtr;
|
Chris@0
|
1186 $lastArgComma = $openPtr;
|
Chris@0
|
1187 while (($nextPtr = $phpcsFile->findNext(T_COMMA, ($lastPtr + 1), $closePtr)) !== false) {
|
Chris@0
|
1188 if ($this->findContainingBrackets($phpcsFile, $nextPtr) === $openPtr) {
|
Chris@0
|
1189 // Comma is at our level of brackets, it's an argument delimiter.
|
Chris@0
|
1190 array_push($argPtrs, range(($lastArgComma + 1), ($nextPtr - 1)));
|
Chris@0
|
1191 $lastArgComma = $nextPtr;
|
Chris@0
|
1192 }
|
Chris@0
|
1193
|
Chris@0
|
1194 $lastPtr = $nextPtr;
|
Chris@0
|
1195 }
|
Chris@0
|
1196
|
Chris@0
|
1197 array_push($argPtrs, range(($lastArgComma + 1), ($closePtr - 1)));
|
Chris@0
|
1198
|
Chris@0
|
1199 return $argPtrs;
|
Chris@0
|
1200
|
Chris@0
|
1201 }//end findFunctionCallArguments()
|
Chris@0
|
1202
|
Chris@0
|
1203
|
Chris@0
|
1204 /**
|
Chris@0
|
1205 * Checks the function prototype.
|
Chris@0
|
1206 *
|
Chris@17
|
1207 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1208 * @param int $stackPtr
|
Chris@17
|
1209 * @param string $varName
|
Chris@17
|
1210 * @param string $currScope
|
Chris@0
|
1211 *
|
Chris@0
|
1212 * @return bool
|
Chris@0
|
1213 */
|
Chris@0
|
1214 protected function checkForFunctionPrototype(
|
Chris@17
|
1215 File $phpcsFile,
|
Chris@0
|
1216 $stackPtr,
|
Chris@0
|
1217 $varName,
|
Chris@0
|
1218 $currScope
|
Chris@0
|
1219 ) {
|
Chris@0
|
1220 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1221
|
Chris@0
|
1222 // Are we a function or closure parameter?
|
Chris@0
|
1223 // It would be nice to get the list of function parameters from watching for
|
Chris@0
|
1224 // T_FUNCTION, but AbstractVariableSniff and AbstractScopeSniff define everything
|
Chris@0
|
1225 // we need to do that as private or final, so we have to do it this hackish way.
|
Chris@0
|
1226 if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) {
|
Chris@0
|
1227 return false;
|
Chris@0
|
1228 }
|
Chris@0
|
1229
|
Chris@0
|
1230 // Function names are T_STRING, and return-by-reference is T_BITWISE_AND,
|
Chris@0
|
1231 // so we look backwards from the opening bracket for the first thing that
|
Chris@0
|
1232 // isn't a function name, reference sigil or whitespace and check if
|
Chris@0
|
1233 // it's a function keyword.
|
Chris@0
|
1234 $functionPtr = $phpcsFile->findPrevious(
|
Chris@0
|
1235 array(
|
Chris@0
|
1236 T_STRING,
|
Chris@0
|
1237 T_WHITESPACE,
|
Chris@0
|
1238 T_BITWISE_AND,
|
Chris@0
|
1239 ),
|
Chris@0
|
1240 ($openPtr - 1),
|
Chris@0
|
1241 null,
|
Chris@0
|
1242 true,
|
Chris@0
|
1243 null,
|
Chris@0
|
1244 true
|
Chris@0
|
1245 );
|
Chris@0
|
1246 if (($functionPtr !== false)
|
Chris@0
|
1247 && (($tokens[$functionPtr]['code'] === T_FUNCTION)
|
Chris@0
|
1248 || ($tokens[$functionPtr]['code'] === T_CLOSURE))
|
Chris@0
|
1249 ) {
|
Chris@0
|
1250 // TODO: typeHint.
|
Chris@0
|
1251 $this->markVariableDeclaration($varName, 'param', null, $stackPtr, $functionPtr);
|
Chris@0
|
1252 // Are we pass-by-reference?
|
Chris@0
|
1253 $referencePtr = $phpcsFile->findPrevious(
|
Chris@0
|
1254 T_WHITESPACE,
|
Chris@0
|
1255 ($stackPtr - 1),
|
Chris@0
|
1256 null,
|
Chris@0
|
1257 true,
|
Chris@0
|
1258 null,
|
Chris@0
|
1259 true
|
Chris@0
|
1260 );
|
Chris@0
|
1261 if (($referencePtr !== false) && ($tokens[$referencePtr]['code'] === T_BITWISE_AND)) {
|
Chris@0
|
1262 $varInfo = $this->getVariableInfo($varName, $functionPtr);
|
Chris@0
|
1263 $varInfo->passByReference = true;
|
Chris@0
|
1264 }
|
Chris@0
|
1265
|
Chris@0
|
1266 // Are we optional with a default?
|
Chris@0
|
1267 if ($this->isNextThingAnAssign($phpcsFile, $stackPtr) !== false) {
|
Chris@0
|
1268 $this->markVariableAssignment($varName, $stackPtr, $functionPtr);
|
Chris@0
|
1269 }
|
Chris@0
|
1270
|
Chris@0
|
1271 return true;
|
Chris@0
|
1272 }//end if
|
Chris@0
|
1273
|
Chris@0
|
1274 // Is it a use keyword? Use is both a read and a define, fun!
|
Chris@0
|
1275 if (($functionPtr !== false) && ($tokens[$functionPtr]['code'] === T_USE)) {
|
Chris@0
|
1276 $this->markVariableRead($varName, $stackPtr, $currScope);
|
Chris@0
|
1277 if ($this->isVariableUndefined($varName, $stackPtr, $currScope) === true) {
|
Chris@0
|
1278 // We haven't been defined by this point.
|
Chris@0
|
1279 $phpcsFile->addWarning(
|
Chris@0
|
1280 "Variable %s is undefined.",
|
Chris@0
|
1281 $stackPtr,
|
Chris@0
|
1282 'UndefinedVariable',
|
Chris@0
|
1283 array("\${$varName}")
|
Chris@0
|
1284 );
|
Chris@0
|
1285 return true;
|
Chris@0
|
1286 }
|
Chris@0
|
1287
|
Chris@0
|
1288 // $functionPtr is at the use, we need the function keyword for start of scope.
|
Chris@0
|
1289 $functionPtr = $phpcsFile->findPrevious(
|
Chris@0
|
1290 T_CLOSURE,
|
Chris@0
|
1291 ($functionPtr - 1),
|
Chris@0
|
1292 ($currScope + 1),
|
Chris@0
|
1293 false,
|
Chris@0
|
1294 null,
|
Chris@0
|
1295 true
|
Chris@0
|
1296 );
|
Chris@0
|
1297 if ($functionPtr !== false) {
|
Chris@0
|
1298 // TODO: typeHints in use?
|
Chris@0
|
1299 $this->markVariableDeclaration($varName, 'bound', null, $stackPtr, $functionPtr);
|
Chris@0
|
1300 $this->markVariableAssignment($varName, $stackPtr, $functionPtr);
|
Chris@0
|
1301
|
Chris@0
|
1302 // Are we pass-by-reference?
|
Chris@0
|
1303 $referencePtr = $phpcsFile->findPrevious(
|
Chris@0
|
1304 T_WHITESPACE,
|
Chris@0
|
1305 ($stackPtr - 1),
|
Chris@0
|
1306 null,
|
Chris@0
|
1307 true,
|
Chris@0
|
1308 null,
|
Chris@0
|
1309 true
|
Chris@0
|
1310 );
|
Chris@0
|
1311 if (($referencePtr !== false) && ($tokens[$referencePtr]['code'] === T_BITWISE_AND)) {
|
Chris@0
|
1312 $varInfo = $this->getVariableInfo($varName, $functionPtr);
|
Chris@0
|
1313 $varInfo->passByReference = true;
|
Chris@0
|
1314 }
|
Chris@0
|
1315
|
Chris@0
|
1316 return true;
|
Chris@0
|
1317 }//end if
|
Chris@0
|
1318 }//end if
|
Chris@0
|
1319
|
Chris@0
|
1320 return false;
|
Chris@0
|
1321
|
Chris@0
|
1322 }//end checkForFunctionPrototype()
|
Chris@0
|
1323
|
Chris@0
|
1324
|
Chris@0
|
1325 /**
|
Chris@0
|
1326 * Checks if we are in a catch() block.
|
Chris@0
|
1327 *
|
Chris@17
|
1328 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1329 * @param int $stackPtr
|
Chris@17
|
1330 * @param string $varName
|
Chris@17
|
1331 * @param string $currScope
|
Chris@0
|
1332 *
|
Chris@0
|
1333 * @return bool
|
Chris@0
|
1334 */
|
Chris@0
|
1335 protected function checkForCatchBlock(
|
Chris@17
|
1336 File $phpcsFile,
|
Chris@0
|
1337 $stackPtr,
|
Chris@0
|
1338 $varName,
|
Chris@0
|
1339 $currScope
|
Chris@0
|
1340 ) {
|
Chris@0
|
1341 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1342
|
Chris@0
|
1343 // Are we a catch block parameter?
|
Chris@0
|
1344 if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) {
|
Chris@0
|
1345 return false;
|
Chris@0
|
1346 }
|
Chris@0
|
1347
|
Chris@0
|
1348 // Function names are T_STRING, and return-by-reference is T_BITWISE_AND,
|
Chris@0
|
1349 // so we look backwards from the opening bracket for the first thing that
|
Chris@0
|
1350 // isn't a function name, reference sigil or whitespace and check if
|
Chris@0
|
1351 // it's a function keyword.
|
Chris@0
|
1352 $catchPtr = $phpcsFile->findPrevious(
|
Chris@0
|
1353 T_WHITESPACE,
|
Chris@0
|
1354 ($openPtr - 1),
|
Chris@0
|
1355 null,
|
Chris@0
|
1356 true,
|
Chris@0
|
1357 null,
|
Chris@0
|
1358 true
|
Chris@0
|
1359 );
|
Chris@0
|
1360 if (($catchPtr !== false)
|
Chris@0
|
1361 && ($tokens[$catchPtr]['code'] === T_CATCH)
|
Chris@0
|
1362 ) {
|
Chris@0
|
1363 // Scope of the exception var is actually the function, not just the catch block.
|
Chris@0
|
1364 // TODO: typeHint.
|
Chris@0
|
1365 $this->markVariableDeclaration($varName, 'local', null, $stackPtr, $currScope, true);
|
Chris@0
|
1366 $this->markVariableAssignment($varName, $stackPtr, $currScope);
|
Chris@0
|
1367 if ($this->allowUnusedCaughtExceptions !== false) {
|
Chris@0
|
1368 $varInfo = $this->getVariableInfo($varName, $currScope);
|
Chris@0
|
1369 $varInfo->ignoreUnused = true;
|
Chris@0
|
1370 }
|
Chris@0
|
1371
|
Chris@0
|
1372 return true;
|
Chris@0
|
1373 }
|
Chris@0
|
1374
|
Chris@0
|
1375 return false;
|
Chris@0
|
1376
|
Chris@0
|
1377 }//end checkForCatchBlock()
|
Chris@0
|
1378
|
Chris@0
|
1379
|
Chris@0
|
1380 /**
|
Chris@0
|
1381 * Checks if $this is used within a class.
|
Chris@0
|
1382 *
|
Chris@17
|
1383 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1384 * @param int $stackPtr
|
Chris@17
|
1385 * @param string $varName
|
Chris@17
|
1386 * @param string $currScope
|
Chris@0
|
1387 *
|
Chris@0
|
1388 * @return bool
|
Chris@0
|
1389 */
|
Chris@0
|
1390 protected function checkForThisWithinClass(
|
Chris@17
|
1391 File $phpcsFile,
|
Chris@0
|
1392 $stackPtr,
|
Chris@0
|
1393 $varName,
|
Chris@0
|
1394 $currScope
|
Chris@0
|
1395 ) {
|
Chris@0
|
1396 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1397 $token = $tokens[$stackPtr];
|
Chris@0
|
1398
|
Chris@0
|
1399 // Are we $this within a class?
|
Chris@0
|
1400 if (($varName !== 'this') || empty($token['conditions']) === true) {
|
Chris@0
|
1401 return false;
|
Chris@0
|
1402 }
|
Chris@0
|
1403
|
Chris@0
|
1404 foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) {
|
Chris@0
|
1405 if ($scopeCode === T_CLASS || $scopeCode === T_TRAIT) {
|
Chris@0
|
1406 return true;
|
Chris@0
|
1407 }
|
Chris@0
|
1408 }
|
Chris@0
|
1409
|
Chris@0
|
1410 return false;
|
Chris@0
|
1411
|
Chris@0
|
1412 }//end checkForThisWithinClass()
|
Chris@0
|
1413
|
Chris@0
|
1414
|
Chris@0
|
1415 /**
|
Chris@0
|
1416 * Checks if the variable is a PHP super global.
|
Chris@0
|
1417 *
|
Chris@17
|
1418 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1419 * @param int $stackPtr
|
Chris@17
|
1420 * @param string $varName
|
Chris@17
|
1421 * @param string $currScope
|
Chris@0
|
1422 *
|
Chris@0
|
1423 * @return bool
|
Chris@0
|
1424 */
|
Chris@0
|
1425 protected function checkForSuperGlobal(
|
Chris@17
|
1426 File $phpcsFile,
|
Chris@0
|
1427 $stackPtr,
|
Chris@0
|
1428 $varName,
|
Chris@0
|
1429 $currScope
|
Chris@0
|
1430 ) {
|
Chris@0
|
1431 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1432 $token = $tokens[$stackPtr];
|
Chris@0
|
1433
|
Chris@0
|
1434 // Are we a superglobal variable?
|
Chris@0
|
1435 if (in_array(
|
Chris@0
|
1436 $varName,
|
Chris@0
|
1437 array(
|
Chris@0
|
1438 'GLOBALS',
|
Chris@0
|
1439 '_SERVER',
|
Chris@0
|
1440 '_GET',
|
Chris@0
|
1441 '_POST',
|
Chris@0
|
1442 '_FILES',
|
Chris@0
|
1443 '_COOKIE',
|
Chris@0
|
1444 '_SESSION',
|
Chris@0
|
1445 '_REQUEST',
|
Chris@0
|
1446 '_ENV',
|
Chris@0
|
1447 'argv',
|
Chris@0
|
1448 'argc',
|
Chris@0
|
1449 )
|
Chris@0
|
1450 ) === true
|
Chris@0
|
1451 ) {
|
Chris@0
|
1452 return true;
|
Chris@0
|
1453 }
|
Chris@0
|
1454
|
Chris@0
|
1455 return false;
|
Chris@0
|
1456
|
Chris@0
|
1457 }//end checkForSuperGlobal()
|
Chris@0
|
1458
|
Chris@0
|
1459
|
Chris@0
|
1460 /**
|
Chris@0
|
1461 * Checks if the variable is a static class member.
|
Chris@0
|
1462 *
|
Chris@17
|
1463 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1464 * @param int $stackPtr
|
Chris@17
|
1465 * @param string $varName
|
Chris@17
|
1466 * @param string $currScope
|
Chris@0
|
1467 *
|
Chris@0
|
1468 * @return bool
|
Chris@0
|
1469 */
|
Chris@0
|
1470 protected function checkForStaticMember(
|
Chris@17
|
1471 File $phpcsFile,
|
Chris@0
|
1472 $stackPtr,
|
Chris@0
|
1473 $varName,
|
Chris@0
|
1474 $currScope
|
Chris@0
|
1475 ) {
|
Chris@0
|
1476 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1477 $token = $tokens[$stackPtr];
|
Chris@0
|
1478
|
Chris@0
|
1479 // Are we a static member?
|
Chris@0
|
1480 $doubleColonPtr = ($stackPtr - 1);
|
Chris@0
|
1481 if ($tokens[$doubleColonPtr]['code'] !== T_DOUBLE_COLON) {
|
Chris@0
|
1482 return false;
|
Chris@0
|
1483 }
|
Chris@0
|
1484
|
Chris@0
|
1485 $classNamePtr = ($stackPtr - 2);
|
Chris@0
|
1486 if (($tokens[$classNamePtr]['code'] !== T_STRING)
|
Chris@0
|
1487 && ($tokens[$classNamePtr]['code'] !== T_SELF)
|
Chris@0
|
1488 && ($tokens[$classNamePtr]['code'] !== T_STATIC)
|
Chris@0
|
1489 ) {
|
Chris@0
|
1490 return false;
|
Chris@0
|
1491 }
|
Chris@0
|
1492
|
Chris@0
|
1493 // Are we referring to self:: outside a class?
|
Chris@0
|
1494 // TODO: not sure this is our business or should be some other sniff.
|
Chris@0
|
1495 if (($tokens[$classNamePtr]['code'] === T_SELF)
|
Chris@0
|
1496 || ($tokens[$classNamePtr]['code'] === T_STATIC)
|
Chris@0
|
1497 ) {
|
Chris@0
|
1498 if ($tokens[$classNamePtr]['code'] === T_SELF) {
|
Chris@0
|
1499 $err_class = 'SelfOutsideClass';
|
Chris@0
|
1500 $err_desc = 'self::';
|
Chris@0
|
1501 } else {
|
Chris@0
|
1502 $err_class = 'StaticOutsideClass';
|
Chris@0
|
1503 $err_desc = 'static::';
|
Chris@0
|
1504 }
|
Chris@0
|
1505
|
Chris@0
|
1506 if (empty($token['conditions']) === false) {
|
Chris@0
|
1507 foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) {
|
Chris@0
|
1508 // Self within a closure is invalid.
|
Chris@0
|
1509 // Note: have to fetch code from $tokens, T_CLOSURE isn't set for conditions codes.
|
Chris@0
|
1510 if ($tokens[$scopePtr]['code'] === T_CLOSURE) {
|
Chris@0
|
1511 $phpcsFile->addError(
|
Chris@0
|
1512 "Use of {$err_desc}%s inside closure.",
|
Chris@0
|
1513 $stackPtr,
|
Chris@0
|
1514 $err_class,
|
Chris@0
|
1515 array("\${$varName}")
|
Chris@0
|
1516 );
|
Chris@0
|
1517 return true;
|
Chris@0
|
1518 }
|
Chris@0
|
1519
|
Chris@0
|
1520 if ($scopeCode === T_CLASS || $scopeCode === T_TRAIT) {
|
Chris@0
|
1521 return true;
|
Chris@0
|
1522 }
|
Chris@0
|
1523 }
|
Chris@0
|
1524 }
|
Chris@0
|
1525
|
Chris@0
|
1526 $phpcsFile->addError(
|
Chris@0
|
1527 "Use of {$err_desc}%s outside class definition.",
|
Chris@0
|
1528 $stackPtr,
|
Chris@0
|
1529 $err_class,
|
Chris@0
|
1530 array("\${$varName}")
|
Chris@0
|
1531 );
|
Chris@0
|
1532 return true;
|
Chris@0
|
1533 }//end if
|
Chris@0
|
1534
|
Chris@0
|
1535 return true;
|
Chris@0
|
1536
|
Chris@0
|
1537 }//end checkForStaticMember()
|
Chris@0
|
1538
|
Chris@0
|
1539
|
Chris@0
|
1540 /**
|
Chris@0
|
1541 * Checks if the variable is being assigned to.
|
Chris@0
|
1542 *
|
Chris@17
|
1543 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1544 * @param int $stackPtr
|
Chris@17
|
1545 * @param string $varName
|
Chris@17
|
1546 * @param string $currScope
|
Chris@0
|
1547 *
|
Chris@0
|
1548 * @return bool
|
Chris@0
|
1549 */
|
Chris@0
|
1550 protected function checkForAssignment(
|
Chris@17
|
1551 File $phpcsFile,
|
Chris@0
|
1552 $stackPtr,
|
Chris@0
|
1553 $varName,
|
Chris@0
|
1554 $currScope
|
Chris@0
|
1555 ) {
|
Chris@0
|
1556 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1557
|
Chris@0
|
1558 // Is the next non-whitespace an assignment?
|
Chris@0
|
1559 if (($assignPtr = $this->isNextThingAnAssign($phpcsFile, $stackPtr)) === false) {
|
Chris@0
|
1560 return false;
|
Chris@0
|
1561 }
|
Chris@0
|
1562
|
Chris@0
|
1563 // Plain ol' assignment. Simpl(ish).
|
Chris@0
|
1564 if (($writtenPtr = $this->findWhereAssignExecuted($phpcsFile, $assignPtr)) === false) {
|
Chris@0
|
1565 $writtenPtr = $stackPtr;
|
Chris@0
|
1566 // I dunno.
|
Chris@0
|
1567 }
|
Chris@0
|
1568
|
Chris@0
|
1569 // Check for the ampersand '&' after the assignment, which means this
|
Chris@0
|
1570 // variable is taken by reference.
|
Chris@0
|
1571 $refPtr = $phpcsFile->findNext(T_WHITESPACE, ($assignPtr + 1), null, true);
|
Chris@0
|
1572 if ($tokens[$refPtr]['code'] === T_BITWISE_AND) {
|
Chris@0
|
1573 $varInfo = $this->getVariableInfo($varName, $currScope);
|
Chris@0
|
1574 $varInfo->passByReference = true;
|
Chris@0
|
1575 }
|
Chris@0
|
1576
|
Chris@0
|
1577 $this->markVariableAssignment($varName, $writtenPtr, $currScope);
|
Chris@0
|
1578 return true;
|
Chris@0
|
1579
|
Chris@0
|
1580 }//end checkForAssignment()
|
Chris@0
|
1581
|
Chris@0
|
1582
|
Chris@0
|
1583 /**
|
Chris@0
|
1584 * Check if this is a list language construct assignment.
|
Chris@0
|
1585 *
|
Chris@17
|
1586 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1587 * @param int $stackPtr
|
Chris@17
|
1588 * @param string $varName
|
Chris@17
|
1589 * @param string $currScope
|
Chris@0
|
1590 *
|
Chris@0
|
1591 * @return bool
|
Chris@0
|
1592 */
|
Chris@0
|
1593 protected function checkForListAssignment(
|
Chris@17
|
1594 File $phpcsFile,
|
Chris@0
|
1595 $stackPtr,
|
Chris@0
|
1596 $varName,
|
Chris@0
|
1597 $currScope
|
Chris@0
|
1598 ) {
|
Chris@0
|
1599 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1600
|
Chris@0
|
1601 // OK, are we within a list (...) construct?
|
Chris@0
|
1602 if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) {
|
Chris@0
|
1603 return false;
|
Chris@0
|
1604 }
|
Chris@0
|
1605
|
Chris@0
|
1606 $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, ($openPtr - 1), null, true, null, true);
|
Chris@0
|
1607 if (($prevPtr === false) || ($tokens[$prevPtr]['code'] !== T_LIST)) {
|
Chris@0
|
1608 return false;
|
Chris@0
|
1609 }
|
Chris@0
|
1610
|
Chris@0
|
1611 // OK, we're a list (...) construct... are we being assigned to?
|
Chris@0
|
1612 $closePtr = $tokens[$openPtr]['parenthesis_closer'];
|
Chris@0
|
1613 if (($assignPtr = $this->isNextThingAnAssign($phpcsFile, $closePtr)) === false) {
|
Chris@0
|
1614 return false;
|
Chris@0
|
1615 }
|
Chris@0
|
1616
|
Chris@0
|
1617 // Yes, we're being assigned.
|
Chris@0
|
1618 $writtenPtr = $this->findWhereAssignExecuted($phpcsFile, $assignPtr);
|
Chris@0
|
1619 $this->markVariableAssignment($varName, $writtenPtr, $currScope);
|
Chris@0
|
1620 return true;
|
Chris@0
|
1621
|
Chris@0
|
1622 }//end checkForListAssignment()
|
Chris@0
|
1623
|
Chris@0
|
1624
|
Chris@0
|
1625 /**
|
Chris@0
|
1626 * Check if this variable is declared globally.
|
Chris@0
|
1627 *
|
Chris@17
|
1628 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1629 * @param int $stackPtr
|
Chris@17
|
1630 * @param string $varName
|
Chris@17
|
1631 * @param string $currScope
|
Chris@0
|
1632 *
|
Chris@0
|
1633 * @return bool
|
Chris@0
|
1634 */
|
Chris@0
|
1635 protected function checkForGlobalDeclaration(
|
Chris@17
|
1636 File $phpcsFile,
|
Chris@0
|
1637 $stackPtr,
|
Chris@0
|
1638 $varName,
|
Chris@0
|
1639 $currScope
|
Chris@0
|
1640 ) {
|
Chris@0
|
1641 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1642
|
Chris@0
|
1643 // Are we a global declaration?
|
Chris@0
|
1644 // Search backwards for first token that isn't whitespace, comma or variable.
|
Chris@0
|
1645 $globalPtr = $phpcsFile->findPrevious(
|
Chris@0
|
1646 array(
|
Chris@0
|
1647 T_WHITESPACE,
|
Chris@0
|
1648 T_VARIABLE,
|
Chris@0
|
1649 T_COMMA,
|
Chris@0
|
1650 ),
|
Chris@0
|
1651 ($stackPtr - 1),
|
Chris@0
|
1652 null,
|
Chris@0
|
1653 true,
|
Chris@0
|
1654 null,
|
Chris@0
|
1655 true
|
Chris@0
|
1656 );
|
Chris@0
|
1657 if (($globalPtr === false) || ($tokens[$globalPtr]['code'] !== T_GLOBAL)) {
|
Chris@0
|
1658 return false;
|
Chris@0
|
1659 }
|
Chris@0
|
1660
|
Chris@0
|
1661 // It's a global declaration.
|
Chris@0
|
1662 $this->markVariableDeclaration($varName, 'global', null, $stackPtr, $currScope);
|
Chris@0
|
1663 // Also mark this variable as being a reference, so that we don't get
|
Chris@0
|
1664 // unused variable warnings if it is never read.
|
Chris@0
|
1665 $varInfo = $this->getVariableInfo($varName, $currScope);
|
Chris@0
|
1666 $varInfo->passByReference = true;
|
Chris@0
|
1667 return true;
|
Chris@0
|
1668
|
Chris@0
|
1669 }//end checkForGlobalDeclaration()
|
Chris@0
|
1670
|
Chris@0
|
1671
|
Chris@0
|
1672 /**
|
Chris@0
|
1673 * Check is this is a static variable declaration.
|
Chris@0
|
1674 *
|
Chris@17
|
1675 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1676 * @param int $stackPtr
|
Chris@17
|
1677 * @param string $varName
|
Chris@17
|
1678 * @param string $currScope
|
Chris@0
|
1679 *
|
Chris@0
|
1680 * @return bool
|
Chris@0
|
1681 */
|
Chris@0
|
1682 protected function checkForStaticDeclaration(
|
Chris@17
|
1683 File $phpcsFile,
|
Chris@0
|
1684 $stackPtr,
|
Chris@0
|
1685 $varName,
|
Chris@0
|
1686 $currScope
|
Chris@0
|
1687 ) {
|
Chris@0
|
1688 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1689
|
Chris@0
|
1690 // Are we a static declaration?
|
Chris@0
|
1691 // Static declarations are a bit more complicated than globals, since they
|
Chris@0
|
1692 // can contain assignments. The assignment is compile-time however so can
|
Chris@0
|
1693 // only be constant values, which makes life manageable.
|
Chris@0
|
1694 //
|
Chris@0
|
1695 // Just to complicate matters further, late static binding constants
|
Chris@0
|
1696 // take the form static::CONSTANT and are invalid within static variable
|
Chris@0
|
1697 // assignments, but we don't want to accidentally match their use of the
|
Chris@0
|
1698 // static keyword.
|
Chris@0
|
1699 //
|
Chris@0
|
1700 // Valid values are:
|
Chris@0
|
1701 // number T_MINUS T_LNUMBER T_DNUMBER
|
Chris@0
|
1702 // string T_CONSTANT_ENCAPSED_STRING
|
Chris@0
|
1703 // heredoc T_START_HEREDOC T_HEREDOC T_END_HEREDOC
|
Chris@0
|
1704 // nowdoc T_START_NOWDOC T_NOWDOC T_END_NOWDOC
|
Chris@0
|
1705 // define T_STRING
|
Chris@0
|
1706 // class constant T_STRING T_DOUBLE_COLON T_STRING
|
Chris@0
|
1707 // Search backwards for first token that isn't whitespace, comma, variable,
|
Chris@0
|
1708 // equals, or on the list of assignable constant values above.
|
Chris@0
|
1709 $staticPtr = $phpcsFile->findPrevious(
|
Chris@0
|
1710 array(
|
Chris@0
|
1711 T_WHITESPACE,
|
Chris@0
|
1712 T_VARIABLE,
|
Chris@0
|
1713 T_COMMA,
|
Chris@0
|
1714 T_EQUAL,
|
Chris@0
|
1715 T_MINUS,
|
Chris@0
|
1716 T_LNUMBER,
|
Chris@0
|
1717 T_DNUMBER,
|
Chris@0
|
1718 T_CONSTANT_ENCAPSED_STRING,
|
Chris@0
|
1719 T_STRING,
|
Chris@0
|
1720 T_DOUBLE_COLON,
|
Chris@0
|
1721 T_START_HEREDOC,
|
Chris@0
|
1722 T_HEREDOC,
|
Chris@0
|
1723 T_END_HEREDOC,
|
Chris@0
|
1724 T_START_NOWDOC,
|
Chris@0
|
1725 T_NOWDOC,
|
Chris@0
|
1726 T_END_NOWDOC,
|
Chris@0
|
1727 ),
|
Chris@0
|
1728 ($stackPtr - 1),
|
Chris@0
|
1729 null,
|
Chris@0
|
1730 true,
|
Chris@0
|
1731 null,
|
Chris@0
|
1732 true
|
Chris@0
|
1733 );
|
Chris@0
|
1734 if (($staticPtr === false) || ($tokens[$staticPtr]['code'] !== T_STATIC)) {
|
Chris@0
|
1735 // Debug code.
|
Chris@0
|
1736 // if ($varName == 'static4') {
|
Chris@0
|
1737 // echo "Failing token:\n" . print_r($tokens[$staticPtr], true);
|
Chris@0
|
1738 // }
|
Chris@0
|
1739 // End: Debug code.
|
Chris@0
|
1740 return false;
|
Chris@0
|
1741 }
|
Chris@0
|
1742
|
Chris@0
|
1743 // Is it a late static binding static::?
|
Chris@0
|
1744 // If so, this isn't the static keyword we're looking for, but since
|
Chris@0
|
1745 // static:: isn't allowed in a compile-time constant, we also know
|
Chris@0
|
1746 // we can't be part of a static declaration anyway, so there's no
|
Chris@0
|
1747 // need to look any further.
|
Chris@0
|
1748 $lateStaticBindingPtr = $phpcsFile->findNext(T_WHITESPACE, ($staticPtr + 1), null, true, null, true);
|
Chris@0
|
1749 if (($lateStaticBindingPtr !== false) && ($tokens[$lateStaticBindingPtr]['code'] === T_DOUBLE_COLON)) {
|
Chris@0
|
1750 return false;
|
Chris@0
|
1751 }
|
Chris@0
|
1752
|
Chris@0
|
1753 // It's a static declaration.
|
Chris@0
|
1754 $this->markVariableDeclaration($varName, 'static', null, $stackPtr, $currScope);
|
Chris@0
|
1755 if ($this->isNextThingAnAssign($phpcsFile, $stackPtr) !== false) {
|
Chris@0
|
1756 $this->markVariableAssignment($varName, $stackPtr, $currScope);
|
Chris@0
|
1757 }
|
Chris@0
|
1758
|
Chris@0
|
1759 return true;
|
Chris@0
|
1760
|
Chris@0
|
1761 }//end checkForStaticDeclaration()
|
Chris@0
|
1762
|
Chris@0
|
1763
|
Chris@0
|
1764 /**
|
Chris@0
|
1765 * Check if this is a foreach loop variable.
|
Chris@0
|
1766 *
|
Chris@17
|
1767 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1768 * @param int $stackPtr
|
Chris@17
|
1769 * @param string $varName
|
Chris@17
|
1770 * @param string $currScope
|
Chris@0
|
1771 *
|
Chris@0
|
1772 * @return bool
|
Chris@0
|
1773 */
|
Chris@0
|
1774 protected function checkForForeachLoopVar(
|
Chris@17
|
1775 File $phpcsFile,
|
Chris@0
|
1776 $stackPtr,
|
Chris@0
|
1777 $varName,
|
Chris@0
|
1778 $currScope
|
Chris@0
|
1779 ) {
|
Chris@0
|
1780 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1781
|
Chris@0
|
1782 // Are we a foreach loopvar?
|
Chris@0
|
1783 if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) {
|
Chris@0
|
1784 return false;
|
Chris@0
|
1785 }
|
Chris@0
|
1786
|
Chris@0
|
1787 // Is there an 'as' token between us and the opening bracket?
|
Chris@0
|
1788 if ($phpcsFile->findPrevious(T_AS, ($stackPtr - 1), $openPtr) === false) {
|
Chris@0
|
1789 return false;
|
Chris@0
|
1790 }
|
Chris@0
|
1791
|
Chris@0
|
1792 $this->markVariableAssignment($varName, $stackPtr, $currScope);
|
Chris@0
|
1793
|
Chris@0
|
1794 // Workaround: We want to allow foreach ($array as $key => $value) where
|
Chris@0
|
1795 // $value is never read, so we just mark it read immediately here.
|
Chris@0
|
1796 if ($phpcsFile->findPrevious(T_DOUBLE_ARROW, ($stackPtr - 1), $openPtr) !== false) {
|
Chris@0
|
1797 $this->markVariableRead($varName, $stackPtr, $currScope);
|
Chris@0
|
1798 }
|
Chris@0
|
1799
|
Chris@0
|
1800 // Foreach variables that are read as references like
|
Chris@0
|
1801 // foreach ($array as &$value) should not throw unused variable errors.
|
Chris@0
|
1802 if (($refPtr = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true)) !== false
|
Chris@0
|
1803 && $tokens[$refPtr]['code'] === T_BITWISE_AND
|
Chris@0
|
1804 ) {
|
Chris@0
|
1805 $varInfo = $this->getVariableInfo($varName, $currScope);
|
Chris@0
|
1806 $varInfo->passByReference = true;
|
Chris@0
|
1807 }
|
Chris@0
|
1808
|
Chris@0
|
1809 return true;
|
Chris@0
|
1810
|
Chris@0
|
1811 }//end checkForForeachLoopVar()
|
Chris@0
|
1812
|
Chris@0
|
1813
|
Chris@0
|
1814 /**
|
Chris@0
|
1815 * Check if this is a "&" function call.
|
Chris@0
|
1816 *
|
Chris@17
|
1817 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1818 * @param int $stackPtr
|
Chris@17
|
1819 * @param string $varName
|
Chris@17
|
1820 * @param string $currScope
|
Chris@0
|
1821 *
|
Chris@0
|
1822 * @return bool
|
Chris@0
|
1823 */
|
Chris@0
|
1824 protected function checkForPassByReferenceFunctionCall(
|
Chris@17
|
1825 File $phpcsFile,
|
Chris@0
|
1826 $stackPtr,
|
Chris@0
|
1827 $varName,
|
Chris@0
|
1828 $currScope
|
Chris@0
|
1829 ) {
|
Chris@0
|
1830 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1831 $token = $tokens[$stackPtr];
|
Chris@0
|
1832
|
Chris@0
|
1833 // Are we pass-by-reference to known pass-by-reference function?
|
Chris@0
|
1834 if (($functionPtr = $this->findFunctionCall($phpcsFile, $stackPtr)) === false) {
|
Chris@0
|
1835 return false;
|
Chris@0
|
1836 }
|
Chris@0
|
1837
|
Chris@0
|
1838 // Is our function a known pass-by-reference function?
|
Chris@0
|
1839 $functionName = $tokens[$functionPtr]['content'];
|
Chris@0
|
1840 if (isset($this->_passByRefFunctions[$functionName]) === false) {
|
Chris@0
|
1841 return false;
|
Chris@0
|
1842 }
|
Chris@0
|
1843
|
Chris@0
|
1844 $refArgs = $this->_passByRefFunctions[$functionName];
|
Chris@0
|
1845
|
Chris@0
|
1846 if (($argPtrs = $this->findFunctionCallArguments($phpcsFile, $stackPtr)) === false) {
|
Chris@0
|
1847 return false;
|
Chris@0
|
1848 }
|
Chris@0
|
1849
|
Chris@0
|
1850 // We're within a function call arguments list, find which arg we are.
|
Chris@0
|
1851 $argPos = false;
|
Chris@0
|
1852 foreach ($argPtrs as $idx => $ptrs) {
|
Chris@0
|
1853 if (in_array($stackPtr, $ptrs) === true) {
|
Chris@0
|
1854 $argPos = ($idx + 1);
|
Chris@0
|
1855 break;
|
Chris@0
|
1856 }
|
Chris@0
|
1857 }
|
Chris@0
|
1858
|
Chris@0
|
1859 if ($argPos === false) {
|
Chris@0
|
1860 return false;
|
Chris@0
|
1861 }
|
Chris@0
|
1862
|
Chris@0
|
1863 if (in_array($argPos, $refArgs) === false) {
|
Chris@0
|
1864 // Our arg wasn't mentioned explicitly, are we after an elipsis catch-all?
|
Chris@0
|
1865 if (($elipsis = array_search('...', $refArgs)) === false) {
|
Chris@0
|
1866 return false;
|
Chris@0
|
1867 }
|
Chris@0
|
1868
|
Chris@0
|
1869 if ($argPos < $refArgs[($elipsis - 1)]) {
|
Chris@0
|
1870 return false;
|
Chris@0
|
1871 }
|
Chris@0
|
1872 }
|
Chris@0
|
1873
|
Chris@0
|
1874 // Our argument position matches that of a pass-by-ref argument,
|
Chris@0
|
1875 // check that we're the only part of the argument expression.
|
Chris@0
|
1876 foreach ($argPtrs[($argPos - 1)] as $ptr) {
|
Chris@0
|
1877 if ($ptr === $stackPtr) {
|
Chris@0
|
1878 continue;
|
Chris@0
|
1879 }
|
Chris@0
|
1880
|
Chris@0
|
1881 if ($tokens[$ptr]['code'] !== T_WHITESPACE) {
|
Chris@0
|
1882 return false;
|
Chris@0
|
1883 }
|
Chris@0
|
1884 }
|
Chris@0
|
1885
|
Chris@0
|
1886 // Just us, we can mark it as a write.
|
Chris@0
|
1887 $this->markVariableAssignment($varName, $stackPtr, $currScope);
|
Chris@0
|
1888 // It's a read as well for purposes of used-variables.
|
Chris@0
|
1889 $this->markVariableRead($varName, $stackPtr, $currScope);
|
Chris@0
|
1890 return true;
|
Chris@0
|
1891
|
Chris@0
|
1892 }//end checkForPassByReferenceFunctionCall()
|
Chris@0
|
1893
|
Chris@0
|
1894
|
Chris@0
|
1895 /**
|
Chris@0
|
1896 * Check if the variable is an object property.
|
Chris@0
|
1897 *
|
Chris@17
|
1898 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
1899 * @param int $stackPtr
|
Chris@17
|
1900 * @param string $varName
|
Chris@17
|
1901 * @param string $currScope
|
Chris@0
|
1902 *
|
Chris@0
|
1903 * @return bool
|
Chris@0
|
1904 */
|
Chris@0
|
1905 protected function checkForSymbolicObjectProperty(
|
Chris@17
|
1906 File $phpcsFile,
|
Chris@0
|
1907 $stackPtr,
|
Chris@0
|
1908 $varName,
|
Chris@0
|
1909 $currScope
|
Chris@0
|
1910 ) {
|
Chris@0
|
1911 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1912 $token = $tokens[$stackPtr];
|
Chris@0
|
1913
|
Chris@0
|
1914 // Are we a symbolic object property/function derefeference?
|
Chris@0
|
1915 // Search backwards for first token that isn't whitespace, is it a "->" operator?
|
Chris@0
|
1916 $objectOperatorPtr = $phpcsFile->findPrevious(
|
Chris@0
|
1917 T_WHITESPACE,
|
Chris@0
|
1918 ($stackPtr - 1),
|
Chris@0
|
1919 null,
|
Chris@0
|
1920 true,
|
Chris@0
|
1921 null,
|
Chris@0
|
1922 true
|
Chris@0
|
1923 );
|
Chris@0
|
1924 if (($objectOperatorPtr === false) || ($tokens[$objectOperatorPtr]['code'] !== T_OBJECT_OPERATOR)) {
|
Chris@0
|
1925 return false;
|
Chris@0
|
1926 }
|
Chris@0
|
1927
|
Chris@0
|
1928 $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope);
|
Chris@0
|
1929 return true;
|
Chris@0
|
1930
|
Chris@0
|
1931 }//end checkForSymbolicObjectProperty()
|
Chris@0
|
1932
|
Chris@0
|
1933
|
Chris@0
|
1934 /**
|
Chris@0
|
1935 * Called to process class member vars.
|
Chris@0
|
1936 *
|
Chris@17
|
1937 * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this
|
Chris@17
|
1938 * token was found.
|
Chris@17
|
1939 * @param int $stackPtr The position where the token was found.
|
Chris@0
|
1940 *
|
Chris@0
|
1941 * @return void
|
Chris@0
|
1942 */
|
Chris@0
|
1943 protected function processMemberVar(
|
Chris@17
|
1944 File $phpcsFile,
|
Chris@0
|
1945 $stackPtr
|
Chris@0
|
1946 ) {
|
Chris@0
|
1947 // TODO: don't care for now.
|
Chris@0
|
1948 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1949 $token = $tokens[$stackPtr];
|
Chris@0
|
1950
|
Chris@0
|
1951 }//end processMemberVar()
|
Chris@0
|
1952
|
Chris@0
|
1953
|
Chris@0
|
1954 /**
|
Chris@0
|
1955 * Called to process normal member vars.
|
Chris@0
|
1956 *
|
Chris@17
|
1957 * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this
|
Chris@17
|
1958 * token was found.
|
Chris@17
|
1959 * @param int $stackPtr The position where the token was found.
|
Chris@0
|
1960 *
|
Chris@0
|
1961 * @return void
|
Chris@0
|
1962 */
|
Chris@0
|
1963 protected function processVariable(
|
Chris@17
|
1964 File $phpcsFile,
|
Chris@0
|
1965 $stackPtr
|
Chris@0
|
1966 ) {
|
Chris@0
|
1967 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
1968 $token = $tokens[$stackPtr];
|
Chris@0
|
1969
|
Chris@0
|
1970 $varName = $this->normalizeVarName($token['content']);
|
Chris@0
|
1971 if (($currScope = $this->findVariableScope($phpcsFile, $stackPtr)) === false) {
|
Chris@0
|
1972 return;
|
Chris@0
|
1973 }
|
Chris@0
|
1974
|
Chris@0
|
1975 // Debug code.
|
Chris@0
|
1976 // static $dump_token = false;
|
Chris@0
|
1977 // if ($varName == 'property') {
|
Chris@0
|
1978 // $dump_token = true;
|
Chris@0
|
1979 // }
|
Chris@0
|
1980 // if ($dump_token) {
|
Chris@0
|
1981 // echo "Found variable {$varName} on line {$token['line']} in scope {$currScope}.\n" . print_r($token, true);
|
Chris@0
|
1982 // echo "Prev:\n" . print_r($tokens[$stackPtr - 1], true);
|
Chris@0
|
1983 // }
|
Chris@0
|
1984 // Determine if variable is being assigned or read.
|
Chris@0
|
1985 // Read methods that preempt assignment:
|
Chris@0
|
1986 // Are we a $object->$property type symbolic reference?
|
Chris@0
|
1987 // Possible assignment methods:
|
Chris@0
|
1988 // Is a mandatory function/closure parameter
|
Chris@0
|
1989 // Is an optional function/closure parameter with non-null value
|
Chris@0
|
1990 // Is closure use declaration of a variable defined within containing scope
|
Chris@0
|
1991 // catch (...) block start
|
Chris@0
|
1992 // $this within a class (but not within a closure).
|
Chris@0
|
1993 // $GLOBALS, $_REQUEST, etc superglobals.
|
Chris@0
|
1994 // $var part of class::$var static member
|
Chris@0
|
1995 // Assignment via =
|
Chris@0
|
1996 // Assignment via list (...) =
|
Chris@0
|
1997 // Declares as a global
|
Chris@0
|
1998 // Declares as a static
|
Chris@0
|
1999 // Assignment via foreach (... as ...) { }
|
Chris@0
|
2000 // Pass-by-reference to known pass-by-reference function
|
Chris@0
|
2001 // Are we a $object->$property type symbolic reference?
|
Chris@0
|
2002 if ($this->checkForSymbolicObjectProperty($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2003 return;
|
Chris@0
|
2004 }
|
Chris@0
|
2005
|
Chris@0
|
2006 // Are we a function or closure parameter?
|
Chris@0
|
2007 if ($this->checkForFunctionPrototype($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2008 return;
|
Chris@0
|
2009 }
|
Chris@0
|
2010
|
Chris@0
|
2011 // Are we a catch parameter?
|
Chris@0
|
2012 if ($this->checkForCatchBlock($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2013 return;
|
Chris@0
|
2014 }
|
Chris@0
|
2015
|
Chris@0
|
2016 // Are we $this within a class?
|
Chris@0
|
2017 if ($this->checkForThisWithinClass($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2018 return;
|
Chris@0
|
2019 }
|
Chris@0
|
2020
|
Chris@0
|
2021 // Are we a $GLOBALS, $_REQUEST, etc superglobal?
|
Chris@0
|
2022 if ($this->checkForSuperGlobal($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2023 return;
|
Chris@0
|
2024 }
|
Chris@0
|
2025
|
Chris@0
|
2026 // $var part of class::$var static member
|
Chris@0
|
2027 if ($this->checkForStaticMember($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2028 return;
|
Chris@0
|
2029 }
|
Chris@0
|
2030
|
Chris@0
|
2031 // Is the next non-whitespace an assignment?
|
Chris@0
|
2032 if ($this->checkForAssignment($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2033 return;
|
Chris@0
|
2034 }
|
Chris@0
|
2035
|
Chris@0
|
2036 // OK, are we within a list (...) = construct?
|
Chris@0
|
2037 if ($this->checkForListAssignment($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2038 return;
|
Chris@0
|
2039 }
|
Chris@0
|
2040
|
Chris@0
|
2041 // Are we a global declaration?
|
Chris@0
|
2042 if ($this->checkForGlobalDeclaration($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2043 return;
|
Chris@0
|
2044 }
|
Chris@0
|
2045
|
Chris@0
|
2046 // Are we a static declaration?
|
Chris@0
|
2047 if ($this->checkForStaticDeclaration($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2048 return;
|
Chris@0
|
2049 }
|
Chris@0
|
2050
|
Chris@0
|
2051 // Are we a foreach loopvar?
|
Chris@0
|
2052 if ($this->checkForForeachLoopVar($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2053 return;
|
Chris@0
|
2054 }
|
Chris@0
|
2055
|
Chris@0
|
2056 // Are we pass-by-reference to known pass-by-reference function?
|
Chris@0
|
2057 if ($this->checkForPassByReferenceFunctionCall($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2058 return;
|
Chris@0
|
2059 }
|
Chris@0
|
2060
|
Chris@0
|
2061 // OK, we don't appear to be a write to the var, assume we're a read.
|
Chris@0
|
2062 $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope);
|
Chris@0
|
2063
|
Chris@0
|
2064 }//end processVariable()
|
Chris@0
|
2065
|
Chris@0
|
2066
|
Chris@0
|
2067 /**
|
Chris@0
|
2068 * Called to process variables found in double quoted strings.
|
Chris@0
|
2069 *
|
Chris@0
|
2070 * Note that there may be more than one variable in the string, which will
|
Chris@0
|
2071 * result only in one call for the string.
|
Chris@0
|
2072 *
|
Chris@17
|
2073 * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this
|
Chris@17
|
2074 * token was found.
|
Chris@17
|
2075 * @param int $stackPtr The position where the double quoted
|
Chris@17
|
2076 * string was found.
|
Chris@0
|
2077 *
|
Chris@0
|
2078 * @return void
|
Chris@0
|
2079 */
|
Chris@0
|
2080 protected function processVariableInString(
|
Chris@17
|
2081 File
|
Chris@0
|
2082 $phpcsFile,
|
Chris@0
|
2083 $stackPtr
|
Chris@0
|
2084 ) {
|
Chris@0
|
2085 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
2086 $token = $tokens[$stackPtr];
|
Chris@0
|
2087
|
Chris@0
|
2088 $runMatch = preg_match_all($this->_double_quoted_variable_regexp, $token['content'], $matches);
|
Chris@0
|
2089 if ($runMatch === 0 || $runMatch === false) {
|
Chris@0
|
2090 return;
|
Chris@0
|
2091 }
|
Chris@0
|
2092
|
Chris@0
|
2093 $currScope = $this->findVariableScope($phpcsFile, $stackPtr);
|
Chris@0
|
2094 foreach ($matches[1] as $varName) {
|
Chris@0
|
2095 $varName = $this->normalizeVarName($varName);
|
Chris@0
|
2096 // Are we $this within a class?
|
Chris@0
|
2097 if ($this->checkForThisWithinClass($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2098 continue;
|
Chris@0
|
2099 }
|
Chris@0
|
2100
|
Chris@0
|
2101 if ($this->checkForSuperGlobal($phpcsFile, $stackPtr, $varName, $currScope) === true) {
|
Chris@0
|
2102 continue;
|
Chris@0
|
2103 }
|
Chris@0
|
2104
|
Chris@0
|
2105 $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope);
|
Chris@0
|
2106 }
|
Chris@0
|
2107
|
Chris@0
|
2108 }//end processVariableInString()
|
Chris@0
|
2109
|
Chris@0
|
2110
|
Chris@0
|
2111 /**
|
Chris@0
|
2112 * Check variables in a compact() call.
|
Chris@0
|
2113 *
|
Chris@17
|
2114 * @param \PHP_CodeSniffer\Files\File $phpcsFile
|
Chris@17
|
2115 * @param int $stackPtr
|
Chris@17
|
2116 * @param array $arguments
|
Chris@17
|
2117 * @param string $currScope
|
Chris@0
|
2118 *
|
Chris@0
|
2119 * @return void
|
Chris@0
|
2120 */
|
Chris@0
|
2121 protected function processCompactArguments(
|
Chris@17
|
2122 File
|
Chris@0
|
2123 $phpcsFile,
|
Chris@0
|
2124 $stackPtr,
|
Chris@0
|
2125 $arguments,
|
Chris@0
|
2126 $currScope
|
Chris@0
|
2127 ) {
|
Chris@0
|
2128 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
2129
|
Chris@0
|
2130 foreach ($arguments as $argumentPtrs) {
|
Chris@0
|
2131 $argumentPtrs = array_values(
|
Chris@0
|
2132 array_filter(
|
Chris@0
|
2133 $argumentPtrs,
|
Chris@0
|
2134 function ($argumentPtr) use ($tokens) {
|
Chris@0
|
2135 return $tokens[$argumentPtr]['code'] !== T_WHITESPACE;
|
Chris@0
|
2136 }
|
Chris@0
|
2137 )
|
Chris@0
|
2138 );
|
Chris@0
|
2139 if (empty($argumentPtrs) === true) {
|
Chris@0
|
2140 continue;
|
Chris@0
|
2141 }
|
Chris@0
|
2142
|
Chris@0
|
2143 if (isset($tokens[$argumentPtrs[0]]) === false) {
|
Chris@0
|
2144 continue;
|
Chris@0
|
2145 }
|
Chris@0
|
2146
|
Chris@0
|
2147 $argument_first_token = $tokens[$argumentPtrs[0]];
|
Chris@0
|
2148 if ($argument_first_token['code'] === T_ARRAY) {
|
Chris@0
|
2149 // It's an array argument, recurse.
|
Chris@0
|
2150 if (($array_arguments = $this->findFunctionCallArguments($phpcsFile, $argumentPtrs[0])) !== false) {
|
Chris@0
|
2151 $this->processCompactArguments($phpcsFile, $stackPtr, $array_arguments, $currScope);
|
Chris@0
|
2152 }
|
Chris@0
|
2153
|
Chris@0
|
2154 continue;
|
Chris@0
|
2155 }
|
Chris@0
|
2156
|
Chris@0
|
2157 if (count($argumentPtrs) > 1) {
|
Chris@0
|
2158 // Complex argument, we can't handle it, ignore.
|
Chris@0
|
2159 continue;
|
Chris@0
|
2160 }
|
Chris@0
|
2161
|
Chris@0
|
2162 if ($argument_first_token['code'] === T_CONSTANT_ENCAPSED_STRING) {
|
Chris@0
|
2163 // Single-quoted string literal, ie compact('whatever').
|
Chris@0
|
2164 // Substr is to strip the enclosing single-quotes.
|
Chris@0
|
2165 $varName = substr($argument_first_token['content'], 1, -1);
|
Chris@0
|
2166 $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $argumentPtrs[0], $currScope);
|
Chris@0
|
2167 continue;
|
Chris@0
|
2168 }
|
Chris@0
|
2169
|
Chris@0
|
2170 if ($argument_first_token['code'] === T_DOUBLE_QUOTED_STRING) {
|
Chris@0
|
2171 // Double-quoted string literal.
|
Chris@0
|
2172 if (preg_match($this->_double_quoted_variable_regexp, $argument_first_token['content']) === 1) {
|
Chris@0
|
2173 // Bail if the string needs variable expansion, that's runtime stuff.
|
Chris@0
|
2174 continue;
|
Chris@0
|
2175 }
|
Chris@0
|
2176
|
Chris@0
|
2177 // Substr is to strip the enclosing double-quotes.
|
Chris@0
|
2178 $varName = substr($argument_first_token['content'], 1, -1);
|
Chris@0
|
2179 $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $argumentPtrs[0], $currScope);
|
Chris@0
|
2180 continue;
|
Chris@0
|
2181 }
|
Chris@0
|
2182 }//end foreach
|
Chris@0
|
2183
|
Chris@0
|
2184 }//end processCompactArguments()
|
Chris@0
|
2185
|
Chris@0
|
2186
|
Chris@0
|
2187 /**
|
Chris@0
|
2188 * Called to process variables named in a call to compact().
|
Chris@0
|
2189 *
|
Chris@17
|
2190 * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this
|
Chris@17
|
2191 * token was found.
|
Chris@17
|
2192 * @param int $stackPtr The position where the call to compact()
|
Chris@17
|
2193 * was found.
|
Chris@0
|
2194 *
|
Chris@0
|
2195 * @return void
|
Chris@0
|
2196 */
|
Chris@0
|
2197 protected function processCompact(
|
Chris@17
|
2198 File
|
Chris@0
|
2199 $phpcsFile,
|
Chris@0
|
2200 $stackPtr
|
Chris@0
|
2201 ) {
|
Chris@0
|
2202 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
2203 $token = $tokens[$stackPtr];
|
Chris@0
|
2204
|
Chris@0
|
2205 $currScope = $this->findVariableScope($phpcsFile, $stackPtr);
|
Chris@0
|
2206
|
Chris@0
|
2207 if (($arguments = $this->findFunctionCallArguments($phpcsFile, $stackPtr)) !== false) {
|
Chris@0
|
2208 $this->processCompactArguments($phpcsFile, $stackPtr, $arguments, $currScope);
|
Chris@0
|
2209 }
|
Chris@0
|
2210
|
Chris@0
|
2211 }//end processCompact()
|
Chris@0
|
2212
|
Chris@0
|
2213
|
Chris@0
|
2214 /**
|
Chris@0
|
2215 * Called to process the end of a scope.
|
Chris@0
|
2216 *
|
Chris@0
|
2217 * Note that although triggered by the closing curly brace of the scope, $stackPtr is
|
Chris@0
|
2218 * the scope conditional, not the closing curly brace.
|
Chris@0
|
2219 *
|
Chris@17
|
2220 * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this
|
Chris@17
|
2221 * token was found.
|
Chris@17
|
2222 * @param int $stackPtr The position of the scope conditional.
|
Chris@0
|
2223 *
|
Chris@0
|
2224 * @return void
|
Chris@0
|
2225 */
|
Chris@0
|
2226 protected function processScopeClose(
|
Chris@17
|
2227 File
|
Chris@0
|
2228 $phpcsFile,
|
Chris@0
|
2229 $stackPtr
|
Chris@0
|
2230 ) {
|
Chris@0
|
2231 $scopeInfo = $this->getScopeInfo($stackPtr, false);
|
Chris@0
|
2232 if (is_null($scopeInfo) === true) {
|
Chris@0
|
2233 return;
|
Chris@0
|
2234 }
|
Chris@0
|
2235
|
Chris@0
|
2236 foreach ($scopeInfo->variables as $varInfo) {
|
Chris@0
|
2237 if (($varInfo->ignoreUnused === true) || (isset($varInfo->firstRead) === true)) {
|
Chris@0
|
2238 continue;
|
Chris@0
|
2239 }
|
Chris@0
|
2240
|
Chris@0
|
2241 if (($this->allowUnusedFunctionParameters === true) && ($varInfo->scopeType === 'param')) {
|
Chris@0
|
2242 continue;
|
Chris@0
|
2243 }
|
Chris@0
|
2244
|
Chris@0
|
2245 if (($varInfo->passByReference === true) && isset($varInfo->lastAssignment) === true) {
|
Chris@0
|
2246 // If we're pass-by-reference then it's a common pattern to
|
Chris@0
|
2247 // use the variable to return data to the caller, so any
|
Chris@0
|
2248 // assignment also counts as "variable use" for the purposes
|
Chris@0
|
2249 // of "unused variable" warnings.
|
Chris@0
|
2250 continue;
|
Chris@0
|
2251 }
|
Chris@0
|
2252
|
Chris@0
|
2253 if (isset($varInfo->firstDeclared) === true) {
|
Chris@0
|
2254 $phpcsFile->addWarning(
|
Chris@0
|
2255 "Unused %s %s.",
|
Chris@0
|
2256 $varInfo->firstDeclared,
|
Chris@0
|
2257 'UnusedVariable',
|
Chris@0
|
2258 array(
|
Chris@0
|
2259 VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType],
|
Chris@0
|
2260 "\${$varInfo->name}",
|
Chris@0
|
2261 )
|
Chris@0
|
2262 );
|
Chris@0
|
2263 } else if (isset($varInfo->firstInitialized) === true) {
|
Chris@0
|
2264 $phpcsFile->addWarning(
|
Chris@0
|
2265 "Unused %s %s.",
|
Chris@0
|
2266 $varInfo->firstInitialized,
|
Chris@0
|
2267 'UnusedVariable',
|
Chris@0
|
2268 array(
|
Chris@0
|
2269 VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType],
|
Chris@0
|
2270 "\${$varInfo->name}",
|
Chris@0
|
2271 )
|
Chris@0
|
2272 );
|
Chris@0
|
2273 }//end if
|
Chris@0
|
2274 }//end foreach
|
Chris@0
|
2275
|
Chris@0
|
2276 }//end processScopeClose()
|
Chris@0
|
2277
|
Chris@0
|
2278
|
Chris@0
|
2279 }//end class
|