mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Allow constants in array offsets to be reasoned about
This commit is contained in:
parent
ef992612d9
commit
c31d963918
@ -416,16 +416,20 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
||||
{
|
||||
switch (gettype($value)) {
|
||||
case 'boolean':
|
||||
return Type::getBool();
|
||||
if ($value) {
|
||||
return Type::getTrue();
|
||||
}
|
||||
|
||||
return Type::getFalse();
|
||||
|
||||
case 'integer':
|
||||
return Type::getInt();
|
||||
return Type::getInt(false, $value);
|
||||
|
||||
case 'double':
|
||||
return Type::getFloat();
|
||||
return Type::getFloat($value);
|
||||
|
||||
case 'string':
|
||||
return Type::getString();
|
||||
return Type::getString($value);
|
||||
|
||||
case 'array':
|
||||
return Type::getArray();
|
||||
|
@ -54,6 +54,8 @@ class ArrayAssignmentChecker
|
||||
* @param Context $context
|
||||
*
|
||||
* @return false|null
|
||||
*
|
||||
* @psalm-suppress UnusedVariable due to Psalm bug
|
||||
*/
|
||||
public static function updateArrayType(
|
||||
StatementsChecker $statements_checker,
|
||||
@ -131,13 +133,31 @@ class ArrayAssignmentChecker
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($child_stmt->dim instanceof PhpParser\Node\Scalar\String_
|
||||
|| ($child_stmt->dim instanceof PhpParser\Node\Expr\ConstFetch
|
||||
&& $child_stmt->dim->inferredType->isSingleStringLiteral())
|
||||
) {
|
||||
if ($child_stmt->dim instanceof PhpParser\Node\Scalar\String_) {
|
||||
if (preg_match('/^(0|[1-9][0-9]*)$/', $child_stmt->dim->value)) {
|
||||
$var_id_additions[] = '[' . $child_stmt->dim->value . ']';
|
||||
$value = $child_stmt->dim->value;
|
||||
} else {
|
||||
$value = $child_stmt->dim->inferredType->getSingleStringLiteral();
|
||||
}
|
||||
$var_id_additions[] = '[\'' . $child_stmt->dim->value . '\']';
|
||||
} elseif ($child_stmt->dim instanceof PhpParser\Node\Scalar\LNumber) {
|
||||
$var_id_additions[] = '[' . $child_stmt->dim->value . ']';
|
||||
|
||||
if (preg_match('/^(0|[1-9][0-9]*)$/', $value)) {
|
||||
$var_id_additions[] = '[' . $value . ']';
|
||||
}
|
||||
$var_id_additions[] = '[\'' . $value . '\']';
|
||||
} elseif ($child_stmt->dim instanceof PhpParser\Node\Scalar\LNumber
|
||||
|| ($child_stmt->dim instanceof PhpParser\Node\Expr\ConstFetch
|
||||
&& $child_stmt->dim->inferredType->isSingleIntLiteral())
|
||||
) {
|
||||
if ($child_stmt->dim instanceof PhpParser\Node\Scalar\LNumber) {
|
||||
$value = $child_stmt->dim->value;
|
||||
} else {
|
||||
$value = $child_stmt->dim->inferredType->getSingleIntLiteral();
|
||||
}
|
||||
|
||||
$var_id_additions[] = '[' . $value . ']';
|
||||
} elseif ($child_stmt->dim instanceof PhpParser\Node\Expr\Variable
|
||||
&& is_string($child_stmt->dim->name)
|
||||
) {
|
||||
@ -199,10 +219,24 @@ class ArrayAssignmentChecker
|
||||
throw new \InvalidArgumentException('Should never get here');
|
||||
}
|
||||
|
||||
$is_single_string_literal = false;
|
||||
|
||||
if ($current_dim instanceof PhpParser\Node\Scalar\String_
|
||||
|| $current_dim instanceof PhpParser\Node\Scalar\LNumber
|
||||
|| ($current_dim instanceof PhpParser\Node\Expr\ConstFetch
|
||||
&& isset($current_dim->inferredType)
|
||||
&& (($is_single_string_literal = $current_dim->inferredType->isSingleStringLiteral())
|
||||
|| $current_dim->inferredType->isSingleIntLiteral()))
|
||||
) {
|
||||
if ($current_dim instanceof PhpParser\Node\Scalar\String_
|
||||
|| $current_dim instanceof PhpParser\Node\Scalar\LNumber
|
||||
) {
|
||||
$key_value = $current_dim->value;
|
||||
} elseif ($is_single_string_literal) {
|
||||
$key_value = $current_dim->inferredType->getSingleStringLiteral();
|
||||
} else {
|
||||
$key_value = $current_dim->inferredType->getSingleIntLiteral();
|
||||
}
|
||||
|
||||
$has_matching_objectlike_property = false;
|
||||
|
||||
@ -261,13 +295,26 @@ class ArrayAssignmentChecker
|
||||
}
|
||||
|
||||
$root_is_string = $root_type->isString();
|
||||
$is_single_string_literal = false;
|
||||
|
||||
if (($current_dim instanceof PhpParser\Node\Scalar\String_
|
||||
|| $current_dim instanceof PhpParser\Node\Scalar\LNumber)
|
||||
|| $current_dim instanceof PhpParser\Node\Scalar\LNumber
|
||||
|| ($current_dim instanceof PhpParser\Node\Expr\ConstFetch
|
||||
&& isset($current_dim->inferredType)
|
||||
&& (($is_single_string_literal = $current_dim->inferredType->isSingleStringLiteral())
|
||||
|| $current_dim->inferredType->isSingleIntLiteral())))
|
||||
&& ($current_dim instanceof PhpParser\Node\Scalar\String_
|
||||
|| !$root_is_string)
|
||||
) {
|
||||
if ($current_dim instanceof PhpParser\Node\Scalar\String_
|
||||
|| $current_dim instanceof PhpParser\Node\Scalar\LNumber
|
||||
) {
|
||||
$key_value = $current_dim->value;
|
||||
} elseif ($is_single_string_literal) {
|
||||
$key_value = $current_dim->inferredType->getSingleStringLiteral();
|
||||
} else {
|
||||
$key_value = $current_dim->inferredType->getSingleIntLiteral();
|
||||
}
|
||||
|
||||
$has_matching_objectlike_property = false;
|
||||
|
||||
|
@ -728,6 +728,8 @@ class ExpressionChecker
|
||||
&& is_string($stmt->dim->name)
|
||||
) {
|
||||
$offset = '$' . $stmt->dim->name;
|
||||
} elseif ($stmt->dim instanceof PhpParser\Node\Expr\ConstFetch) {
|
||||
$offset = implode('\\', $stmt->dim->name->parts);
|
||||
}
|
||||
|
||||
return $root_var_id && $offset !== null ? $root_var_id . '[' . $offset . ']' : null;
|
||||
|
@ -1070,7 +1070,8 @@ class StatementsChecker extends SourceChecker implements StatementsSource
|
||||
$predefined_constants = Config::getInstance()->getPredefinedConstants();
|
||||
|
||||
if (isset($predefined_constants[$fq_const_name ?: $const_name])) {
|
||||
return ClassLikeChecker::getTypeFromValue($predefined_constants[$fq_const_name ?: $const_name]);
|
||||
$type = ClassLikeChecker::getTypeFromValue($predefined_constants[$fq_const_name ?: $const_name]);
|
||||
return $type;
|
||||
}
|
||||
|
||||
$stubbed_const_type = $project_checker->codebase->getStubbedConstantType(
|
||||
|
@ -925,6 +925,13 @@ class ArrayAssignmentTest extends TestCase
|
||||
$arr = [1 => 0, 1, 2, 3];
|
||||
$arr = [1 => "one", 2 => "two", "three")',
|
||||
],
|
||||
'constArrayAssignment' => [
|
||||
'<?php
|
||||
const BAR = 2;
|
||||
$arr = [1 => 2];
|
||||
$arr[BAR] = [6];
|
||||
$bar = $arr[BAR][0];',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user