Skip to content

Commit

Permalink
Add proper handling of unpacked arguments with string keys (#5446)
Browse files Browse the repository at this point in the history
* Add proper handling of unpacked arguments with string keys

* Fix undefined array key error

* Fix missed named arguments handling

* Fix false-positive on variadic parameter

* Add tests
  • Loading branch information
yakimun authored Mar 22, 2021
1 parent 4eca6ac commit fb94db9
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -639,9 +639,72 @@ public static function checkArgumentsMatch(
$matched_args = [];

foreach ($args as $argument_offset => $arg) {
if ($arg->unpack && $function_param_count > $argument_offset) {
for ($i = $argument_offset; $i < $function_param_count; $i++) {
$arg_function_params[$argument_offset][] = $function_params[$i];
if ($arg->unpack) {
if ($function_param_count > $argument_offset) {
for ($i = $argument_offset; $i < $function_param_count; $i++) {
$arg_function_params[$argument_offset][] = $function_params[$i];
}
}

if (($arg_value_type = $statements_analyzer->node_data->getType($arg->value))
&& $arg_value_type->hasArray()) {
/**
* @psalm-suppress PossiblyUndefinedStringArrayOffset
* @var TArray|TList|TKeyedArray
*/
$array_type = $arg_value_type->getAtomicTypes()['array'];

if ($array_type instanceof TKeyedArray) {
$key_types = $array_type->getGenericArrayType()->getChildNodes()[0]->getChildNodes();

foreach ($key_types as $key_type) {
if (!$key_type instanceof Type\Atomic\TLiteralString
|| ($function_storage && !$function_storage->allow_named_arg_calls)) {
continue;
}

$param_found = false;

foreach ($function_params as $candidate_param) {
if ($candidate_param->name === $key_type->value || $candidate_param->is_variadic) {
if ($candidate_param->name === $key_type->value) {
if (isset($matched_args[$candidate_param->name])) {
if (IssueBuffer::accepts(
new InvalidNamedArgument(
'Parameter $' . $key_type->value . ' has already been used in '
. ($cased_method_id ?: $method_id),
new CodeLocation($statements_analyzer, $arg),
(string)$method_id
),
$statements_analyzer->getSuppressedIssues()
)) {
// fall through
}
}

$matched_args[$candidate_param->name] = true;
}

$param_found = true;
break;
}
}

if (!$param_found) {
if (IssueBuffer::accepts(
new InvalidNamedArgument(
'Parameter $' . $key_type->value . ' does not exist on function '
. ($cased_method_id ?: $method_id),
new CodeLocation($statements_analyzer, $arg),
(string)$method_id
),
$statements_analyzer->getSuppressedIssues()
)) {
// fall through
}
}
}
}
}
} elseif ($arg->name && (!$function_storage || $function_storage->allow_named_arg_calls)) {
foreach ($function_params as $candidate_param) {
Expand Down
42 changes: 42 additions & 0 deletions tests/ArgTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,15 @@ function takesArguments(int ...$args) : void {}
[],
'8.0'
],
'useUnpackedNamedVariadicArguments' => [
'<?php
function takesArguments(int ...$args) : void {}
takesArguments(...["age" => 5]);',
[],
[],
'8.0'
],
'variadicArgsOptional' => [
'<?php
bar(...["aaaaa"]);
Expand Down Expand Up @@ -378,6 +387,27 @@ function foo(array $input) : CustomerData {
}',
'error_message' => 'InvalidNamedArgument'
],
'useUnpackedInvalidNamedArgument' => [
'<?php
class CustomerData {
public function __construct(
public string $name,
public string $email,
public int $age,
) {}
}
/**
* @param array{aage: int, name: string, email: string} $input
*/
function foo(array $input) : CustomerData {
return new CustomerData(...$input);
}',
'error_message' => 'InvalidNamedArgument',
[],
false,
'8.0'
],
'noNamedArgsMethod' => [
'<?php
class CustomerData
Expand Down Expand Up @@ -504,6 +534,18 @@ function test(int $param, int $param2): void {
false,
'8.0'
],
'overwriteOrderedWithUnpackedNamedParam' => [
'<?php
function test(int $param, int $param2): void {
echo $param + $param2;
}
test(1, ...["param" => 2]);',
'error_message' => 'InvalidNamedArgument',
[],
false,
'8.0'
],
];
}
}

0 comments on commit fb94db9

Please sign in to comment.