mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
parent
f2347303c9
commit
292f6e797f
@ -225,8 +225,10 @@ class Reconciler
|
||||
$codebase,
|
||||
$key,
|
||||
$existing_types,
|
||||
$new_types,
|
||||
$code_location,
|
||||
$has_isset || $has_inverted_isset,
|
||||
$has_isset,
|
||||
$has_inverted_isset,
|
||||
$has_empty
|
||||
);
|
||||
|
||||
@ -422,6 +424,7 @@ class Reconciler
|
||||
*
|
||||
* @param string $key
|
||||
* @param array<string,Type\Union> $existing_keys
|
||||
* @param array<string,mixed> $new_assertions
|
||||
* @param string[][] $new_type_parts
|
||||
*
|
||||
* @return Type\Union|null
|
||||
@ -430,8 +433,10 @@ class Reconciler
|
||||
Codebase $codebase,
|
||||
string $key,
|
||||
array &$existing_keys,
|
||||
array $new_assertions,
|
||||
?CodeLocation $code_location,
|
||||
bool $has_isset,
|
||||
bool $has_inverted_isset,
|
||||
bool $has_empty
|
||||
) {
|
||||
$key_parts = self::breakUpPathIntoParts($key);
|
||||
@ -488,7 +493,11 @@ class Reconciler
|
||||
|
||||
$new_base_type_candidate = clone $existing_key_type_part->type_params[1];
|
||||
|
||||
if ($has_isset) {
|
||||
if (($has_isset || $has_inverted_isset) && isset($new_assertions[$new_base_key])) {
|
||||
if ($has_inverted_isset && $new_base_key === $key) {
|
||||
$new_base_type_candidate->addType(new Type\Atomic\TNull);
|
||||
}
|
||||
|
||||
$new_base_type_candidate->possibly_undefined = true;
|
||||
}
|
||||
} elseif ($existing_key_type_part instanceof Type\Atomic\TList) {
|
||||
@ -498,7 +507,11 @@ class Reconciler
|
||||
|
||||
$new_base_type_candidate = clone $existing_key_type_part->type_param;
|
||||
|
||||
if ($has_isset) {
|
||||
if (($has_isset || $has_inverted_isset) && isset($new_assertions[$new_base_key])) {
|
||||
if ($has_inverted_isset && $new_base_key === $key) {
|
||||
$new_base_type_candidate->addType(new Type\Atomic\TNull);
|
||||
}
|
||||
|
||||
$new_base_type_candidate->possibly_undefined = true;
|
||||
}
|
||||
} elseif ($existing_key_type_part instanceof Type\Atomic\TNull) {
|
||||
|
@ -796,20 +796,6 @@ class IssetTest extends \Psalm\Tests\TestCase
|
||||
}
|
||||
}'
|
||||
],
|
||||
'SKIPPED-issetOnArrayOfArraysReturningString' => [
|
||||
'<?php
|
||||
function foo(int $i) : ?string {
|
||||
/** @var array<array> */
|
||||
$tokens = [];
|
||||
|
||||
if (!isset($tokens[$i]["a"])) {
|
||||
/** @psalm-suppress PossiblyUndefinedArrayOffset */
|
||||
return $tokens[$i]["a"];
|
||||
}
|
||||
|
||||
return "hello";
|
||||
}',
|
||||
],
|
||||
'issetOnArrayOfArraysReturningStringInElse' => [
|
||||
'<?php
|
||||
function foo(int $i) : string {
|
||||
@ -823,6 +809,84 @@ class IssetTest extends \Psalm\Tests\TestCase
|
||||
}
|
||||
}',
|
||||
],
|
||||
'issetOnArrayOfObjectsAssertingOnIssetValue' => [
|
||||
'<?php
|
||||
class A {
|
||||
public ?string $name = null;
|
||||
}
|
||||
|
||||
function foo(int $i) : void {
|
||||
/** @var array<int, A> */
|
||||
$tokens = [];
|
||||
|
||||
if (isset($tokens[$i]->name) && $tokens[$i]->name === "hello") {}
|
||||
}',
|
||||
],
|
||||
'issetOnArrayOfObjectsAssertingOnNotIssetValue' => [
|
||||
'<?php
|
||||
class A {
|
||||
public ?string $name = null;
|
||||
}
|
||||
|
||||
function foo(int $i) : void {
|
||||
/** @var array<int, A> */
|
||||
$tokens = [];
|
||||
|
||||
if (!isset($tokens[$i])) {
|
||||
if (rand(0, 1)) {
|
||||
if (rand(0, 1)) {
|
||||
$tokens[$i] = new A();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
echo $tokens[$i]->name;
|
||||
}',
|
||||
],
|
||||
'issetOnArrayOfMixed' => [
|
||||
'<?php
|
||||
/**
|
||||
* @psalm-suppress MixedArrayAccess
|
||||
* @psalm-suppress MixedArgument
|
||||
*/
|
||||
function foo(int $i) : void {
|
||||
/** @var array */
|
||||
$tokens = [];
|
||||
|
||||
if (!isset($tokens[$i]["a"])) {
|
||||
echo $tokens[$i]["b"];
|
||||
}
|
||||
}',
|
||||
],
|
||||
'issetOnArrayOfArrays' => [
|
||||
'<?php
|
||||
/**
|
||||
* @psalm-suppress MixedArgument
|
||||
*/
|
||||
function foo(int $i) : void {
|
||||
/** @var array<array> */
|
||||
$tokens = [];
|
||||
|
||||
if (!isset($tokens[$i]["a"])) {
|
||||
echo $tokens[$i]["b"];
|
||||
}
|
||||
}',
|
||||
],
|
||||
'issetOnArrayOfArrayOfStrings' => [
|
||||
'<?php
|
||||
function foo(int $i) : void {
|
||||
/** @var array<int, array<string, string>> */
|
||||
$tokens = [];
|
||||
|
||||
if (!isset($tokens[$i]["a"])) {
|
||||
echo $tokens[$i]["b"];
|
||||
}
|
||||
}',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@ -902,47 +966,17 @@ class IssetTest extends \Psalm\Tests\TestCase
|
||||
}',
|
||||
'error_message' => 'TypeDoesNotContainType'
|
||||
],
|
||||
'issetOnArrayOfMixed' => [
|
||||
'issetOnArrayOfArraysReturningString' => [
|
||||
'<?php
|
||||
/**
|
||||
* @psalm-suppress PossiblyUndefinedStringArrayOffset
|
||||
* @psalm-suppress MixedArrayAccess
|
||||
* @psalm-suppress MixedArgument
|
||||
*/
|
||||
function foo(int $i) : void {
|
||||
/** @var array */
|
||||
$tokens = [];
|
||||
|
||||
if (!isset($tokens[$i]["a"])) {
|
||||
echo $tokens[$i]["b"];
|
||||
}
|
||||
}',
|
||||
'error_message' => 'PossiblyUndefinedArrayOffset',
|
||||
],
|
||||
'SKIPPED-issetOnArrayOfArrays' => [
|
||||
'<?php
|
||||
/**
|
||||
* @psalm-suppress MixedArgument
|
||||
*/
|
||||
function foo(int $i) : void {
|
||||
function foo(int $i) : ?string {
|
||||
/** @var array<array> */
|
||||
$tokens = [];
|
||||
|
||||
if (!isset($tokens[$i]["a"])) {
|
||||
echo $tokens[$i]["b"];
|
||||
return $tokens[$i]["a"];
|
||||
}
|
||||
}',
|
||||
'error_message' => 'PossiblyUndefinedArrayOffset',
|
||||
],
|
||||
'SKIPPED-issetOnArrayOfArrayOfStrings' => [
|
||||
'<?php
|
||||
function foo(int $i) : void {
|
||||
/** @var array<int, array<string, string>> */
|
||||
$tokens = [];
|
||||
|
||||
if (!isset($tokens[$i]["a"])) {
|
||||
echo $tokens[$i]["b"];
|
||||
}
|
||||
return "hello";
|
||||
}',
|
||||
'error_message' => 'PossiblyUndefinedArrayOffset',
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user