diff --git a/src/Psalm/CallMap.php b/src/Psalm/CallMap.php index c8681ad44..2f3810d40 100644 --- a/src/Psalm/CallMap.php +++ b/src/Psalm/CallMap.php @@ -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', 'subject'=>'string|array', 'limit='=>'int', '&w_count='=>'int'], -'preg_split' => ['array', 'pattern'=>'string', 'subject'=>'string', 'limit='=>'?int', 'flags='=>'int'], +'preg_split' => ['array|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'], diff --git a/src/Psalm/Checker/FunctionChecker.php b/src/Psalm/Checker/FunctionChecker.php index e5118ea7f..bf193322d 100644 --- a/src/Psalm/Checker/FunctionChecker.php +++ b/src/Psalm/Checker/FunctionChecker.php @@ -110,8 +110,19 @@ class FunctionChecker extends FunctionLikeChecker } } - if ($call_map_key === 'explode' || $call_map_key === 'preg_split') { - return Type::parseString('array'); + 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' diff --git a/src/Psalm/Checker/Statements/Expression/Fetch/ArrayFetchChecker.php b/src/Psalm/Checker/Statements/Expression/Fetch/ArrayFetchChecker.php index 85cba83c0..41195df47 100644 --- a/src/Psalm/Checker/Statements/Expression/Fetch/ArrayFetchChecker.php +++ b/src/Psalm/Checker/Statements/Expression/Fetch/ArrayFetchChecker.php @@ -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) diff --git a/src/Psalm/Checker/Statements/ReturnChecker.php b/src/Psalm/Checker/Statements/ReturnChecker.php index bf5233653..e98da7e18 100644 --- a/src/Psalm/Checker/Statements/ReturnChecker.php +++ b/src/Psalm/Checker/Statements/ReturnChecker.php @@ -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() diff --git a/tests/FunctionCallTest.php b/tests/FunctionCallTest.php index 75a44a3a0..204de5a30 100644 --- a/tests/FunctionCallTest.php +++ b/tests/FunctionCallTest.php @@ -608,6 +608,13 @@ class FunctionCallTest extends TestCase '$c' => 'int', ], ], + 'explodeWithPossiblyFalse' => [ + ' */ + function exploder(string $s) : array { + return explode(" ", $s); + }', + ], ]; } @@ -840,6 +847,13 @@ class FunctionCallTest extends TestCase $a = var_export(["a"]);', 'error_message' => 'AssignmentToVoid', ], + 'explodeWithEmptyString' => [ + ' 'FalsableReturnStatement', + ], ]; } }