mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Fix issues found by improved Psalm checks
cc @TysonAndre, found with RedundantCondition checks
This commit is contained in:
parent
fd3de443b2
commit
4312ef380b
@ -7606,7 +7606,7 @@ return [
|
||||
'ReflectionClass::getModifiers' => ['int'],
|
||||
'ReflectionClass::getNamespaceName' => ['string'],
|
||||
'ReflectionClass::getName' => ['string'],
|
||||
'ReflectionClass::getParentClass' => ['ReflectionClass'],
|
||||
'ReflectionClass::getParentClass' => ['?ReflectionClass'],
|
||||
'ReflectionClass::getProperties' => ['array', 'filter='=>'int'],
|
||||
'ReflectionClass::getProperty' => ['ReflectionProperty', 'name'=>'string'],
|
||||
'ReflectionClass::getShortName' => ['string'],
|
||||
|
@ -1562,12 +1562,12 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
||||
|
||||
$class_storage = $project_checker->classlike_storage_provider->get($declaring_property_class);
|
||||
|
||||
$storage = $class_storage->properties[$property_name];
|
||||
|
||||
if (!$storage) {
|
||||
if (!isset($class_storage->properties[$property_name])) {
|
||||
throw new \UnexpectedValueException('$storage should not be null for ' . $property_id);
|
||||
}
|
||||
|
||||
$storage = $class_storage->properties[$property_name];
|
||||
|
||||
switch ($storage->visibility) {
|
||||
case self::VISIBILITY_PUBLIC:
|
||||
return null;
|
||||
|
@ -934,7 +934,7 @@ abstract class FunctionLikeChecker extends SourceChecker implements StatementsSo
|
||||
}
|
||||
|
||||
if (!$return_type) {
|
||||
if ($inferred_return_type && !$inferred_return_type->isMixed()) {
|
||||
if (!$inferred_return_type->isMixed()) {
|
||||
$this->addDocblockReturnType($project_checker, $inferred_return_type);
|
||||
}
|
||||
|
||||
@ -983,7 +983,7 @@ abstract class FunctionLikeChecker extends SourceChecker implements StatementsSo
|
||||
);
|
||||
}
|
||||
|
||||
if ($inferred_return_type && !$declared_return_type->isMixed()) {
|
||||
if (!$declared_return_type->isMixed()) {
|
||||
if ($inferred_return_type->isVoid() && $declared_return_type->isVoid()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -39,9 +39,7 @@ class MethodChecker extends FunctionLikeChecker
|
||||
if ($method_id = self::getDeclaringMethodId($project_checker, $method_id)) {
|
||||
$storage = self::getStorage($project_checker, $method_id);
|
||||
|
||||
if ($storage) {
|
||||
return $storage->params;
|
||||
}
|
||||
return $storage->params;
|
||||
}
|
||||
|
||||
throw new \UnexpectedValueException('Cannot get method params for ' . $method_id);
|
||||
@ -84,10 +82,6 @@ class MethodChecker extends FunctionLikeChecker
|
||||
|
||||
$storage = self::getStorage($project_checker, $method_id);
|
||||
|
||||
if (!$storage) {
|
||||
throw new \UnexpectedValueException('$storage should not be null for ' . $method_id);
|
||||
}
|
||||
|
||||
if ($storage->return_type) {
|
||||
return $storage->return_type;
|
||||
}
|
||||
@ -97,7 +91,7 @@ class MethodChecker extends FunctionLikeChecker
|
||||
foreach ($class_storage->overridden_method_ids[$method_name] as $overridden_method_id) {
|
||||
$overridden_storage = self::getStorage($project_checker, $overridden_method_id);
|
||||
|
||||
if ($overridden_storage && $overridden_storage->return_type) {
|
||||
if ($overridden_storage->return_type) {
|
||||
if ($overridden_storage->return_type->isNull()) {
|
||||
return Type::getVoid();
|
||||
}
|
||||
@ -128,17 +122,13 @@ class MethodChecker extends FunctionLikeChecker
|
||||
|
||||
$storage = self::getStorage($project_checker, $method_id);
|
||||
|
||||
if (!$storage) {
|
||||
throw new \UnexpectedValueException('$storage should not be null for ' . $method_id);
|
||||
}
|
||||
|
||||
if (!$storage->return_type_location) {
|
||||
$overridden_method_ids = self::getOverriddenMethodIds($project_checker, $method_id);
|
||||
|
||||
foreach ($overridden_method_ids as $overridden_method_id) {
|
||||
$overridden_storage = self::getStorage($project_checker, $overridden_method_id);
|
||||
|
||||
if ($overridden_storage && $overridden_storage->return_type_location) {
|
||||
if ($overridden_storage->return_type_location) {
|
||||
$defined_location = $overridden_storage->return_type_location;
|
||||
break;
|
||||
}
|
||||
@ -262,10 +252,6 @@ class MethodChecker extends FunctionLikeChecker
|
||||
|
||||
$storage = self::getStorage($project_checker, $method_id);
|
||||
|
||||
if (!$storage) {
|
||||
throw new \UnexpectedValueException('$storage should not be null');
|
||||
}
|
||||
|
||||
if (!$storage->is_static) {
|
||||
if ($self_call) {
|
||||
if (IssueBuffer::accepts(
|
||||
@ -496,10 +482,6 @@ class MethodChecker extends FunctionLikeChecker
|
||||
|
||||
$storage = self::getStorage($project_checker, $declaring_method_id);
|
||||
|
||||
if (!$storage) {
|
||||
throw new \UnexpectedValueException('$storage should not be null for ' . $declaring_method_id);
|
||||
}
|
||||
|
||||
switch ($storage->visibility) {
|
||||
case ClassLikeChecker::VISIBILITY_PUBLIC:
|
||||
return true;
|
||||
@ -583,10 +565,6 @@ class MethodChecker extends FunctionLikeChecker
|
||||
|
||||
$storage = self::getStorage($project_checker, $declaring_method_id);
|
||||
|
||||
if (!$storage) {
|
||||
throw new \UnexpectedValueException('$storage should not be null for ' . $declaring_method_id);
|
||||
}
|
||||
|
||||
switch ($storage->visibility) {
|
||||
case ClassLikeChecker::VISIBILITY_PUBLIC:
|
||||
return null;
|
||||
@ -772,10 +750,6 @@ class MethodChecker extends FunctionLikeChecker
|
||||
|
||||
$storage = self::getStorage($project_checker, $method_id);
|
||||
|
||||
if (!$storage) {
|
||||
throw new \UnexpectedValueException('$storage should not be null for ' . $method_id);
|
||||
}
|
||||
|
||||
list($fq_class_name) = explode('::', $method_id);
|
||||
|
||||
return $fq_class_name . '::' . $storage->cased_name;
|
||||
|
@ -441,7 +441,6 @@ class ProjectChecker
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @psalm-suppress ParadoxicalCondition
|
||||
*/
|
||||
public function scanFiles()
|
||||
{
|
||||
|
@ -1146,6 +1146,7 @@ class AssignmentChecker
|
||||
// First go from the root element up, and go as far as we can to figure out what
|
||||
// array types there are
|
||||
while ($child_stmts) {
|
||||
/** @var PhpParser\Node\Expr\ArrayDimFetch */
|
||||
$child_stmt = array_shift($child_stmts);
|
||||
|
||||
if (count($child_stmts)) {
|
||||
|
@ -171,15 +171,13 @@ class CallChecker
|
||||
if ($var_type_part instanceof Type\Atomic\Fn) {
|
||||
$function_params = $var_type_part->params;
|
||||
|
||||
if ($var_type_part->return_type) {
|
||||
if (isset($stmt->inferredType)) {
|
||||
$stmt->inferredType = Type::combineUnionTypes(
|
||||
$stmt->inferredType,
|
||||
$var_type_part->return_type
|
||||
);
|
||||
} else {
|
||||
$stmt->inferredType = $var_type_part->return_type;
|
||||
}
|
||||
if (isset($stmt->inferredType)) {
|
||||
$stmt->inferredType = Type::combineUnionTypes(
|
||||
$stmt->inferredType,
|
||||
$var_type_part->return_type
|
||||
);
|
||||
} else {
|
||||
$stmt->inferredType = $var_type_part->return_type;
|
||||
}
|
||||
|
||||
$function_exists = true;
|
||||
@ -2179,7 +2177,7 @@ class CallChecker
|
||||
$array_arg_types[] = $array_arg_type;
|
||||
}
|
||||
|
||||
/** @var PhpParser\Node\Arg */
|
||||
/** @var ?PhpParser\Node\Arg */
|
||||
$closure_arg = isset($args[$closure_index]) ? $args[$closure_index] : null;
|
||||
|
||||
/** @var Type\Union|null */
|
||||
@ -2191,7 +2189,7 @@ class CallChecker
|
||||
|
||||
$project_checker = $file_checker->project_checker;
|
||||
|
||||
if ($closure_arg_type) {
|
||||
if ($closure_arg && $closure_arg_type) {
|
||||
$min_closure_param_count = $max_closure_param_count = count($array_arg_types);
|
||||
|
||||
if ($method_id === 'array_filter') {
|
||||
|
@ -850,7 +850,8 @@ class FetchChecker
|
||||
if (!TypeChecker::isContainedBy(
|
||||
$project_checker,
|
||||
$offset_type,
|
||||
$type->type_params[0]
|
||||
$type->type_params[0],
|
||||
$offset_type->ignore_nullable_issues
|
||||
)) {
|
||||
$invalid_offset_types[] = (string)$type->type_params[0];
|
||||
} else {
|
||||
@ -939,7 +940,7 @@ class FetchChecker
|
||||
$type->properties[$int_key_value]
|
||||
);
|
||||
}
|
||||
} elseif ($string_key_value && $in_assignment && $string_key_value) {
|
||||
} elseif ($string_key_value && $in_assignment) {
|
||||
$type->properties[$string_key_value] = new Type\Union([new TEmpty]);
|
||||
|
||||
if (!$array_access_type) {
|
||||
@ -968,7 +969,8 @@ class FetchChecker
|
||||
} elseif (TypeChecker::isContainedBy(
|
||||
$project_checker,
|
||||
$offset_type,
|
||||
Type::getString()
|
||||
Type::getString(),
|
||||
$offset_type->ignore_nullable_issues
|
||||
)) {
|
||||
if ($replacement_type) {
|
||||
$generic_params = Type::combineUnionTypes(
|
||||
|
@ -2085,23 +2085,21 @@ class ExpressionChecker
|
||||
if (isset($stmt->if->inferredType)) {
|
||||
$lhs_type = $stmt->if->inferredType;
|
||||
}
|
||||
} elseif ($stmt->cond) {
|
||||
if (isset($stmt->cond->inferredType)) {
|
||||
$if_return_type_reconciled = TypeChecker::reconcileTypes(
|
||||
'!falsy',
|
||||
$stmt->cond->inferredType,
|
||||
'',
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
} elseif (isset($stmt->cond->inferredType)) {
|
||||
$if_return_type_reconciled = TypeChecker::reconcileTypes(
|
||||
'!falsy',
|
||||
$stmt->cond->inferredType,
|
||||
'',
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
|
||||
if ($if_return_type_reconciled === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$lhs_type = $if_return_type_reconciled;
|
||||
if ($if_return_type_reconciled === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$lhs_type = $if_return_type_reconciled;
|
||||
}
|
||||
|
||||
if (!$lhs_type || !isset($stmt->else->inferredType)) {
|
||||
|
@ -409,6 +409,12 @@ return [
|
||||
'phpparser\\node\\expr\\new_' => [
|
||||
'args' => 'array<int, PhpParser\Node\Arg>',
|
||||
],
|
||||
'phpparser\node\expr\array_' => [
|
||||
'items' => 'array<int, phpparser\node\expr\arrayitem>',
|
||||
],
|
||||
'phpparser\node\expr\list_' => [
|
||||
'items' => 'array<int, phpparser\node\expr\arrayitem|null>',
|
||||
],
|
||||
'phpparser\\node\\expr\\methodcall' => [
|
||||
'args' => 'array<int, PhpParser\Node\Arg>',
|
||||
],
|
||||
|
@ -88,7 +88,8 @@ function array_diff_key(array $arr, array $arr2, array $arr3 = null, array $arr4
|
||||
* @template TValue
|
||||
*
|
||||
* @param array<TKey, TValue> $arr
|
||||
* @return TValue
|
||||
* @return ?TValue
|
||||
* @psalm-ignore-nullable-return
|
||||
*/
|
||||
function array_shift(array &$arr) {}
|
||||
|
||||
@ -97,7 +98,8 @@ function array_shift(array &$arr) {}
|
||||
* @template TValue
|
||||
*
|
||||
* @param array<TKey, TValue> $arr
|
||||
* @return TValue
|
||||
* @return ?TValue
|
||||
* @psalm-ignore-nullable-return
|
||||
*/
|
||||
function array_pop(array &$arr) {}
|
||||
|
||||
|
@ -518,8 +518,8 @@ class ReturnTypeTest extends TestCase
|
||||
],
|
||||
'mixedInferredReturnType' => [
|
||||
'<?php
|
||||
function fooFoo() : string {
|
||||
return array_pop([]);
|
||||
function fooFoo(array $arr) : string {
|
||||
return array_pop($arr);
|
||||
}',
|
||||
'error_message' => 'MixedInferredReturnType',
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user