1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Use a better check for functional purity

This commit is contained in:
Matthew Brown 2019-09-08 11:49:14 -04:00
parent 3dbfedb51a
commit a032978a85
2 changed files with 19 additions and 11 deletions

View File

@ -619,8 +619,10 @@ class FunctionCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expressio
|| $codebase->find_unused_variables
|| !$config->remember_property_assignments_after_call)
) {
$must_use = false;
$callmap_function_pure = $function_id && $in_call_map
? $codebase->functions->isCallMapFunctionPure($codebase, $function_id, $stmt->args)
? $codebase->functions->isCallMapFunctionPure($codebase, $function_id, $stmt->args, $must_use)
: null;
if (($function_storage
@ -643,7 +645,8 @@ class FunctionCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expressio
$context->removeAllObjectVars();
}
} elseif ($function_id
&& (($function_storage && $function_storage->pure) || $callmap_function_pure === true)
&& (($function_storage && $function_storage->pure)
|| ($callmap_function_pure === true && $must_use))
&& $codebase->find_unused_variables
&& !$context->inside_conditional
&& !$context->inside_unset

View File

@ -264,8 +264,12 @@ class Functions
/**
* @param array<int, \PhpParser\Node\Arg> $args
*/
public function isCallMapFunctionPure(Codebase $codebase, string $function_id, array $args) : bool
{
public function isCallMapFunctionPure(
Codebase $codebase,
string $function_id,
array $args,
bool &$must_use
) : bool {
$impure_functions = [
// file io
'chdir', 'chgrp', 'chmod', 'chown', 'chroot', 'closedir', 'copy', 'file_put_contents',
@ -309,7 +313,7 @@ class Functions
'shell_exec', 'exec', 'system', 'passthru', 'pcntl_exec',
// well-known functions
'libxml_use_internal_errors', 'array_map', 'curl_exec',
'libxml_use_internal_errors', 'curl_exec',
'mt_srand', 'openssl_pkcs7_sign', 'mysqli_select_db', 'preg_replace_callback',
'mt_rand', 'rand',
@ -346,11 +350,6 @@ class Functions
return false;
}
// $matches is basically the (conditional) output of these functions
if ($function_id === 'preg_match' || $function_id === 'preg_match_all') {
return true;
}
$function_callable = \Psalm\Internal\Codebase\CallMap::getCallableFromCallMapById(
$codebase,
$function_id,
@ -361,10 +360,16 @@ class Functions
return false;
}
$must_use = true;
foreach ($function_callable->params as $i => $param) {
if ($param->by_ref && isset($args[$i])) {
if ($param->type && $param->type->hasCallableType() && isset($args[$i])) {
return false;
}
if ($param->by_ref && isset($args[$i])) {
$must_use = false;
}
}
return true;