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:
parent
61f5a06a7b
commit
7af771a006
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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"];'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user