1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 13:51:54 +01:00

Fix array_column with object and column name null

This commit is contained in:
HypeMC 2022-09-17 21:21:33 +02:00
parent 9ed9c4b64c
commit 602e26edd4
2 changed files with 95 additions and 6 deletions

View File

@ -36,7 +36,7 @@ class ArrayColumnReturnTypeProvider implements FunctionReturnTypeProviderInterfa
return Type::getMixed();
}
$row_shape = null;
$row_type = $row_shape = null;
$input_array_not_empty = false;
// calculate row shape
@ -45,7 +45,6 @@ class ArrayColumnReturnTypeProvider implements FunctionReturnTypeProviderInterfa
&& $first_arg_type->hasArray()
) {
$input_array = $first_arg_type->getAtomicTypes()['array'];
$row_type = null;
if ($input_array instanceof TKeyedArray) {
$row_type = $input_array->getGenericArrayType()->type_params[1];
} elseif ($input_array instanceof TArray) {
@ -104,7 +103,7 @@ class ArrayColumnReturnTypeProvider implements FunctionReturnTypeProviderInterfa
}
$result_key_type = Type::getArrayKey();
$result_element_type = null;
$result_element_type = null !== $row_type && $value_column_name_is_null ? $row_type : null;
$have_at_least_one_res = false;
// calculate results
if ($row_shape instanceof TKeyedArray) {
@ -116,9 +115,7 @@ class ArrayColumnReturnTypeProvider implements FunctionReturnTypeProviderInterfa
}
//array_column skips undefined elements so resulting type is necessarily defined
$result_element_type->possibly_undefined = false;
} elseif ($value_column_name_is_null) {
$result_element_type = new Union([$row_shape]);
} else {
} elseif (!$value_column_name_is_null) {
$result_element_type = Type::getMixed();
}

View File

@ -3,10 +3,12 @@
namespace Psalm\Tests\ReturnTypeProvider;
use Psalm\Tests\TestCase;
use Psalm\Tests\Traits\InvalidCodeAnalysisTestTrait;
use Psalm\Tests\Traits\ValidCodeAnalysisTestTrait;
class ArrayColumnTest extends TestCase
{
use InvalidCodeAnalysisTestTrait;
use ValidCodeAnalysisTestTrait;
public function providerValidCodeParse(): iterable
@ -61,5 +63,95 @@ class ArrayColumnTest extends TestCase
}
',
];
yield 'arrayColumnWithObjectsAndColumnNameNull' => [
'<?php
class C {
/** @var string */
public $name = "";
public function foo(): void {}
}
foreach (array_column([new C, new C], null, "name") as $instance) {
$instance->foo();
}
',
];
yield 'arrayColumnWithIntersectionAndColumnNameNull' => [
'<?php
interface I {
public function foo(): void;
}
abstract class A {
/** @var string */
public $name = "";
abstract public function bar(): void;
}
class C extends A implements I {
public function foo(): void {}
public function bar(): void {}
}
/** @var (A&I)[] $instances */
$instances = [];
foreach (array_column($instances, null, "name") as $instance) {
$instance->foo();
$instance->bar();
}
',
];
yield 'arrayColumnWithArrayAndColumnNameNull' => [
'<?php
class C {
/** @var string */
public $name = "";
public function foo(): void {}
}
foreach (array_column([["name" => "", "instance" => new C]], null, "name") as $array) {
$array["instance"]->foo();
}
',
];
yield 'arrayColumnWithListOfObject' => [
'<?php
function foo(object $object): void {}
/** @var list<object> $instances */
$instances = [];
foreach (array_column($instances, null, "name") as $instance) {
foo($instance);
}
',
];
yield 'arrayColumnWithListOfArrays' => [
'<?php
function foo(array $array): void {}
/** @var list<array> $arrays */
$arrays = [];
foreach (array_column($arrays, null, "name") as $array) {
foo($array);
}
',
];
}
public function providerInvalidCodeParse(): iterable
{
yield 'arrayColumnWithArrayAndColumnNameNull' => [
'<?php
/** @var list<array{name: string, instance: object}> $arrays */
$arrays = [];
foreach (array_column($arrays, null, "name") as $array) {
$array["instance"]->foo();
}
',
'error_message' => 'MixedMethodCall',
];
}
}