mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Break out array_key_exists tests
This commit is contained in:
parent
ace372bfb4
commit
f8e22ab7ac
@ -776,67 +776,6 @@ class ArrayAccessTest extends TestCase
|
|||||||
'<?php
|
'<?php
|
||||||
["s" => "str"]["str"[0]];',
|
["s" => "str"]["str"[0]];',
|
||||||
],
|
],
|
||||||
'assertConstantOffsetsInMethod' => [
|
|
||||||
'<?php
|
|
||||||
class C {
|
|
||||||
public const ARR = [
|
|
||||||
"a" => ["foo" => true],
|
|
||||||
"b" => []
|
|
||||||
];
|
|
||||||
|
|
||||||
public function bar(string $key): bool {
|
|
||||||
if (!array_key_exists($key, self::ARR) || !array_key_exists("foo", self::ARR[$key])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::ARR[$key]["foo"];
|
|
||||||
}
|
|
||||||
}',
|
|
||||||
[],
|
|
||||||
['MixedReturnStatement', 'MixedInferredReturnType'],
|
|
||||||
],
|
|
||||||
'assertSelfClassConstantOffsetsInFunction' => [
|
|
||||||
'<?php
|
|
||||||
namespace Ns;
|
|
||||||
|
|
||||||
class C {
|
|
||||||
public const ARR = [
|
|
||||||
"a" => ["foo" => true],
|
|
||||||
"b" => []
|
|
||||||
];
|
|
||||||
|
|
||||||
public function bar(?string $key): bool {
|
|
||||||
if ($key === null || !array_key_exists($key, self::ARR) || !array_key_exists("foo", self::ARR[$key])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::ARR[$key]["foo"];
|
|
||||||
}
|
|
||||||
}',
|
|
||||||
[],
|
|
||||||
['MixedReturnStatement', 'MixedInferredReturnType'],
|
|
||||||
],
|
|
||||||
'assertNamedClassConstantOffsetsInFunction' => [
|
|
||||||
'<?php
|
|
||||||
namespace Ns;
|
|
||||||
|
|
||||||
class C {
|
|
||||||
public const ARR = [
|
|
||||||
"a" => ["foo" => true],
|
|
||||||
"b" => [],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function bar(?string $key): bool {
|
|
||||||
if ($key === null || !array_key_exists($key, C::ARR) || !array_key_exists("foo", C::ARR[$key])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return C::ARR[$key]["foo"];
|
|
||||||
}',
|
|
||||||
[],
|
|
||||||
['MixedReturnStatement', 'MixedInferredReturnType'],
|
|
||||||
],
|
|
||||||
'arrayAccessAfterByRefArrayOffsetAssignment' => [
|
'arrayAccessAfterByRefArrayOffsetAssignment' => [
|
||||||
'<?php
|
'<?php
|
||||||
/**
|
/**
|
||||||
|
@ -948,50 +948,6 @@ class ArrayAssignmentTest extends TestCase
|
|||||||
echo $a[0];
|
echo $a[0];
|
||||||
}',
|
}',
|
||||||
],
|
],
|
||||||
'possiblyUndefinedArrayAccessWithArrayKeyExists' => [
|
|
||||||
'<?php
|
|
||||||
if (rand(0,1)) {
|
|
||||||
$a = ["a" => 1];
|
|
||||||
} else {
|
|
||||||
$a = [2, 3];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_key_exists(0, $a)) {
|
|
||||||
echo $a[0];
|
|
||||||
}',
|
|
||||||
],
|
|
||||||
'noCrashOnArrayKeyExistsBracket' => [
|
|
||||||
'<?php
|
|
||||||
class MyCollection {
|
|
||||||
/**
|
|
||||||
* @param int $commenter
|
|
||||||
* @param int $numToGet
|
|
||||||
* @return int[]
|
|
||||||
*/
|
|
||||||
public function getPosters($commenter, $numToGet=10) {
|
|
||||||
$posters = array();
|
|
||||||
$count = 0;
|
|
||||||
$a = new ArrayObject([[1234]]);
|
|
||||||
$iter = $a->getIterator();
|
|
||||||
while ($iter->valid() && $count < $numToGet) {
|
|
||||||
$value = $iter->current();
|
|
||||||
if ($value[0] != $commenter) {
|
|
||||||
if (!array_key_exists($value[0], $posters)) {
|
|
||||||
$posters[$value[0]] = 1;
|
|
||||||
$count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$iter->next();
|
|
||||||
}
|
|
||||||
return array_keys($posters);
|
|
||||||
}
|
|
||||||
}',
|
|
||||||
'assertions' => [],
|
|
||||||
'error_levels' => [
|
|
||||||
'MixedArrayAccess', 'MixedAssignment', 'MixedArrayOffset',
|
|
||||||
'MixedArgument',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'accessArrayAfterSuppressingBugs' => [
|
'accessArrayAfterSuppressingBugs' => [
|
||||||
'<?php
|
'<?php
|
||||||
$a = [];
|
$a = [];
|
||||||
@ -1632,32 +1588,6 @@ class ArrayAssignmentTest extends TestCase
|
|||||||
}',
|
}',
|
||||||
'error_message' => 'InvalidPropertyAssignmentValue',
|
'error_message' => 'InvalidPropertyAssignmentValue',
|
||||||
],
|
],
|
||||||
'possiblyUndefinedArrayAccessWithArrayKeyExistsOnWrongKey' => [
|
|
||||||
'<?php
|
|
||||||
if (rand(0,1)) {
|
|
||||||
$a = ["a" => 1];
|
|
||||||
} else {
|
|
||||||
$a = [2, 3];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_key_exists("a", $a)) {
|
|
||||||
echo $a[0];
|
|
||||||
}',
|
|
||||||
'error_message' => 'PossiblyUndefinedArrayOffset',
|
|
||||||
],
|
|
||||||
'possiblyUndefinedArrayAccessWithArrayKeyExistsOnMissingKey' => [
|
|
||||||
'<?php
|
|
||||||
if (rand(0,1)) {
|
|
||||||
$a = ["a" => 1];
|
|
||||||
} else {
|
|
||||||
$a = [2, 3];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_key_exists("b", $a)) {
|
|
||||||
echo $a[0];
|
|
||||||
}',
|
|
||||||
'error_message' => 'PossiblyUndefinedArrayOffset',
|
|
||||||
],
|
|
||||||
'duplicateStringArrayKey' => [
|
'duplicateStringArrayKey' => [
|
||||||
'<?php
|
'<?php
|
||||||
$arr = [
|
$arr = [
|
||||||
|
@ -1764,24 +1764,6 @@ class ArrayFunctionCallTest extends TestCase
|
|||||||
return $elements;
|
return $elements;
|
||||||
}'
|
}'
|
||||||
],
|
],
|
||||||
'arrayKeyExistsShoudldNotModifyIntType' => [
|
|
||||||
'<?php
|
|
||||||
class HttpError {
|
|
||||||
const ERRS = [
|
|
||||||
403 => "a",
|
|
||||||
404 => "b",
|
|
||||||
500 => "c"
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function init(string $code) : string {
|
|
||||||
if (array_key_exists($code, HttpError::ERRS)) {
|
|
||||||
return $code;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}'
|
|
||||||
],
|
|
||||||
'arrayChangeKeyCaseWithNonStringKeys' => [
|
'arrayChangeKeyCaseWithNonStringKeys' => [
|
||||||
'<?php
|
'<?php
|
||||||
|
|
||||||
|
@ -759,24 +759,6 @@ class ConstantTest extends TestCase
|
|||||||
echo A::C[$s];
|
echo A::C[$s];
|
||||||
}'
|
}'
|
||||||
],
|
],
|
||||||
'arrayKeyExistsWithClassConst' => [
|
|
||||||
'<?php
|
|
||||||
class C {}
|
|
||||||
class D {}
|
|
||||||
|
|
||||||
class A {
|
|
||||||
const FLAGS = [
|
|
||||||
0 => [C::class => "foo"],
|
|
||||||
1 => [D::class => "bar"],
|
|
||||||
];
|
|
||||||
|
|
||||||
private function foo(int $i) : void {
|
|
||||||
if (array_key_exists(C::class, self::FLAGS[$i])) {
|
|
||||||
echo self::FLAGS[$i][C::class];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}'
|
|
||||||
],
|
|
||||||
'getClassConstantOffset' => [
|
'getClassConstantOffset' => [
|
||||||
'<?php
|
'<?php
|
||||||
class C {
|
class C {
|
||||||
@ -835,19 +817,6 @@ class ConstantTest extends TestCase
|
|||||||
|
|
||||||
echo B::VALUES["there"];'
|
echo B::VALUES["there"];'
|
||||||
],
|
],
|
||||||
'constantArrayKeyExistsWithClassConstant' => [
|
|
||||||
'<?php
|
|
||||||
class Foo {
|
|
||||||
public const F = "key";
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param array{key?: string} $a */
|
|
||||||
function one(array $a): void {
|
|
||||||
if (array_key_exists(Foo::F, $a)) {
|
|
||||||
echo $a[Foo::F];
|
|
||||||
}
|
|
||||||
}'
|
|
||||||
],
|
|
||||||
'internalConstWildcard' => [
|
'internalConstWildcard' => [
|
||||||
'<?php
|
'<?php
|
||||||
/**
|
/**
|
||||||
|
339
tests/TypeReconciliation/ArrayKeyExistsTest.php
Normal file
339
tests/TypeReconciliation/ArrayKeyExistsTest.php
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
<?php
|
||||||
|
namespace Psalm\Tests\TypeReconciliation;
|
||||||
|
|
||||||
|
class ArrayKeyExistsTest extends \Psalm\Tests\TestCase
|
||||||
|
{
|
||||||
|
use \Psalm\Tests\Traits\ValidCodeAnalysisTestTrait;
|
||||||
|
use \Psalm\Tests\Traits\InvalidCodeAnalysisTestTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return iterable<string,array{string,assertions?:array<string,string>,error_levels?:string[]}>
|
||||||
|
*/
|
||||||
|
public function providerValidCodeParse(): iterable
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'arrayKeyExistsOnStringArrayShouldInformArrayness' => [
|
||||||
|
'<?php
|
||||||
|
/**
|
||||||
|
* @param string[] $a
|
||||||
|
* @return array{b: string}
|
||||||
|
*/
|
||||||
|
function foo(array $a) {
|
||||||
|
if (array_key_exists("b", $a)) {
|
||||||
|
return $a;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \Exception("bad");
|
||||||
|
}'
|
||||||
|
],
|
||||||
|
'arrayKeyExistsThrice' => [
|
||||||
|
'<?php
|
||||||
|
function three(array $a): void {
|
||||||
|
if (!array_key_exists("a", $a)
|
||||||
|
|| !array_key_exists("b", $a)
|
||||||
|
|| !array_key_exists("c", $a)
|
||||||
|
|| (!is_string($a["a"]) && !is_int($a["a"]))
|
||||||
|
|| (!is_string($a["b"]) && !is_int($a["b"]))
|
||||||
|
|| (!is_string($a["c"]) && !is_int($a["c"]))
|
||||||
|
) {
|
||||||
|
throw new \Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $a["a"];
|
||||||
|
echo $a["b"];
|
||||||
|
}'
|
||||||
|
],
|
||||||
|
'arrayKeyExistsTwice' => [
|
||||||
|
'<?php
|
||||||
|
function two(array $a): void {
|
||||||
|
if (!array_key_exists("a", $a) || !(is_string($a["a"]) || is_int($a["a"])) ||
|
||||||
|
!array_key_exists("b", $a) || !(is_string($a["b"]) || is_int($a["b"]))
|
||||||
|
) {
|
||||||
|
throw new \Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $a["a"];
|
||||||
|
echo $a["b"];
|
||||||
|
}'
|
||||||
|
],
|
||||||
|
'assertConstantOffsetsInMethod' => [
|
||||||
|
'<?php
|
||||||
|
class C {
|
||||||
|
public const ARR = [
|
||||||
|
"a" => ["foo" => true],
|
||||||
|
"b" => []
|
||||||
|
];
|
||||||
|
|
||||||
|
public function bar(string $key): bool {
|
||||||
|
if (!array_key_exists($key, self::ARR) || !array_key_exists("foo", self::ARR[$key])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::ARR[$key]["foo"];
|
||||||
|
}
|
||||||
|
}',
|
||||||
|
[],
|
||||||
|
['MixedReturnStatement', 'MixedInferredReturnType'],
|
||||||
|
],
|
||||||
|
'assertSelfClassConstantOffsetsInFunction' => [
|
||||||
|
'<?php
|
||||||
|
namespace Ns;
|
||||||
|
|
||||||
|
class C {
|
||||||
|
public const ARR = [
|
||||||
|
"a" => ["foo" => true],
|
||||||
|
"b" => []
|
||||||
|
];
|
||||||
|
|
||||||
|
public function bar(?string $key): bool {
|
||||||
|
if ($key === null || !array_key_exists($key, self::ARR) || !array_key_exists("foo", self::ARR[$key])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::ARR[$key]["foo"];
|
||||||
|
}
|
||||||
|
}',
|
||||||
|
[],
|
||||||
|
['MixedReturnStatement', 'MixedInferredReturnType'],
|
||||||
|
],
|
||||||
|
'assertNamedClassConstantOffsetsInFunction' => [
|
||||||
|
'<?php
|
||||||
|
namespace Ns;
|
||||||
|
|
||||||
|
class C {
|
||||||
|
public const ARR = [
|
||||||
|
"a" => ["foo" => true],
|
||||||
|
"b" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function bar(?string $key): bool {
|
||||||
|
if ($key === null || !array_key_exists($key, C::ARR) || !array_key_exists("foo", C::ARR[$key])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return C::ARR[$key]["foo"];
|
||||||
|
}',
|
||||||
|
[],
|
||||||
|
['MixedReturnStatement', 'MixedInferredReturnType'],
|
||||||
|
],
|
||||||
|
'possiblyUndefinedArrayAccessWithArrayKeyExists' => [
|
||||||
|
'<?php
|
||||||
|
if (rand(0,1)) {
|
||||||
|
$a = ["a" => 1];
|
||||||
|
} else {
|
||||||
|
$a = [2, 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists(0, $a)) {
|
||||||
|
echo $a[0];
|
||||||
|
}',
|
||||||
|
],
|
||||||
|
'arrayKeyExistsShoudldNotModifyIntType' => [
|
||||||
|
'<?php
|
||||||
|
class HttpError {
|
||||||
|
const ERRS = [
|
||||||
|
403 => "a",
|
||||||
|
404 => "b",
|
||||||
|
500 => "c"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function init(string $code) : string {
|
||||||
|
if (array_key_exists($code, HttpError::ERRS)) {
|
||||||
|
return $code;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}'
|
||||||
|
],
|
||||||
|
'arrayKeyExistsWithClassConst' => [
|
||||||
|
'<?php
|
||||||
|
class C {}
|
||||||
|
class D {}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
const FLAGS = [
|
||||||
|
0 => [C::class => "foo"],
|
||||||
|
1 => [D::class => "bar"],
|
||||||
|
];
|
||||||
|
|
||||||
|
private function foo(int $i) : void {
|
||||||
|
if (array_key_exists(C::class, self::FLAGS[$i])) {
|
||||||
|
echo self::FLAGS[$i][C::class];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
],
|
||||||
|
'constantArrayKeyExistsWithClassConstant' => [
|
||||||
|
'<?php
|
||||||
|
class Foo {
|
||||||
|
public const F = "key";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param array{key?: string} $a */
|
||||||
|
function one(array $a): void {
|
||||||
|
if (array_key_exists(Foo::F, $a)) {
|
||||||
|
echo $a[Foo::F];
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
],
|
||||||
|
'assertTypeNarrowedByNestedIsset' => [
|
||||||
|
'<?php
|
||||||
|
/**
|
||||||
|
* @psalm-suppress MixedMethodCall
|
||||||
|
* @psalm-suppress MixedArgument
|
||||||
|
*/
|
||||||
|
function foo(array $array = []): void {
|
||||||
|
if (array_key_exists("a", $array)) {
|
||||||
|
echo $array["a"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists("b", $array)) {
|
||||||
|
echo $array["b"]->format("Y-m-d");
|
||||||
|
}
|
||||||
|
}',
|
||||||
|
],
|
||||||
|
'assertArrayKeyExistsRefinesType' => [
|
||||||
|
'<?php
|
||||||
|
class Foo {
|
||||||
|
/** @var array<int,string> */
|
||||||
|
public const DAYS = [
|
||||||
|
1 => "mon",
|
||||||
|
2 => "tue",
|
||||||
|
3 => "wed",
|
||||||
|
4 => "thu",
|
||||||
|
5 => "fri",
|
||||||
|
6 => "sat",
|
||||||
|
7 => "sun",
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @param key-of<self::DAYS> $dayNum*/
|
||||||
|
private static function doGetDayName(int $dayNum): string {
|
||||||
|
return self::DAYS[$dayNum];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @throws LogicException */
|
||||||
|
public static function getDayName(int $dayNum): string {
|
||||||
|
if (! array_key_exists($dayNum, self::DAYS)) {
|
||||||
|
throw new \LogicException();
|
||||||
|
}
|
||||||
|
return self::doGetDayName($dayNum);
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
],
|
||||||
|
'arrayKeyExistsInferString' => [
|
||||||
|
'<?php
|
||||||
|
function foo(mixed $file) : string {
|
||||||
|
/** @psalm-suppress MixedArgument */
|
||||||
|
if (array_key_exists($file, ["a" => 1, "b" => 2])) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}',
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
'8.0'
|
||||||
|
],
|
||||||
|
'arrayKeyExistsComplex' => [
|
||||||
|
'<?php
|
||||||
|
class A {
|
||||||
|
private const MAP = [
|
||||||
|
"a" => 1,
|
||||||
|
"b" => 2,
|
||||||
|
"c" => 3,
|
||||||
|
"d" => 4,
|
||||||
|
"e" => 5,
|
||||||
|
"f" => 6,
|
||||||
|
"g" => 7,
|
||||||
|
"h" => 8,
|
||||||
|
"i" => 9,
|
||||||
|
"j" => 10,
|
||||||
|
"k" => 11,
|
||||||
|
];
|
||||||
|
|
||||||
|
public function doWork(string $a): void {
|
||||||
|
if (!array_key_exists($a, self::MAP)) {}
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
],
|
||||||
|
'arrayKeyExistsAccess' => [
|
||||||
|
'<?php
|
||||||
|
/** @param array<int, string> $arr */
|
||||||
|
function foo(array $arr) : void {
|
||||||
|
if (array_key_exists(1, $arr)) {
|
||||||
|
$a = ($arr[1] === "b") ? true : false;
|
||||||
|
}
|
||||||
|
}',
|
||||||
|
],
|
||||||
|
'noCrashOnArrayKeyExistsBracket' => [
|
||||||
|
'<?php
|
||||||
|
class MyCollection {
|
||||||
|
/**
|
||||||
|
* @param int $commenter
|
||||||
|
* @param int $numToGet
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
public function getPosters($commenter, $numToGet=10) {
|
||||||
|
$posters = array();
|
||||||
|
$count = 0;
|
||||||
|
$a = new ArrayObject([[1234]]);
|
||||||
|
$iter = $a->getIterator();
|
||||||
|
while ($iter->valid() && $count < $numToGet) {
|
||||||
|
$value = $iter->current();
|
||||||
|
if ($value[0] != $commenter) {
|
||||||
|
if (!array_key_exists($value[0], $posters)) {
|
||||||
|
$posters[$value[0]] = 1;
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$iter->next();
|
||||||
|
}
|
||||||
|
return array_keys($posters);
|
||||||
|
}
|
||||||
|
}',
|
||||||
|
'assertions' => [],
|
||||||
|
'error_levels' => [
|
||||||
|
'MixedArrayAccess', 'MixedAssignment', 'MixedArrayOffset',
|
||||||
|
'MixedArgument',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return iterable<string,array{string,error_message:string,2?:string[],3?:bool,4?:string}>
|
||||||
|
*/
|
||||||
|
public function providerInvalidCodeParse(): iterable
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'possiblyUndefinedArrayAccessWithArrayKeyExistsOnWrongKey' => [
|
||||||
|
'<?php
|
||||||
|
if (rand(0,1)) {
|
||||||
|
$a = ["a" => 1];
|
||||||
|
} else {
|
||||||
|
$a = [2, 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists("a", $a)) {
|
||||||
|
echo $a[0];
|
||||||
|
}',
|
||||||
|
'error_message' => 'PossiblyUndefinedArrayOffset',
|
||||||
|
],
|
||||||
|
'possiblyUndefinedArrayAccessWithArrayKeyExistsOnMissingKey' => [
|
||||||
|
'<?php
|
||||||
|
if (rand(0,1)) {
|
||||||
|
$a = ["a" => 1];
|
||||||
|
} else {
|
||||||
|
$a = [2, 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists("b", $a)) {
|
||||||
|
echo $a[0];
|
||||||
|
}',
|
||||||
|
'error_message' => 'PossiblyUndefinedArrayOffset',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -1394,22 +1394,6 @@ class ConditionalTest extends \Psalm\Tests\TestCase
|
|||||||
return $ret;
|
return $ret;
|
||||||
}',
|
}',
|
||||||
],
|
],
|
||||||
'assertTypeNarrowedByNestedIsset' => [
|
|
||||||
'<?php
|
|
||||||
/**
|
|
||||||
* @psalm-suppress MixedMethodCall
|
|
||||||
* @psalm-suppress MixedArgument
|
|
||||||
*/
|
|
||||||
function foo(array $array = []): void {
|
|
||||||
if (array_key_exists("a", $array)) {
|
|
||||||
echo $array["a"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_key_exists("b", $array)) {
|
|
||||||
echo $array["b"]->format("Y-m-d");
|
|
||||||
}
|
|
||||||
}',
|
|
||||||
],
|
|
||||||
'assertCheckOnNonZeroArrayOffset' => [
|
'assertCheckOnNonZeroArrayOffset' => [
|
||||||
'<?php
|
'<?php
|
||||||
/**
|
/**
|
||||||
@ -1719,34 +1703,6 @@ class ConditionalTest extends \Psalm\Tests\TestCase
|
|||||||
}
|
}
|
||||||
}'
|
}'
|
||||||
],
|
],
|
||||||
'assertArrayKeyExistsRefinesType' => [
|
|
||||||
'<?php
|
|
||||||
class Foo {
|
|
||||||
/** @var array<int,string> */
|
|
||||||
public const DAYS = [
|
|
||||||
1 => "mon",
|
|
||||||
2 => "tue",
|
|
||||||
3 => "wed",
|
|
||||||
4 => "thu",
|
|
||||||
5 => "fri",
|
|
||||||
6 => "sat",
|
|
||||||
7 => "sun",
|
|
||||||
];
|
|
||||||
|
|
||||||
/** @param key-of<self::DAYS> $dayNum*/
|
|
||||||
private static function doGetDayName(int $dayNum): string {
|
|
||||||
return self::DAYS[$dayNum];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @throws LogicException */
|
|
||||||
public static function getDayName(int $dayNum): string {
|
|
||||||
if (! array_key_exists($dayNum, self::DAYS)) {
|
|
||||||
throw new \LogicException();
|
|
||||||
}
|
|
||||||
return self::doGetDayName($dayNum);
|
|
||||||
}
|
|
||||||
}'
|
|
||||||
],
|
|
||||||
'assertPropertiesOfElseStatement' => [
|
'assertPropertiesOfElseStatement' => [
|
||||||
'<?php
|
'<?php
|
||||||
class C {
|
class C {
|
||||||
|
@ -613,20 +613,7 @@ class IssetTest extends \Psalm\Tests\TestCase
|
|||||||
throw new \Exception("bad");
|
throw new \Exception("bad");
|
||||||
}'
|
}'
|
||||||
],
|
],
|
||||||
'arrayKeyExistsOnStringArrayShouldInformArrayness' => [
|
|
||||||
'<?php
|
|
||||||
/**
|
|
||||||
* @param string[] $a
|
|
||||||
* @return array{b: string}
|
|
||||||
*/
|
|
||||||
function foo(array $a) {
|
|
||||||
if (array_key_exists("b", $a)) {
|
|
||||||
return $a;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \Exception("bad");
|
|
||||||
}'
|
|
||||||
],
|
|
||||||
'issetOnArrayTwice' => [
|
'issetOnArrayTwice' => [
|
||||||
'<?php
|
'<?php
|
||||||
function foo(array $options): void {
|
function foo(array $options): void {
|
||||||
@ -966,36 +953,6 @@ class IssetTest extends \Psalm\Tests\TestCase
|
|||||||
assert($dt);
|
assert($dt);
|
||||||
}'
|
}'
|
||||||
],
|
],
|
||||||
'arrayKeyExistsThrice' => [
|
|
||||||
'<?php
|
|
||||||
function three(array $a): void {
|
|
||||||
if (!array_key_exists("a", $a)
|
|
||||||
|| !array_key_exists("b", $a)
|
|
||||||
|| !array_key_exists("c", $a)
|
|
||||||
|| (!is_string($a["a"]) && !is_int($a["a"]))
|
|
||||||
|| (!is_string($a["b"]) && !is_int($a["b"]))
|
|
||||||
|| (!is_string($a["c"]) && !is_int($a["c"]))
|
|
||||||
) {
|
|
||||||
throw new \Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
echo $a["a"];
|
|
||||||
echo $a["b"];
|
|
||||||
}'
|
|
||||||
],
|
|
||||||
'arrayKeyExistsTwice' => [
|
|
||||||
'<?php
|
|
||||||
function two(array $a): void {
|
|
||||||
if (!array_key_exists("a", $a) || !(is_string($a["a"]) || is_int($a["a"])) ||
|
|
||||||
!array_key_exists("b", $a) || !(is_string($a["b"]) || is_int($a["b"]))
|
|
||||||
) {
|
|
||||||
throw new \Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
echo $a["a"];
|
|
||||||
echo $a["b"];
|
|
||||||
}'
|
|
||||||
],
|
|
||||||
'issetOnNullableMixed' => [
|
'issetOnNullableMixed' => [
|
||||||
'<?php
|
'<?php
|
||||||
function processParam(mixed $param) : void {
|
function processParam(mixed $param) : void {
|
||||||
|
@ -457,15 +457,6 @@ class RedundantConditionTest extends \Psalm\Tests\TestCase
|
|||||||
var_export($x);
|
var_export($x);
|
||||||
}',
|
}',
|
||||||
],
|
],
|
||||||
'arrayKeyExistsAccess' => [
|
|
||||||
'<?php
|
|
||||||
/** @param array<int, string> $arr */
|
|
||||||
function foo(array $arr) : void {
|
|
||||||
if (array_key_exists(1, $arr)) {
|
|
||||||
$a = ($arr[1] === "b") ? true : false;
|
|
||||||
}
|
|
||||||
}',
|
|
||||||
],
|
|
||||||
'noRedundantConditionStringNotFalse' => [
|
'noRedundantConditionStringNotFalse' => [
|
||||||
'<?php
|
'<?php
|
||||||
function foo(string $s) : void {
|
function foo(string $s) : void {
|
||||||
|
@ -836,42 +836,6 @@ class ValueTest extends \Psalm\Tests\TestCase
|
|||||||
if (!in_array(A::ACTION_ONE, $case_actions, true)) {}
|
if (!in_array(A::ACTION_ONE, $case_actions, true)) {}
|
||||||
}'
|
}'
|
||||||
],
|
],
|
||||||
'arrayKeyExistsInferString' => [
|
|
||||||
'<?php
|
|
||||||
function foo(mixed $file) : string {
|
|
||||||
/** @psalm-suppress MixedArgument */
|
|
||||||
if (array_key_exists($file, ["a" => 1, "b" => 2])) {
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}',
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
'8.0'
|
|
||||||
],
|
|
||||||
'arrayKeyExistsComplex' => [
|
|
||||||
'<?php
|
|
||||||
class A {
|
|
||||||
private const MAP = [
|
|
||||||
"a" => 1,
|
|
||||||
"b" => 2,
|
|
||||||
"c" => 3,
|
|
||||||
"d" => 4,
|
|
||||||
"e" => 5,
|
|
||||||
"f" => 6,
|
|
||||||
"g" => 7,
|
|
||||||
"h" => 8,
|
|
||||||
"i" => 9,
|
|
||||||
"j" => 10,
|
|
||||||
"k" => 11,
|
|
||||||
];
|
|
||||||
|
|
||||||
public function doWork(string $a): void {
|
|
||||||
if (!array_key_exists($a, self::MAP)) {}
|
|
||||||
}
|
|
||||||
}'
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user