-
Notifications
You must be signed in to change notification settings - Fork 651
/
ArrayPopReturnTypeProvider.php
96 lines (79 loc) · 3.13 KB
/
ArrayPopReturnTypeProvider.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<?php
namespace Psalm\Internal\Provider\ReturnTypeProvider;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Plugin\EventHandler\Event\FunctionReturnTypeProviderEvent;
use Psalm\Plugin\EventHandler\FunctionReturnTypeProviderInterface;
use Psalm\Type;
use Psalm\Type\Atomic\TArray;
use Psalm\Type\Atomic\TKeyedArray;
use Psalm\Type\Atomic\TList;
use Psalm\Type\Atomic\TNonEmptyArray;
use Psalm\Type\Atomic\TNonEmptyList;
use Psalm\Type\Atomic\TNull;
use Psalm\Type\Union;
class ArrayPopReturnTypeProvider implements FunctionReturnTypeProviderInterface
{
/**
* @return array<lowercase-string>
*/
public static function getFunctionIds(): array
{
return ['array_pop', 'array_shift'];
}
public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): Union
{
$statements_source = $event->getStatementsSource();
$call_args = $event->getCallArgs();
$function_id = $event->getFunctionId();
if (!$statements_source instanceof StatementsAnalyzer) {
return Type::getMixed();
}
$first_arg = $call_args[0]->value ?? null;
$first_arg_array = $first_arg
&& ($first_arg_type = $statements_source->node_data->getType($first_arg))
&& $first_arg_type->hasType('array')
&& !$first_arg_type->hasMixed()
&& ($array_atomic_type = $first_arg_type->getAtomicTypes()['array'])
&& ($array_atomic_type instanceof TArray
|| $array_atomic_type instanceof TKeyedArray
|| $array_atomic_type instanceof TList)
? $array_atomic_type
: null;
if (!$first_arg_array) {
return Type::getMixed();
}
$nullable = false;
if ($first_arg_array instanceof TArray) {
$value_type = clone $first_arg_array->type_params[1];
if ($first_arg_array->isEmptyArray()) {
return Type::getNull();
}
if (!$first_arg_array instanceof TNonEmptyArray) {
$nullable = true;
}
} elseif ($first_arg_array instanceof TList) {
$value_type = clone $first_arg_array->type_param;
if (!$first_arg_array instanceof TNonEmptyList) {
$nullable = true;
}
} else {
// special case where we know the type of the first element
if ($function_id === 'array_shift' && $first_arg_array->is_list && isset($first_arg_array->properties[0])) {
$value_type = clone $first_arg_array->properties[0];
} else {
$value_type = $first_arg_array->getGenericValueType();
if (!$first_arg_array->sealed && !$first_arg_array->previous_value_type) {
$nullable = true;
}
}
}
if ($nullable) {
$value_type->addType(new TNull);
$codebase = $statements_source->getCodebase();
if ($codebase->config->ignore_internal_nullable_issues) {
$value_type->ignore_nullable_issues = true;
}
}
return $value_type;
}
}