mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Type explode more accurately
This commit is contained in:
parent
02a5d22449
commit
3cc549384f
@ -8650,7 +8650,7 @@ return [
|
||||
'preg_replace' => ['string|array', 'regex'=>'string|array', 'replace'=>'string|array', 'subject'=>'string|array', 'limit='=>'int', '&w_count='=>'int'],
|
||||
'preg_replace_callback' => ['string|array', 'regex'=>'string|array', 'callback'=>'callable(array):string', 'subject'=>'string|array', 'limit='=>'int', '&w_count='=>'int'],
|
||||
'preg_replace_callback_array' => ['string|array', 'pattern'=>'array<string,callable(array):string>', 'subject'=>'string|array', 'limit='=>'int', '&w_count='=>'int'],
|
||||
'preg_split' => ['array', 'pattern'=>'string', 'subject'=>'string', 'limit='=>'?int', 'flags='=>'int'],
|
||||
'preg_split' => ['array<int, string>|false', 'pattern'=>'string', 'subject'=>'string', 'limit='=>'?int', 'flags='=>'int'],
|
||||
'prev' => ['mixed', '&rw_array_arg'=>'array'],
|
||||
'print' => ['int', 'arg'=>'string'],
|
||||
'print_r' => ['string|true', 'var'=>'mixed', 'return='=>'bool'],
|
||||
|
@ -110,8 +110,19 @@ class FunctionChecker extends FunctionLikeChecker
|
||||
}
|
||||
}
|
||||
|
||||
if ($call_map_key === 'explode' || $call_map_key === 'preg_split') {
|
||||
return Type::parseString('array<int, string>');
|
||||
if ($call_map_key === 'explode'
|
||||
&& $call_args[0]->value instanceof PhpParser\Node\Scalar\String_
|
||||
) {
|
||||
if ($call_args[0]->value->value === '') {
|
||||
return Type::getFalse();
|
||||
}
|
||||
|
||||
return new Type\Union([
|
||||
new Type\Atomic\TArray([
|
||||
Type::getInt(),
|
||||
Type::getString()
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
if ($call_map_key === 'abs'
|
||||
|
@ -528,6 +528,10 @@ class ArrayFetchChecker
|
||||
|
||||
$codebase->analyzer->incrementNonMixedCount($statements_checker->getCheckedFilePath());
|
||||
|
||||
if ($type instanceof Type\Atomic\TFalse && $array_type->ignore_falsable_issues) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($type instanceof TNamedObject) {
|
||||
if (strtolower($type->value) !== 'simplexmlelement'
|
||||
&& $codebase->classExists($type->value)
|
||||
|
@ -244,8 +244,8 @@ class ReturnChecker
|
||||
if (IssueBuffer::accepts(
|
||||
new NullableReturnStatement(
|
||||
'The declared return type \'' . $local_return_type . '\' for '
|
||||
. $cased_method_id . ' is not nullable, but \'' . $inferred_type
|
||||
. '\' contains null',
|
||||
. $cased_method_id . ' is not nullable, but the function returns \''
|
||||
. $inferred_type . '\'',
|
||||
new CodeLocation($source, $stmt)
|
||||
),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
@ -262,8 +262,8 @@ class ReturnChecker
|
||||
if (IssueBuffer::accepts(
|
||||
new FalsableReturnStatement(
|
||||
'The declared return type \'' . $local_return_type . '\' for '
|
||||
. $cased_method_id . ' does not allow false, but \'' . $inferred_type
|
||||
. '\' contains false',
|
||||
. $cased_method_id . ' does not allow false, but the function returns \''
|
||||
. $inferred_type . '\'',
|
||||
new CodeLocation($source, $stmt)
|
||||
),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
|
@ -608,6 +608,13 @@ class FunctionCallTest extends TestCase
|
||||
'$c' => 'int',
|
||||
],
|
||||
],
|
||||
'explodeWithPossiblyFalse' => [
|
||||
'<?php
|
||||
/** @return array<int, string> */
|
||||
function exploder(string $s) : array {
|
||||
return explode(" ", $s);
|
||||
}',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@ -840,6 +847,13 @@ class FunctionCallTest extends TestCase
|
||||
$a = var_export(["a"]);',
|
||||
'error_message' => 'AssignmentToVoid',
|
||||
],
|
||||
'explodeWithEmptyString' => [
|
||||
'<?php
|
||||
function exploder(string $s) : array {
|
||||
return explode("", $s);
|
||||
}',
|
||||
'error_message' => 'FalsableReturnStatement',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user