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)) {
|
switch (gettype($value)) {
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
return Type::getBool();
|
if ($value) {
|
||||||
|
return Type::getTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Type::getFalse();
|
||||||
|
|
||||||
case 'integer':
|
case 'integer':
|
||||||
return Type::getInt();
|
return Type::getInt(false, $value);
|
||||||
|
|
||||||
case 'double':
|
case 'double':
|
||||||
return Type::getFloat();
|
return Type::getFloat($value);
|
||||||
|
|
||||||
case 'string':
|
case 'string':
|
||||||
return Type::getString();
|
return Type::getString($value);
|
||||||
|
|
||||||
case 'array':
|
case 'array':
|
||||||
return Type::getArray();
|
return Type::getArray();
|
||||||
|
@ -54,6 +54,8 @@ class ArrayAssignmentChecker
|
|||||||
* @param Context $context
|
* @param Context $context
|
||||||
*
|
*
|
||||||
* @return false|null
|
* @return false|null
|
||||||
|
*
|
||||||
|
* @psalm-suppress UnusedVariable due to Psalm bug
|
||||||
*/
|
*/
|
||||||
public static function updateArrayType(
|
public static function updateArrayType(
|
||||||
StatementsChecker $statements_checker,
|
StatementsChecker $statements_checker,
|
||||||
@ -131,13 +133,31 @@ class ArrayAssignmentChecker
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($child_stmt->dim instanceof PhpParser\Node\Scalar\String_) {
|
if ($child_stmt->dim instanceof PhpParser\Node\Scalar\String_
|
||||||
if (preg_match('/^(0|[1-9][0-9]*)$/', $child_stmt->dim->value)) {
|
|| ($child_stmt->dim instanceof PhpParser\Node\Expr\ConstFetch
|
||||||
$var_id_additions[] = '[' . $child_stmt->dim->value . ']';
|
&& $child_stmt->dim->inferredType->isSingleStringLiteral())
|
||||||
|
) {
|
||||||
|
if ($child_stmt->dim instanceof PhpParser\Node\Scalar\String_) {
|
||||||
|
$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) {
|
if (preg_match('/^(0|[1-9][0-9]*)$/', $value)) {
|
||||||
$var_id_additions[] = '[' . $child_stmt->dim->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
|
} elseif ($child_stmt->dim instanceof PhpParser\Node\Expr\Variable
|
||||||
&& is_string($child_stmt->dim->name)
|
&& is_string($child_stmt->dim->name)
|
||||||
) {
|
) {
|
||||||
@ -199,10 +219,24 @@ class ArrayAssignmentChecker
|
|||||||
throw new \InvalidArgumentException('Should never get here');
|
throw new \InvalidArgumentException('Should never get here');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$is_single_string_literal = false;
|
||||||
|
|
||||||
if ($current_dim instanceof PhpParser\Node\Scalar\String_
|
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()))
|
||||||
) {
|
) {
|
||||||
$key_value = $current_dim->value;
|
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;
|
$has_matching_objectlike_property = false;
|
||||||
|
|
||||||
@ -261,13 +295,26 @@ class ArrayAssignmentChecker
|
|||||||
}
|
}
|
||||||
|
|
||||||
$root_is_string = $root_type->isString();
|
$root_is_string = $root_type->isString();
|
||||||
|
$is_single_string_literal = false;
|
||||||
|
|
||||||
if (($current_dim instanceof PhpParser\Node\Scalar\String_
|
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_
|
&& ($current_dim instanceof PhpParser\Node\Scalar\String_
|
||||||
|| !$root_is_string)
|
|| !$root_is_string)
|
||||||
) {
|
) {
|
||||||
$key_value = $current_dim->value;
|
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;
|
$has_matching_objectlike_property = false;
|
||||||
|
|
||||||
|
@ -728,6 +728,8 @@ class ExpressionChecker
|
|||||||
&& is_string($stmt->dim->name)
|
&& is_string($stmt->dim->name)
|
||||||
) {
|
) {
|
||||||
$offset = '$' . $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;
|
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();
|
$predefined_constants = Config::getInstance()->getPredefinedConstants();
|
||||||
|
|
||||||
if (isset($predefined_constants[$fq_const_name ?: $const_name])) {
|
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(
|
$stubbed_const_type = $project_checker->codebase->getStubbedConstantType(
|
||||||
|
@ -925,6 +925,13 @@ class ArrayAssignmentTest extends TestCase
|
|||||||
$arr = [1 => 0, 1, 2, 3];
|
$arr = [1 => 0, 1, 2, 3];
|
||||||
$arr = [1 => "one", 2 => "two", "three")',
|
$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