mirror of
https://github.com/danog/psalm.git
synced 2024-11-27 04:45:20 +01:00
Make isset($a[foo]) imply $a is not a string
This commit is contained in:
parent
b7d4db892c
commit
699d763cc1
@ -152,7 +152,6 @@ class ArrayFetchAnalyzer
|
||||
if ($context->inside_isset
|
||||
&& $stmt->dim
|
||||
&& isset($stmt->dim->inferredType)
|
||||
&& $stmt->var->inferredType->hasArray()
|
||||
&& ($stmt->var instanceof PhpParser\Node\Expr\ClassConstFetch
|
||||
|| $stmt->var instanceof PhpParser\Node\Expr\ConstFetch)
|
||||
) {
|
||||
@ -165,7 +164,10 @@ class ArrayFetchAnalyzer
|
||||
$const_array_key_type = $array_type->getGenericKeyType();
|
||||
}
|
||||
|
||||
if ($dim_var_id && !$const_array_key_type->hasMixed() && !$stmt->dim->inferredType->hasMixed()) {
|
||||
if ($dim_var_id
|
||||
&& !$const_array_key_type->hasMixed()
|
||||
&& !$stmt->dim->inferredType->hasMixed()
|
||||
) {
|
||||
$new_offset_type = clone $stmt->dim->inferredType;
|
||||
$const_array_key_atomic_types = $const_array_key_type->getTypes();
|
||||
|
||||
@ -646,17 +648,21 @@ class ArrayFetchAnalyzer
|
||||
true
|
||||
)) {
|
||||
$expected_offset_types[] = $valid_offset_type->getId();
|
||||
|
||||
if (!$inside_isset) {
|
||||
$array_access_type = Type::getMixed();
|
||||
}
|
||||
} else {
|
||||
$has_valid_offset = true;
|
||||
}
|
||||
|
||||
if (!$array_access_type) {
|
||||
$array_access_type = Type::getSingleLetter();
|
||||
} else {
|
||||
$array_access_type = Type::combineUnionTypes(
|
||||
$array_access_type,
|
||||
Type::getSingleLetter()
|
||||
);
|
||||
if (!$array_access_type) {
|
||||
$array_access_type = Type::getSingleLetter();
|
||||
} else {
|
||||
$array_access_type = Type::combineUnionTypes(
|
||||
$array_access_type,
|
||||
Type::getSingleLetter()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
@ -799,7 +805,9 @@ class ArrayFetchAnalyzer
|
||||
. (is_int($key_value) ? $key_value : '\'' . $key_value . '\'');
|
||||
}
|
||||
|
||||
if ($has_valid_offset) {
|
||||
if ($has_valid_offset && $inside_isset) {
|
||||
// do nothing
|
||||
} elseif ($has_valid_offset) {
|
||||
if (IssueBuffer::accepts(
|
||||
new PossiblyInvalidArrayOffset(
|
||||
'Cannot access value on variable ' . $array_var_id . ' ' . $used_offset
|
||||
|
@ -97,6 +97,10 @@ class Reconciler
|
||||
|
||||
$new_base_key = $base_key . '[' . $array_key . ']';
|
||||
|
||||
if (strpos($array_key, '\'') !== false) {
|
||||
$new_types[$base_key][] = ['!string'];
|
||||
}
|
||||
|
||||
$base_key = $new_base_key;
|
||||
} elseif ($divider === '->') {
|
||||
$property_name = array_shift($key_parts);
|
||||
@ -128,10 +132,6 @@ class Reconciler
|
||||
// make sure array keys come after base keys
|
||||
ksort($new_types);
|
||||
|
||||
if (empty($new_types)) {
|
||||
return $existing_types;
|
||||
}
|
||||
|
||||
$codebase = $statements_analyzer->getCodebase();
|
||||
|
||||
foreach ($new_types as $key => $new_type_parts) {
|
||||
|
@ -441,6 +441,37 @@ class IssetTest extends TestCase
|
||||
'assertions' => [],
|
||||
'error_levels' => ['PossiblyNullReference'],
|
||||
],
|
||||
'assertArrayAfterIssetStringOffset' => [
|
||||
'<?php
|
||||
/**
|
||||
* @param string|array $a
|
||||
*/
|
||||
function _renderInput($a) : array {
|
||||
if (isset($a["foo"], $a["bar"])) {
|
||||
return $a;
|
||||
}
|
||||
|
||||
return [];
|
||||
}'
|
||||
],
|
||||
'assertMoreComplicatedArrayAfterIssetStringOffset' => [
|
||||
'<?php
|
||||
/**
|
||||
* @param string|int $val
|
||||
* @param string|array $text
|
||||
* @param array $data
|
||||
*/
|
||||
function _renderInput($val, $text, $data) : array {
|
||||
if (is_int($val) && isset($text["foo"], $text["bar"])) {
|
||||
$radio = $text;
|
||||
} else {
|
||||
$radio = ["value" => $val, "text" => $text];
|
||||
}
|
||||
return $radio;
|
||||
}',
|
||||
'assertions' => [],
|
||||
'error_levels' => ['MixedAssignment'],
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user