1
0
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:
Brown 2018-12-14 18:52:29 -05:00
parent b7d4db892c
commit 699d763cc1
3 changed files with 54 additions and 15 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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'],
]
];
}