mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Fix handling of coerced callmap args
This commit is contained in:
parent
c29b3744ec
commit
9aa0aca949
@ -1508,7 +1508,7 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer
|
||||
) {
|
||||
$storage = $this->getFunctionLikeStorage($statements_analyzer);
|
||||
|
||||
foreach ($storage->params as $i => $param) {
|
||||
foreach ($storage->params as $param) {
|
||||
if ($param->by_ref && isset($context->vars_in_scope['$' . $param->name]) && !$param->is_variadic) {
|
||||
$actual_type = $context->vars_in_scope['$' . $param->name];
|
||||
$param_out_type = $param->out_type ?: $param->type;
|
||||
|
@ -513,7 +513,6 @@ class ArgumentsAnalyzer
|
||||
$cased_method_id,
|
||||
$last_param,
|
||||
$function_params,
|
||||
$function_storage,
|
||||
$argument_offset,
|
||||
$arg,
|
||||
$context,
|
||||
@ -692,7 +691,6 @@ class ArgumentsAnalyzer
|
||||
* @param string|null $cased_method_id
|
||||
* @param FunctionLikeParameter|null $last_param
|
||||
* @param array<int, FunctionLikeParameter> $function_params
|
||||
* @param FunctionLikeStorage|null $function_storage
|
||||
* @return false|null
|
||||
*/
|
||||
private static function handlePossiblyMatchingByRefParam(
|
||||
@ -702,7 +700,6 @@ class ArgumentsAnalyzer
|
||||
$cased_method_id,
|
||||
$last_param,
|
||||
$function_params,
|
||||
$function_storage,
|
||||
int $argument_offset,
|
||||
PhpParser\Node\Arg $arg,
|
||||
Context $context,
|
||||
|
@ -96,6 +96,7 @@ class InternalCallMapHandler
|
||||
}
|
||||
|
||||
$matching_param_count_callable = null;
|
||||
$matching_coerced_param_count_callable = null;
|
||||
|
||||
foreach ($callables as $possible_callable) {
|
||||
$possible_function_params = $possible_callable->params;
|
||||
@ -103,6 +104,7 @@ class InternalCallMapHandler
|
||||
assert($possible_function_params !== null);
|
||||
|
||||
$all_args_match = true;
|
||||
$type_coerced = false;
|
||||
|
||||
$last_param = count($possible_function_params)
|
||||
? $possible_function_params[count($possible_function_params) - 1]
|
||||
@ -179,6 +181,10 @@ class InternalCallMapHandler
|
||||
true,
|
||||
$arg_result
|
||||
) || $arg_result->type_coerced) {
|
||||
if ($arg_result->type_coerced) {
|
||||
$type_coerced = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -190,9 +196,17 @@ class InternalCallMapHandler
|
||||
$matching_param_count_callable = $possible_callable;
|
||||
}
|
||||
|
||||
if ($all_args_match) {
|
||||
if ($all_args_match && !$type_coerced) {
|
||||
return $possible_callable;
|
||||
}
|
||||
|
||||
if ($all_args_match) {
|
||||
$matching_coerced_param_count_callable = $possible_callable;
|
||||
}
|
||||
}
|
||||
|
||||
if ($matching_coerced_param_count_callable) {
|
||||
return $matching_coerced_param_count_callable;
|
||||
}
|
||||
|
||||
if ($matching_param_count_callable) {
|
||||
@ -274,6 +288,13 @@ class InternalCallMapHandler
|
||||
? Type::parseString($arg_type)
|
||||
: Type::getMixed();
|
||||
|
||||
$out_type = null;
|
||||
|
||||
if ($arg_name[0] === 'w' && $arg_name[1] === '_') {
|
||||
$out_type = $param_type;
|
||||
$param_type = Type::getMixed();
|
||||
}
|
||||
|
||||
$function_param = new FunctionLikeParameter(
|
||||
$arg_name,
|
||||
$by_reference,
|
||||
@ -285,6 +306,10 @@ class InternalCallMapHandler
|
||||
$variadic
|
||||
);
|
||||
|
||||
if ($out_type) {
|
||||
$function_param->out_type = $out_type;
|
||||
}
|
||||
|
||||
if (isset(self::$taint_sink_map[$call_map_key][$arg_offset])) {
|
||||
$function_param->sinks = self::$taint_sink_map[$call_map_key][$arg_offset];
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ class DateTimeZone
|
||||
public function __construct(string $tz) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-taint-specialize
|
||||
*/
|
||||
interface Throwable
|
||||
{
|
||||
/**
|
||||
@ -56,6 +59,9 @@ interface Throwable
|
||||
public function getTraceAsString() : string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-taint-specialize
|
||||
*/
|
||||
class Exception implements Throwable
|
||||
{
|
||||
/**
|
||||
@ -124,6 +130,9 @@ class Exception implements Throwable
|
||||
public final function getTraceAsString() : string {}
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-taint-specialize
|
||||
*/
|
||||
class Error implements Throwable
|
||||
{
|
||||
/**
|
||||
|
@ -1291,6 +1291,15 @@ class FunctionCallTest extends TestCase
|
||||
'$n' => 'int',
|
||||
]
|
||||
],
|
||||
'writeArgsAllowed' => [
|
||||
'<?php
|
||||
/** @return false|int */
|
||||
function safeMatch(string $pattern, string $subject, ?array $matches = null, int $flags = 0) {
|
||||
return \preg_match($pattern, $subject, $matches, $flags);
|
||||
}
|
||||
|
||||
safeMatch("/a/", "b");'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user