This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | require_once('command_functions.php'); |
||
3 | |||
4 | use Psalm\ErrorBaseline; |
||
5 | use Psalm\Internal\Analyzer\ProjectAnalyzer; |
||
6 | use Psalm\Internal\Provider; |
||
7 | use Psalm\Config; |
||
8 | use Psalm\Internal\IncludeCollector; |
||
9 | use Psalm\IssueBuffer; |
||
10 | use Psalm\Progress\DebugProgress; |
||
11 | use Psalm\Progress\DefaultProgress; |
||
12 | use Psalm\Progress\LongProgress; |
||
13 | use Psalm\Progress\VoidProgress; |
||
14 | |||
15 | // show all errors |
||
16 | error_reporting(-1); |
||
17 | |||
18 | $valid_short_options = [ |
||
19 | 'f:', |
||
20 | 'm', |
||
21 | 'h', |
||
22 | 'v', |
||
23 | 'c:', |
||
24 | 'i', |
||
25 | 'r:', |
||
26 | ]; |
||
27 | |||
28 | $valid_long_options = [ |
||
29 | 'clear-cache', |
||
30 | 'clear-global-cache', |
||
31 | 'config:', |
||
32 | 'debug', |
||
33 | 'debug-by-line', |
||
34 | 'debug-emitted-issues', |
||
35 | 'diff', |
||
36 | 'diff-methods', |
||
37 | 'disable-extension:', |
||
38 | 'find-dead-code::', |
||
39 | 'find-unused-code::', |
||
40 | 'find-unused-variables', |
||
41 | 'find-references-to:', |
||
42 | 'help', |
||
43 | 'ignore-baseline', |
||
44 | 'init', |
||
45 | 'monochrome', |
||
46 | 'no-cache', |
||
47 | 'no-reflection-cache', |
||
48 | 'no-file-cache', |
||
49 | 'output-format:', |
||
50 | 'plugin:', |
||
51 | 'report:', |
||
52 | 'report-show-info:', |
||
53 | 'root:', |
||
54 | 'set-baseline:', |
||
55 | 'show-info:', |
||
56 | 'show-snippet:', |
||
57 | 'stats', |
||
58 | 'threads:', |
||
59 | 'update-baseline', |
||
60 | 'use-baseline:', |
||
61 | 'use-ini-defaults', |
||
62 | 'version', |
||
63 | 'php-version:', |
||
64 | 'generate-json-map:', |
||
65 | 'generate-stubs:', |
||
66 | 'alter', |
||
67 | 'language-server', |
||
68 | 'refactor', |
||
69 | 'shepherd::', |
||
70 | 'no-progress', |
||
71 | 'long-progress', |
||
72 | 'no-suggestions', |
||
73 | 'include-php-versions', // used for baseline |
||
74 | 'pretty-print', // used for JSON reports |
||
75 | 'track-tainted-input', |
||
76 | 'taint-analysis', |
||
77 | 'security-analysis', |
||
78 | 'find-unused-psalm-suppress', |
||
79 | 'error-level:', |
||
80 | ]; |
||
81 | |||
82 | gc_collect_cycles(); |
||
83 | gc_disable(); |
||
84 | |||
85 | $args = array_slice($argv, 1); |
||
86 | |||
87 | // get options from command line |
||
88 | $options = getopt(implode('', $valid_short_options), $valid_long_options); |
||
89 | |||
90 | if (isset($options['alter'])) { |
||
91 | require_once __DIR__ . '/psalter.php'; |
||
92 | exit; |
||
93 | } |
||
94 | |||
95 | if (isset($options['language-server'])) { |
||
96 | require_once __DIR__ . '/psalm-language-server.php'; |
||
97 | exit; |
||
98 | } |
||
99 | |||
100 | if (isset($options['refactor'])) { |
||
101 | require_once __DIR__ . '/psalm-refactor.php'; |
||
102 | exit; |
||
103 | } |
||
104 | |||
105 | require_once __DIR__ . '/Psalm/Internal/exception_handler.php'; |
||
106 | |||
107 | array_map( |
||
108 | /** |
||
109 | * @param string $arg |
||
110 | * |
||
111 | * @return void |
||
112 | */ |
||
113 | View Code Duplication | function ($arg) use ($valid_long_options, $valid_short_options) { |
|
0 ignored issues
–
show
|
|||
114 | if (substr($arg, 0, 2) === '--' && $arg !== '--') { |
||
115 | $arg_name = preg_replace('/=.*$/', '', substr($arg, 2)); |
||
116 | |||
117 | if (!in_array($arg_name, $valid_long_options) |
||
118 | && !in_array($arg_name . ':', $valid_long_options) |
||
119 | && !in_array($arg_name . '::', $valid_long_options) |
||
120 | ) { |
||
121 | fwrite( |
||
122 | STDERR, |
||
123 | 'Unrecognised argument "--' . $arg_name . '"' . PHP_EOL |
||
124 | . 'Type --help to see a list of supported arguments'. PHP_EOL |
||
125 | ); |
||
126 | exit(1); |
||
127 | } |
||
128 | } elseif (substr($arg, 0, 1) === '-' && $arg !== '-' && $arg !== '--') { |
||
129 | $arg_name = preg_replace('/=.*$/', '', substr($arg, 1)); |
||
130 | |||
131 | if (!in_array($arg_name, $valid_short_options) && !in_array($arg_name . ':', $valid_short_options)) { |
||
132 | fwrite( |
||
133 | STDERR, |
||
134 | 'Unrecognised argument "-' . $arg_name . '"' . PHP_EOL |
||
135 | . 'Type --help to see a list of supported arguments'. PHP_EOL |
||
136 | ); |
||
137 | exit(1); |
||
138 | } |
||
139 | } |
||
140 | }, |
||
141 | $args |
||
142 | ); |
||
143 | |||
144 | View Code Duplication | if (!array_key_exists('use-ini-defaults', $options)) { |
|
0 ignored issues
–
show
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. ![]() |
|||
145 | ini_set('display_errors', 'stderr'); |
||
146 | ini_set('display_startup_errors', '1'); |
||
147 | ini_set('memory_limit', (string) (8 * 1024 * 1024 * 1024)); |
||
148 | } |
||
149 | |||
150 | if (array_key_exists('help', $options)) { |
||
151 | $options['h'] = false; |
||
152 | } |
||
153 | |||
154 | if (array_key_exists('version', $options)) { |
||
155 | $options['v'] = false; |
||
156 | } |
||
157 | |||
158 | if (array_key_exists('init', $options)) { |
||
159 | $options['i'] = false; |
||
160 | } |
||
161 | |||
162 | if (array_key_exists('monochrome', $options)) { |
||
163 | $options['m'] = false; |
||
164 | } |
||
165 | |||
166 | if (isset($options['config'])) { |
||
167 | $options['c'] = $options['config']; |
||
168 | } |
||
169 | |||
170 | View Code Duplication | if (isset($options['c']) && is_array($options['c'])) { |
|
0 ignored issues
–
show
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. ![]() |
|||
171 | fwrite(STDERR, 'Too many config files provided' . PHP_EOL); |
||
172 | exit(1); |
||
173 | } |
||
174 | |||
175 | |||
176 | if (array_key_exists('h', $options)) { |
||
177 | echo getPsalmHelpText(); |
||
178 | /* |
||
179 | --shepherd[=host] |
||
180 | Send data to Shepherd, Psalm's GitHub integration tool. |
||
181 | `host` is the location of the Shepherd server. It defaults to shepherd.dev |
||
182 | More information is available at https://psalm.dev/shepherd |
||
183 | */ |
||
184 | |||
185 | exit; |
||
186 | } |
||
187 | |||
188 | View Code Duplication | if (getcwd() === false) { |
|
0 ignored issues
–
show
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. ![]() |
|||
189 | fwrite(STDERR, 'Cannot get current working directory' . PHP_EOL); |
||
190 | exit(1); |
||
191 | } |
||
192 | |||
193 | if (isset($options['root'])) { |
||
194 | $options['r'] = $options['root']; |
||
195 | } |
||
196 | |||
197 | $current_dir = (string)getcwd() . DIRECTORY_SEPARATOR; |
||
198 | |||
199 | View Code Duplication | if (isset($options['r']) && is_string($options['r'])) { |
|
0 ignored issues
–
show
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. ![]() |
|||
200 | $root_path = realpath($options['r']); |
||
201 | |||
202 | if (!$root_path) { |
||
203 | fwrite( |
||
204 | STDERR, |
||
205 | 'Could not locate root directory ' . $current_dir . DIRECTORY_SEPARATOR . $options['r'] . PHP_EOL |
||
206 | ); |
||
207 | exit(1); |
||
208 | } |
||
209 | |||
210 | $current_dir = $root_path . DIRECTORY_SEPARATOR; |
||
211 | } |
||
212 | |||
213 | $path_to_config = get_path_to_config($options); |
||
214 | |||
215 | $vendor_dir = getVendorDir($current_dir); |
||
216 | |||
217 | require_once __DIR__ . '/' . 'Psalm/Internal/IncludeCollector.php'; |
||
218 | |||
219 | $include_collector = new IncludeCollector(); |
||
220 | $first_autoloader = $include_collector->runAndCollect( |
||
221 | function () use ($current_dir, $options, $vendor_dir) { |
||
222 | return requireAutoloaders($current_dir, isset($options['r']), $vendor_dir); |
||
223 | } |
||
224 | ); |
||
225 | |||
226 | |||
227 | if (array_key_exists('v', $options)) { |
||
228 | echo 'Psalm ' . PSALM_VERSION . PHP_EOL; |
||
229 | exit; |
||
230 | } |
||
231 | |||
232 | $output_format = isset($options['output-format']) && is_string($options['output-format']) |
||
233 | ? $options['output-format'] |
||
234 | : \Psalm\Report::TYPE_CONSOLE; |
||
235 | |||
236 | $init_level = null; |
||
237 | $init_source_dir = null; |
||
238 | |||
239 | if (isset($options['i'])) { |
||
240 | if (file_exists($current_dir . 'psalm.xml')) { |
||
241 | die('A config file already exists in the current directory' . PHP_EOL); |
||
242 | } |
||
243 | |||
244 | $args = array_values(array_filter( |
||
245 | $args, |
||
246 | /** |
||
247 | * @param string $arg |
||
248 | * |
||
249 | * @return bool |
||
250 | */ |
||
251 | function ($arg) { |
||
252 | return $arg !== '--ansi' |
||
253 | && $arg !== '--no-ansi' |
||
254 | && $arg !== '-i' |
||
255 | && $arg !== '--init' |
||
256 | && $arg !== '--debug' |
||
257 | && $arg !== '--debug-by-line' |
||
258 | && $arg !== '--debug-emitted-issues' |
||
259 | && strpos($arg, '--disable-extension=') !== 0 |
||
260 | && strpos($arg, '--root=') !== 0 |
||
261 | && strpos($arg, '--r=') !== 0; |
||
262 | } |
||
263 | )); |
||
264 | |||
265 | if (count($args)) { |
||
266 | if (count($args) > 2) { |
||
267 | die('Too many arguments provided for psalm --init' . PHP_EOL); |
||
268 | } |
||
269 | |||
270 | if (isset($args[1])) { |
||
271 | if (!preg_match('/^[1-8]$/', $args[1])) { |
||
272 | die('Config strictness must be a number between 1 and 8 inclusive' . PHP_EOL); |
||
273 | } |
||
274 | |||
275 | $init_level = (int)$args[1]; |
||
276 | } |
||
277 | |||
278 | $init_source_dir = $args[0]; |
||
279 | } |
||
280 | |||
281 | $vendor_dir = getVendorDir($current_dir); |
||
282 | |||
283 | if ($init_level === null) { |
||
284 | echo "Calculating best config level based on project files\n"; |
||
285 | Psalm\Config\Creator::createBareConfig($current_dir, $init_source_dir, $vendor_dir); |
||
286 | $config = \Psalm\Config::getInstance(); |
||
287 | } else { |
||
288 | try { |
||
289 | $template_contents = Psalm\Config\Creator::getContents( |
||
290 | $current_dir, |
||
291 | $init_source_dir, |
||
292 | $init_level, |
||
293 | $vendor_dir |
||
294 | ); |
||
295 | } catch (Psalm\Exception\ConfigCreationException $e) { |
||
296 | die($e->getMessage() . PHP_EOL); |
||
297 | } |
||
298 | |||
299 | if (!file_put_contents($current_dir . 'psalm.xml', $template_contents)) { |
||
300 | die('Could not write to psalm.xml' . PHP_EOL); |
||
301 | } |
||
302 | |||
303 | exit('Config file created successfully. Please re-run psalm.' . PHP_EOL); |
||
304 | } |
||
305 | } else { |
||
306 | $config = initialiseConfig($path_to_config, $current_dir, $output_format, $first_autoloader); |
||
307 | |||
308 | if (isset($options['error-level']) |
||
309 | && is_numeric($options['error-level']) |
||
310 | ) { |
||
311 | $config_level = (int) $options['error-level']; |
||
312 | |||
313 | if (!in_array($config_level, [1, 2, 3, 4, 5, 6, 7, 8], true)) { |
||
314 | throw new \Psalm\Exception\ConfigException( |
||
315 | 'Invalid error level ' . $config_level |
||
316 | ); |
||
317 | } |
||
318 | |||
319 | $config->level = $config_level; |
||
320 | } |
||
321 | } |
||
322 | |||
323 | $config->setIncludeCollector($include_collector); |
||
324 | |||
325 | if ($config->resolve_from_config_file) { |
||
326 | $current_dir = $config->base_dir; |
||
327 | chdir($current_dir); |
||
328 | } |
||
329 | |||
330 | $in_ci = isset($_SERVER['TRAVIS']) |
||
331 | || isset($_SERVER['CIRCLECI']) |
||
332 | || isset($_SERVER['APPVEYOR']) |
||
333 | || isset($_SERVER['JENKINS_URL']) |
||
334 | || isset($_SERVER['SCRUTINIZER']) |
||
335 | || isset($_SERVER['GITLAB_CI']) |
||
336 | || isset($_SERVER['GITHUB_WORKFLOW']); |
||
337 | |||
338 | // disable progressbar on CI |
||
339 | if ($in_ci) { |
||
340 | $options['long-progress'] = true; |
||
341 | } |
||
342 | |||
343 | if (isset($options['threads'])) { |
||
344 | $threads = (int)$options['threads']; |
||
345 | } elseif (isset($options['debug']) || $in_ci) { |
||
346 | $threads = 1; |
||
347 | } else { |
||
348 | $threads = max(1, ProjectAnalyzer::getCpuCount() - 1); |
||
349 | } |
||
350 | |||
351 | if (!isset($options['threads']) |
||
352 | && !isset($options['debug']) |
||
353 | && $threads === 1 |
||
354 | && ini_get('pcre.jit') === '1' |
||
355 | && PHP_OS === 'Darwin' |
||
356 | && version_compare(PHP_VERSION, '7.3.0') >= 0 |
||
357 | && version_compare(PHP_VERSION, '7.4.0') < 0 |
||
358 | ) { |
||
359 | echo( |
||
360 | 'If you want to run Psalm as a language server, or run Psalm with' . PHP_EOL |
||
361 | . 'multiple processes (--threads=4), beware:' . PHP_EOL |
||
362 | . \Psalm\Internal\Fork\Pool::MAC_PCRE_MESSAGE . PHP_EOL . PHP_EOL |
||
363 | ); |
||
364 | } |
||
365 | |||
366 | $ini_handler = new \Psalm\Internal\Fork\PsalmRestarter('PSALM'); |
||
367 | |||
368 | if (isset($options['disable-extension'])) { |
||
369 | if (is_array($options['disable-extension'])) { |
||
370 | /** @psalm-suppress MixedAssignment */ |
||
371 | foreach ($options['disable-extension'] as $extension) { |
||
372 | if (is_string($extension)) { |
||
373 | $ini_handler->disableExtension($extension); |
||
374 | } |
||
375 | } |
||
376 | } elseif (is_string($options['disable-extension'])) { |
||
377 | $ini_handler->disableExtension($options['disable-extension']); |
||
378 | } |
||
379 | } |
||
380 | |||
381 | if ($threads > 1) { |
||
382 | $ini_handler->disableExtension('grpc'); |
||
383 | } |
||
384 | |||
385 | $ini_handler->disableExtension('uopz'); |
||
386 | |||
387 | $type_map_location = null; |
||
388 | |||
389 | if (isset($options['generate-json-map']) && is_string($options['generate-json-map'])) { |
||
390 | $type_map_location = $options['generate-json-map']; |
||
391 | } |
||
392 | |||
393 | $stubs_location = null; |
||
394 | |||
395 | if (isset($options['generate-stubs']) && is_string($options['generate-stubs'])) { |
||
396 | $stubs_location = $options['generate-stubs']; |
||
397 | } |
||
398 | |||
399 | // If Xdebug is enabled, restart without it |
||
400 | $ini_handler->check(); |
||
401 | |||
402 | if (is_null($config->load_xdebug_stub) && '' !== $ini_handler->getSkippedVersion()) { |
||
403 | $config->load_xdebug_stub = true; |
||
404 | } |
||
405 | |||
406 | if (isset($options['debug-emitted-issues'])) { |
||
407 | $config->debug_emitted_issues = true; |
||
408 | } |
||
409 | |||
410 | setlocale(LC_CTYPE, 'C'); |
||
411 | |||
412 | View Code Duplication | if (isset($options['set-baseline'])) { |
|
0 ignored issues
–
show
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. ![]() |
|||
413 | if (is_array($options['set-baseline'])) { |
||
414 | die('Only one baseline file can be created at a time' . PHP_EOL); |
||
415 | } |
||
416 | } |
||
417 | |||
418 | $paths_to_check = getPathsToCheck(isset($options['f']) ? $options['f'] : null); |
||
419 | |||
420 | $plugins = []; |
||
421 | |||
422 | View Code Duplication | if (isset($options['plugin'])) { |
|
0 ignored issues
–
show
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. ![]() |
|||
423 | $plugins = $options['plugin']; |
||
424 | |||
425 | if (!is_array($plugins)) { |
||
426 | $plugins = [$plugins]; |
||
427 | } |
||
428 | } |
||
429 | |||
430 | |||
431 | |||
432 | $show_info = isset($options['show-info']) |
||
433 | ? $options['show-info'] === 'true' || $options['show-info'] === '1' |
||
434 | : false; |
||
435 | |||
436 | $is_diff = isset($options['diff']); |
||
437 | |||
438 | /** @var false|'always'|'auto' $find_unused_code */ |
||
0 ignored issues
–
show
The doc-type
false|'always'|'auto' could not be parsed: Unknown type name "'always'" at position 6. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
439 | $find_unused_code = false; |
||
440 | if (isset($options['find-dead-code'])) { |
||
441 | $options['find-unused-code'] = $options['find-dead-code']; |
||
442 | } |
||
443 | |||
444 | if (isset($options['find-unused-code'])) { |
||
445 | if ($options['find-unused-code'] === 'always') { |
||
446 | $find_unused_code = 'always'; |
||
447 | } else { |
||
448 | $find_unused_code = 'auto'; |
||
449 | } |
||
450 | } |
||
451 | |||
452 | $find_unused_variables = isset($options['find-unused-variables']); |
||
453 | |||
454 | $find_references_to = isset($options['find-references-to']) && is_string($options['find-references-to']) |
||
455 | ? $options['find-references-to'] |
||
456 | : null; |
||
457 | |||
458 | if (isset($options['shepherd'])) { |
||
459 | if (is_string($options['shepherd'])) { |
||
460 | $config->shepherd_host = $options['shepherd']; |
||
461 | } |
||
462 | $shepherd_plugin = __DIR__ . '/Psalm/Plugin/Shepherd.php'; |
||
463 | |||
464 | if (!file_exists($shepherd_plugin)) { |
||
465 | die('Could not find Shepherd plugin location ' . $shepherd_plugin . PHP_EOL); |
||
466 | } |
||
467 | |||
468 | $plugins[] = $shepherd_plugin; |
||
469 | } |
||
470 | |||
471 | View Code Duplication | if (isset($options['clear-cache'])) { |
|
0 ignored issues
–
show
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. ![]() |
|||
472 | $cache_directory = $config->getCacheDirectory(); |
||
473 | |||
474 | Config::removeCacheDirectory($cache_directory); |
||
475 | echo 'Cache directory deleted' . PHP_EOL; |
||
476 | exit; |
||
477 | } |
||
478 | |||
479 | View Code Duplication | if (isset($options['clear-global-cache'])) { |
|
0 ignored issues
–
show
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. ![]() |
|||
480 | $cache_directory = $config->getGlobalCacheDirectory(); |
||
481 | |||
482 | if ($cache_directory) { |
||
483 | Config::removeCacheDirectory($cache_directory); |
||
484 | echo 'Global cache directory deleted' . PHP_EOL; |
||
485 | } |
||
486 | |||
487 | exit; |
||
488 | } |
||
489 | |||
490 | $debug = array_key_exists('debug', $options) || array_key_exists('debug-by-line', $options); |
||
491 | |||
492 | if ($debug) { |
||
493 | $progress = new DebugProgress(); |
||
494 | } elseif (isset($options['no-progress'])) { |
||
495 | $progress = new VoidProgress(); |
||
496 | } else { |
||
497 | $show_errors = !$config->error_baseline || isset($options['ignore-baseline']); |
||
498 | if (isset($options['long-progress'])) { |
||
499 | $progress = new LongProgress($show_errors, $show_info); |
||
500 | } else { |
||
501 | $progress = new DefaultProgress($show_errors, $show_info); |
||
502 | } |
||
503 | } |
||
504 | |||
505 | if (isset($options['no-cache']) || isset($options['i'])) { |
||
506 | $providers = new Provider\Providers( |
||
507 | new Provider\FileProvider |
||
508 | ); |
||
509 | } else { |
||
510 | $no_reflection_cache = isset($options['no-reflection-cache']); |
||
511 | $no_file_cache = isset($options['no-file-cache']); |
||
512 | |||
513 | $file_storage_cache_provider = $no_reflection_cache |
||
514 | ? null |
||
515 | : new Provider\FileStorageCacheProvider($config); |
||
516 | |||
517 | $classlike_storage_cache_provider = $no_reflection_cache |
||
518 | ? null |
||
519 | : new Provider\ClassLikeStorageCacheProvider($config); |
||
520 | |||
521 | $providers = new Provider\Providers( |
||
522 | new Provider\FileProvider, |
||
523 | new Provider\ParserCacheProvider($config, !$no_file_cache), |
||
524 | $file_storage_cache_provider, |
||
525 | $classlike_storage_cache_provider, |
||
526 | new Provider\FileReferenceCacheProvider($config), |
||
527 | new Provider\ProjectCacheProvider($current_dir . DIRECTORY_SEPARATOR . 'composer.lock') |
||
528 | ); |
||
529 | } |
||
530 | |||
531 | $stdout_report_options = new \Psalm\Report\ReportOptions(); |
||
532 | $stdout_report_options->use_color = !array_key_exists('m', $options); |
||
533 | $stdout_report_options->show_info = $show_info; |
||
534 | $stdout_report_options->show_suggestions = !array_key_exists('no-suggestions', $options); |
||
535 | /** |
||
536 | * @psalm-suppress PropertyTypeCoercion |
||
537 | */ |
||
538 | $stdout_report_options->format = $output_format; |
||
539 | $stdout_report_options->show_snippet = !isset($options['show-snippet']) || $options['show-snippet'] !== "false"; |
||
540 | $stdout_report_options->pretty = isset($options['pretty-print']) && $options['pretty-print'] !== "false"; |
||
541 | |||
542 | /** @var list<string>|string $report_file_paths type guaranteed by argument to getopt() */ |
||
0 ignored issues
–
show
The doc-type
list<string>|string could not be parsed: Expected "|" or "end of type", but got "<" at position 4. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
543 | $report_file_paths = $options['report'] ?? []; |
||
544 | if (is_string($report_file_paths)) { |
||
545 | $report_file_paths = [$report_file_paths]; |
||
546 | } |
||
547 | $project_analyzer = new ProjectAnalyzer( |
||
548 | $config, |
||
549 | $providers, |
||
550 | $stdout_report_options, |
||
551 | ProjectAnalyzer::getFileReportOptions( |
||
552 | $report_file_paths, |
||
553 | isset($options['report-show-info']) |
||
554 | ? $options['report-show-info'] !== 'false' && $options['report-show-info'] !== '0' |
||
555 | : true |
||
556 | ), |
||
557 | $threads, |
||
558 | $progress |
||
559 | ); |
||
560 | |||
561 | if (!isset($options['php-version'])) { |
||
562 | $options['php-version'] = $config->getPhpVersion(); |
||
563 | } |
||
564 | |||
565 | View Code Duplication | if (isset($options['php-version'])) { |
|
0 ignored issues
–
show
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. ![]() |
|||
566 | if (!is_string($options['php-version'])) { |
||
567 | die('Expecting a version number in the format x.y' . PHP_EOL); |
||
568 | } |
||
569 | |||
570 | $project_analyzer->setPhpVersion($options['php-version']); |
||
571 | } |
||
572 | |||
573 | if ($type_map_location) { |
||
574 | $project_analyzer->getCodebase()->store_node_types = true; |
||
575 | } |
||
576 | |||
577 | $start_time = microtime(true); |
||
578 | |||
579 | if (array_key_exists('debug-by-line', $options)) { |
||
580 | $project_analyzer->debug_lines = true; |
||
581 | } |
||
582 | |||
583 | if ($config->find_unused_code) { |
||
584 | $find_unused_code = 'auto'; |
||
585 | } |
||
586 | |||
587 | if ($find_references_to !== null) { |
||
588 | $project_analyzer->getCodebase()->collectLocations(); |
||
589 | $project_analyzer->show_issues = false; |
||
590 | } |
||
591 | |||
592 | if ($find_unused_code) { |
||
593 | $project_analyzer->getCodebase()->reportUnusedCode($find_unused_code); |
||
594 | } |
||
595 | |||
596 | if ($config->find_unused_variables || $find_unused_variables) { |
||
597 | $project_analyzer->getCodebase()->reportUnusedVariables(); |
||
598 | } |
||
599 | |||
600 | if ($config->run_taint_analysis || (isset($options['track-tainted-input']) |
||
601 | || isset($options['security-analysis']) |
||
602 | || isset($options['taint-analysis'])) |
||
603 | ) { |
||
604 | $project_analyzer->trackTaintedInputs(); |
||
605 | } |
||
606 | |||
607 | if (isset($options['find-unused-psalm-suppress'])) { |
||
608 | $project_analyzer->trackUnusedSuppressions(); |
||
609 | } |
||
610 | |||
611 | /** @var string $plugin_path */ |
||
612 | foreach ($plugins as $plugin_path) { |
||
613 | $config->addPluginPath($plugin_path); |
||
614 | } |
||
615 | |||
616 | if ($paths_to_check === null) { |
||
617 | $project_analyzer->check($current_dir, $is_diff); |
||
618 | } elseif ($paths_to_check) { |
||
619 | $project_analyzer->checkPaths($paths_to_check); |
||
620 | } |
||
621 | |||
622 | if ($find_references_to) { |
||
623 | $project_analyzer->findReferencesTo($find_references_to); |
||
624 | } |
||
625 | |||
626 | if (isset($options['set-baseline']) && is_string($options['set-baseline'])) { |
||
627 | if ($is_diff) { |
||
628 | fwrite(STDERR, 'Cannot set baseline in --diff mode' . PHP_EOL); |
||
629 | } else { |
||
630 | fwrite(STDERR, 'Writing error baseline to file...' . PHP_EOL); |
||
631 | |||
632 | ErrorBaseline::create( |
||
633 | new \Psalm\Internal\Provider\FileProvider, |
||
634 | $options['set-baseline'], |
||
635 | IssueBuffer::getIssuesData(), |
||
636 | $config->include_php_versions_in_error_baseline || isset($options['include-php-versions']) |
||
637 | ); |
||
638 | |||
639 | fwrite(STDERR, "Baseline saved to {$options['set-baseline']}."); |
||
640 | |||
641 | update_config_file( |
||
642 | $config, |
||
643 | $path_to_config ?? $current_dir, |
||
644 | $options['set-baseline'] |
||
645 | ); |
||
646 | |||
647 | fwrite(STDERR, PHP_EOL); |
||
648 | } |
||
649 | } |
||
650 | |||
651 | $issue_baseline = []; |
||
652 | |||
653 | if (isset($options['update-baseline'])) { |
||
654 | if ($is_diff) { |
||
655 | fwrite(STDERR, 'Cannot update baseline in --diff mode' . PHP_EOL); |
||
656 | } else { |
||
657 | $baselineFile = Config::getInstance()->error_baseline; |
||
658 | |||
659 | if (empty($baselineFile)) { |
||
660 | die('Cannot update baseline, because no baseline file is configured.' . PHP_EOL); |
||
661 | } |
||
662 | |||
663 | try { |
||
664 | $issue_current_baseline = ErrorBaseline::read( |
||
665 | new \Psalm\Internal\Provider\FileProvider, |
||
666 | $baselineFile |
||
667 | ); |
||
668 | $total_issues_current_baseline = ErrorBaseline::countTotalIssues($issue_current_baseline); |
||
669 | |||
670 | $issue_baseline = ErrorBaseline::update( |
||
671 | new \Psalm\Internal\Provider\FileProvider, |
||
672 | $baselineFile, |
||
673 | IssueBuffer::getIssuesData(), |
||
674 | $config->include_php_versions_in_error_baseline || isset($options['include-php-versions']) |
||
675 | ); |
||
676 | $total_issues_updated_baseline = ErrorBaseline::countTotalIssues($issue_baseline); |
||
677 | |||
678 | $total_fixed_issues = $total_issues_current_baseline - $total_issues_updated_baseline; |
||
679 | |||
680 | if ($total_fixed_issues > 0) { |
||
681 | echo str_repeat('-', 30) . "\n"; |
||
682 | echo $total_fixed_issues . ' errors fixed' . "\n"; |
||
683 | } |
||
684 | } catch (\Psalm\Exception\ConfigException $exception) { |
||
685 | fwrite(STDERR, 'Could not update baseline file: ' . $exception->getMessage() . PHP_EOL); |
||
686 | exit(1); |
||
687 | } |
||
688 | } |
||
689 | } |
||
690 | |||
691 | if (isset($options['use-baseline'])) { |
||
692 | View Code Duplication | if (!is_string($options['use-baseline'])) { |
|
0 ignored issues
–
show
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. ![]() |
|||
693 | fwrite(STDERR, '--use-baseline must be a string' . PHP_EOL); |
||
694 | exit(1); |
||
695 | } |
||
696 | |||
697 | $baseline_file_path = $options['use-baseline']; |
||
698 | } else { |
||
699 | $baseline_file_path = Config::getInstance()->error_baseline; |
||
700 | } |
||
701 | |||
702 | if ($baseline_file_path && !isset($options['ignore-baseline'])) { |
||
703 | try { |
||
704 | $issue_baseline = ErrorBaseline::read( |
||
705 | new \Psalm\Internal\Provider\FileProvider, |
||
706 | $baseline_file_path |
||
707 | ); |
||
708 | } catch (\Psalm\Exception\ConfigException $exception) { |
||
709 | fwrite(STDERR, 'Error while reading baseline: ' . $exception->getMessage() . PHP_EOL); |
||
710 | exit(1); |
||
711 | } |
||
712 | } |
||
713 | |||
714 | if ($type_map_location) { |
||
715 | $file_map = $providers->file_reference_provider->getFileMaps(); |
||
716 | |||
717 | $name_file_map = []; |
||
718 | |||
719 | $expected_references = []; |
||
720 | |||
721 | foreach ($file_map as $file_path => $map) { |
||
722 | $file_name = $config->shortenFileName($file_path); |
||
723 | foreach ($map[0] as $map_parts) { |
||
724 | $expected_references[$map_parts[1]] = true; |
||
725 | } |
||
726 | $map[2] = []; |
||
727 | $name_file_map[$file_name] = $map; |
||
728 | } |
||
729 | |||
730 | $reference_dictionary = \Psalm\Internal\Codebase\ReferenceMapGenerator::getReferenceMap( |
||
731 | $providers->classlike_storage_provider, |
||
732 | $expected_references |
||
733 | ); |
||
734 | |||
735 | $type_map_string = json_encode(['files' => $name_file_map, 'references' => $reference_dictionary]); |
||
736 | |||
737 | $providers->file_provider->setContents( |
||
738 | $type_map_location, |
||
739 | $type_map_string |
||
740 | ); |
||
741 | } |
||
742 | |||
743 | if ($stubs_location) { |
||
744 | $providers->file_provider->setContents( |
||
745 | $stubs_location, |
||
746 | \Psalm\Internal\Stubs\Generator\StubsGenerator::getAll( |
||
747 | $project_analyzer->getCodebase(), |
||
748 | $providers->classlike_storage_provider, |
||
749 | $providers->file_storage_provider |
||
750 | ) |
||
751 | ); |
||
752 | } |
||
753 | |||
754 | if (!isset($options['i'])) { |
||
755 | IssueBuffer::finish( |
||
756 | $project_analyzer, |
||
757 | !$paths_to_check, |
||
758 | $start_time, |
||
759 | isset($options['stats']), |
||
760 | $issue_baseline |
||
761 | ); |
||
762 | } else { |
||
763 | $issues_by_file = IssueBuffer::getIssuesData(); |
||
764 | |||
765 | if (!$issues_by_file) { |
||
766 | $init_level = 1; |
||
767 | } else { |
||
768 | $codebase = $project_analyzer->getCodebase(); |
||
769 | $mixed_counts = $codebase->analyzer->getTotalTypeCoverage($codebase); |
||
770 | |||
771 | $init_level = \Psalm\Config\Creator::getLevel( |
||
772 | array_merge(...array_values($issues_by_file)), |
||
773 | (int) array_sum($mixed_counts) |
||
774 | ); |
||
775 | } |
||
776 | |||
777 | echo "\n" . 'Detected level ' . $init_level . ' as a suitable initial default' . "\n"; |
||
778 | |||
779 | try { |
||
780 | $template_contents = Psalm\Config\Creator::getContents( |
||
781 | $current_dir, |
||
782 | $init_source_dir, |
||
783 | $init_level, |
||
784 | $vendor_dir |
||
785 | ); |
||
786 | } catch (Psalm\Exception\ConfigCreationException $e) { |
||
787 | die($e->getMessage() . PHP_EOL); |
||
788 | } |
||
789 | |||
790 | if (!file_put_contents($current_dir . 'psalm.xml', $template_contents)) { |
||
791 | die('Could not write to psalm.xml' . PHP_EOL); |
||
792 | } |
||
793 | |||
794 | exit('Config file created successfully. Please re-run psalm.' . PHP_EOL); |
||
795 | } |
||
796 |
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.