mirror of
https://github.com/danog/psalm.git
synced 2024-11-27 04:45:20 +01:00
Transform bad offsets (#5817)
* Transform bad offset access * fix build
This commit is contained in:
parent
d1262b0bec
commit
350df114f3
@ -186,6 +186,8 @@ class ArrayAnalyzer
|
||||
} elseif ($atomic_key_type instanceof Type\Atomic\TBool) {
|
||||
$good_types[] = new Type\Atomic\TLiteralInt(0);
|
||||
$good_types[] = new Type\Atomic\TLiteralInt(1);
|
||||
} elseif ($atomic_key_type instanceof Type\Atomic\TLiteralFloat) {
|
||||
$good_types[] = new Type\Atomic\TLiteralInt((int) $atomic_key_type->value);
|
||||
} elseif ($atomic_key_type instanceof Type\Atomic\TFloat) {
|
||||
$good_types[] = new Type\Atomic\TInt;
|
||||
} else {
|
||||
|
@ -11,6 +11,7 @@ use Psalm\Internal\DataFlow\DataFlowNode;
|
||||
use Psalm\Internal\Type\TemplateInferredTypeReplacer;
|
||||
use Psalm\CodeLocation;
|
||||
use Psalm\Context;
|
||||
use Psalm\Internal\Type\TypeCombiner;
|
||||
use Psalm\Issue\EmptyArrayAccess;
|
||||
use Psalm\Issue\InvalidArrayAccess;
|
||||
use Psalm\Issue\InvalidArrayAssignment;
|
||||
@ -426,6 +427,10 @@ class ArrayFetchAnalyzer
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-suppress ComplexMethod to be refactored.
|
||||
* Good type/bad type behaviour could be mutualised with ArrayAnalyzer
|
||||
*/
|
||||
public static function getArrayAccessTypeGivenOffset(
|
||||
StatementsAnalyzer $statements_analyzer,
|
||||
PhpParser\Node\Expr\ArrayDimFetch $stmt,
|
||||
@ -806,6 +811,45 @@ class ArrayFetchAnalyzer
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$good_types = [];
|
||||
$bad_types = [];
|
||||
foreach ($offset_type->getAtomicTypes() as $atomic_key_type) {
|
||||
if (!$atomic_key_type instanceof Type\Atomic\TString
|
||||
&& !$atomic_key_type instanceof Type\Atomic\TInt
|
||||
&& !$atomic_key_type instanceof Type\Atomic\TArrayKey
|
||||
&& !$atomic_key_type instanceof Type\Atomic\TMixed
|
||||
&& !$atomic_key_type instanceof Type\Atomic\TTemplateParam
|
||||
&& !(
|
||||
$atomic_key_type instanceof Type\Atomic\TObjectWithProperties
|
||||
&& isset($atomic_key_type->methods['__toString'])
|
||||
)
|
||||
) {
|
||||
$bad_types[] = $atomic_key_type;
|
||||
|
||||
if ($atomic_key_type instanceof Type\Atomic\TFalse) {
|
||||
$good_types[] = new Type\Atomic\TLiteralInt(0);
|
||||
} elseif ($atomic_key_type instanceof Type\Atomic\TTrue) {
|
||||
$good_types[] = new Type\Atomic\TLiteralInt(1);
|
||||
} elseif ($atomic_key_type instanceof Type\Atomic\TBool) {
|
||||
$good_types[] = new Type\Atomic\TLiteralInt(0);
|
||||
$good_types[] = new Type\Atomic\TLiteralInt(1);
|
||||
} elseif ($atomic_key_type instanceof Type\Atomic\TLiteralFloat) {
|
||||
$good_types[] = new Type\Atomic\TLiteralInt((int)$atomic_key_type->value);
|
||||
} elseif ($atomic_key_type instanceof Type\Atomic\TFloat) {
|
||||
$good_types[] = new Type\Atomic\TInt;
|
||||
} else {
|
||||
$good_types[] = new Type\Atomic\TArrayKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($bad_types && $good_types) {
|
||||
$offset_type->substitute(
|
||||
TypeCombiner::combine($bad_types, $codebase),
|
||||
TypeCombiner::combine($good_types, $codebase)
|
||||
);
|
||||
}
|
||||
|
||||
if (IssueBuffer::accepts(
|
||||
new InvalidArrayOffset(
|
||||
'Cannot access value on variable ' . $array_var_id . ' ' . $used_offset
|
||||
|
@ -1002,6 +1002,21 @@ class ArrayAccessTest extends TestCase
|
||||
echo $arr[$s]["c"];
|
||||
}'
|
||||
],
|
||||
'TransformBadOffsetToGoodOnes' => [
|
||||
'<?php
|
||||
$index = 1.1;
|
||||
|
||||
/** @psalm-suppress InvalidArrayOffset */
|
||||
$_arr1 = [$index => 5];
|
||||
|
||||
$_arr2 = [];
|
||||
/** @psalm-suppress InvalidArrayOffset */
|
||||
$_arr2[$index] = 5;',
|
||||
[
|
||||
'$_arr1===' => 'non-empty-array<1, 5>',
|
||||
'$_arr2===' => 'non-empty-array<1, 5>',
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user