Skip to content
Permalink
Browse files

Use a better check for functional purity

  • Loading branch information...
muglug committed Sep 8, 2019
1 parent 3dbfedb commit a032978a854504de6b3faab5fe98a36eb6435236
@@ -619,8 +619,10 @@ public static function analyze(
|| $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 @@ public static function analyze(
$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
@@ -264,8 +264,12 @@ public static function isVariadic(Codebase $codebase, $function_id, $file_path)
/**
* @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 @@ public function isCallMapFunctionPure(Codebase $codebase, string $function_id, a
'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 @@ public function isCallMapFunctionPure(Codebase $codebase, string $function_id, a
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 @@ public function isCallMapFunctionPure(Codebase $codebase, string $function_id, a
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;

0 comments on commit a032978

Please sign in to comment.
You can’t perform that action at this time.