1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Fix array_key_exists() with all int literal keys (#5197)

When checking code like the following:

```
<?php

function checkNegated(string $key): void {
    $arr = [
        0 => "foo",
        1 => "bar",
    ];

    if (!array_key_exists($key, $arr)) {
        printf("not found\n");
    }
}

function check(string $key): void {
    $arr = [
        0 => "foo",
        1 => "bar",
    ];

    if (array_key_exists($key, $arr)) {
        printf("found\n");
    }
}
```

the `if` in `checkNegated` would cause:

```
ERROR: RedundantCondition - 9:10 - Type string for $key is never =int(0)
```

This happens when the array keys are all int literals, but the "needle"
is a string.

`array_key_exists()` uses a loose equality comparison, but the generated
assertions for this specific case
(`AssertionFinder::getArrayKeyExistsAssertions`) was generating strict
equality clauses. This commit fixes it by changing the generated clause
from `=` to `~`.
This commit is contained in:
Alberto Piai 2021-02-12 23:00:38 +01:00 committed by GitHub
parent 4077de2c93
commit 144bb37f76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 1 deletions

View File

@ -3770,7 +3770,7 @@ class AssertionFinder
}
} elseif ($key_type->allIntLiterals() && !$key_type->possibly_undefined) {
foreach ($key_type->getLiteralInts() as $array_literal_type) {
$literal_assertions[] = '=' . $array_literal_type->getAssertionString();
$literal_assertions[] = '~' . $array_literal_type->getAssertionString();
}
}
}

View File

@ -327,6 +327,34 @@ class ArrayKeyExistsTest extends \Psalm\Tests\TestCase
return 1;
}'
],
'comparesStringAndAllIntKeysCorrectly' => [
'<?php
/**
* @param array<1|2|3, string> $arr
* @return bool
*/
function checkArrayKeyExistsComparison(array $arr, string $key): bool
{
if (array_key_exists($key, $arr)) {
return true;
}
return false;
}'
],
'comparesStringAndAllIntKeysCorrectlyNegated' => [
'<?php
/**
* @param array<1|2|3, string> $arr
* @return bool
*/
function checkArrayKeyExistsComparisonNegated(array $arr, string $key): bool
{
if (!array_key_exists($key, $arr)) {
return false;
}
return true;
}'
],
];
}