1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Fix #3132 - resolve array access in constant properly

This commit is contained in:
Brown 2020-04-18 12:39:00 -04:00
parent 61f5a06a7b
commit 7af771a006
4 changed files with 85 additions and 4 deletions

View File

@ -1540,10 +1540,6 @@ class ClassLikes
throw new \InvalidArgumentException('Must specify $visibility');
}
if (isset($type_candidates[$constant_name])) {
return $type_candidates[$constant_name];
}
if (isset($fallbacks[$constant_name])) {
return new Type\Union([
$this->resolveConstantType(
@ -1554,6 +1550,10 @@ class ClassLikes
]);
}
if (isset($type_candidates[$constant_name])) {
return $type_candidates[$constant_name];
}
return null;
}
@ -1750,6 +1750,31 @@ class ClassLikes
}
}
if ($c instanceof UnresolvedConstant\ArrayOffsetFetch) {
$var_type = $this->resolveConstantType(
$c->array,
$statements_analyzer,
$visited_constant_ids + [$c_id => true]
);
$offset_type = $this->resolveConstantType(
$c->offset,
$statements_analyzer,
$visited_constant_ids + [$c_id => true]
);
if ($var_type instanceof Type\Atomic\ObjectLike
&& ($offset_type instanceof Type\Atomic\TLiteralInt
|| $offset_type instanceof Type\Atomic\TLiteralString)
) {
$union = $var_type->properties[$offset_type->value] ?? null;
if ($union && $union->isSingle()) {
return \array_values($union->getAtomicTypes())[0];
}
}
}
if ($c instanceof UnresolvedConstant\Constant) {
if ($statements_analyzer) {
$found_type = $statements_analyzer->getConstType(

View File

@ -3492,6 +3492,24 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
return new UnresolvedConstant\ScalarValue($aliases->namespace);
}
if ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch && $stmt->dim) {
$left = self::getUnresolvedClassConstExpr(
$stmt->var,
$aliases,
$fq_classlike_name
);
$right = self::getUnresolvedClassConstExpr(
$stmt->dim,
$aliases,
$fq_classlike_name
);
if ($left && $right) {
return new UnresolvedConstant\ArrayOffsetFetch($left, $right);
}
}
if ($stmt instanceof PhpParser\Node\Expr\ClassConstFetch) {
if ($stmt->class instanceof PhpParser\Node\Name
&& $stmt->name instanceof PhpParser\Node\Identifier

View File

@ -0,0 +1,20 @@
<?php
namespace Psalm\Internal\Scanner\UnresolvedConstant;
use Psalm\Internal\Scanner\UnresolvedConstantComponent;
class ArrayOffsetFetch extends UnresolvedConstantComponent
{
/** @var UnresolvedConstantComponent */
public $array;
/** @var UnresolvedConstantComponent */
public $offset;
public function __construct(UnresolvedConstantComponent $left, UnresolvedConstantComponent $right)
{
$this->array = $left;
$this->offset = $right;
}
}

View File

@ -782,6 +782,24 @@ class ConstantTest extends TestCase
A::test();'
],
'referenceClassConstantWithSelf' => [
'<?php
abstract class A {
public const KEYS = [];
public const VALUES = [];
}
class B extends A {
public const VALUES = [\'there\' => self::KEYS[\'hi\']];
public const KEYS = [\'hi\' => CONSTANTS::THERE];
}
class CONSTANTS {
public const THERE = \'there\';
}
echo B::VALUES["there"];'
],
];
}