-
Notifications
You must be signed in to change notification settings - Fork 653
/
StrReplaceReturnTypeProvider.php
86 lines (74 loc) · 2.9 KB
/
StrReplaceReturnTypeProvider.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
<?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\TNull;
use Psalm\Type\Atomic\TString;
use Psalm\Type\Union;
use function call_user_func;
use function count;
use function in_array;
/**
* @internal
*/
class StrReplaceReturnTypeProvider implements FunctionReturnTypeProviderInterface
{
/**
* @return array<lowercase-string>
*/
public static function getFunctionIds(): array
{
return [
'str_replace',
'str_ireplace',
'substr_replace',
'preg_replace',
'preg_replace_callback',
];
}
public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): Union
{
$statements_source = $event->getStatementsSource();
$call_args = $event->getCallArgs();
$function_id = $event->getFunctionId();
if (!$statements_source instanceof StatementsAnalyzer
|| count($call_args) < 3
) {
return Type::getMixed();
}
if ($subject_type = $statements_source->node_data->getType($call_args[2]->value)) {
if (!$subject_type->hasString() && $subject_type->hasArray()) {
return Type::getArray();
}
$return_type = Type::getString();
if (in_array($function_id, ['str_replace', 'str_ireplace'], true)
&& $subject_type->isSingleStringLiteral()
) {
$first_arg = $statements_source->node_data->getType($call_args[0]->value);
$second_arg = $statements_source->node_data->getType($call_args[1]->value);
if ($first_arg && $second_arg && $first_arg->isSingleStringLiteral() && $second_arg->isSingleStringLiteral()) {
/**
* @var string $replaced_string
*/
$replaced_string = call_user_func(
$function_id,
$first_arg->getSingleStringLiteral()->value,
$second_arg->getSingleStringLiteral()->value,
$subject_type->getSingleStringLiteral()->value
);
$return_type = Type::getString($replaced_string);
}
} elseif (in_array($function_id, ['preg_replace', 'preg_replace_callback'], true)) {
$return_type = new Union([new TString, new TNull()]);
$codebase = $statements_source->getCodebase();
if ($codebase->config->ignore_internal_nullable_issues) {
$return_type->ignore_nullable_issues = true;
}
}
return $return_type;
}
return Type::getMixed();
}
}