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

Merge pull request #7449 from orklah/7415-2

Array key exists assert both ways
This commit is contained in:
orklah 2022-01-21 00:42:16 +01:00 committed by GitHub
commit f6369dc086
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 51 deletions

View File

@ -3698,65 +3698,65 @@ class AssertionFinder
if ($literal_assertions && $first_var_name) {
$if_types[$first_var_name] = [$literal_assertions];
} else {
$array_root = isset($expr->getArgs()[1]->value)
? ExpressionIdentifier::getArrayVarId(
$expr->getArgs()[1]->value,
$this_class_name,
$source
)
: null;
}
if ($array_root) {
if ($first_var_name === null && isset($expr->getArgs()[0])) {
$first_arg = $expr->getArgs()[0];
$array_root = isset($expr->getArgs()[1]->value)
? ExpressionIdentifier::getArrayVarId(
$expr->getArgs()[1]->value,
$this_class_name,
$source
)
: null;
if ($first_arg->value instanceof PhpParser\Node\Scalar\String_) {
$first_var_name = '\'' . $first_arg->value->value . '\'';
} elseif ($first_arg->value instanceof PhpParser\Node\Scalar\LNumber) {
$first_var_name = (string)$first_arg->value->value;
}
if ($array_root) {
if ($first_var_name === null && isset($expr->getArgs()[0])) {
$first_arg = $expr->getArgs()[0];
if ($first_arg->value instanceof PhpParser\Node\Scalar\String_) {
$first_var_name = '\'' . $first_arg->value->value . '\'';
} elseif ($first_arg->value instanceof PhpParser\Node\Scalar\LNumber) {
$first_var_name = (string)$first_arg->value->value;
}
}
if ($expr->getArgs()[0]->value instanceof PhpParser\Node\Expr\ClassConstFetch
&& $expr->getArgs()[0]->value->name instanceof PhpParser\Node\Identifier
&& $expr->getArgs()[0]->value->name->name !== 'class'
) {
$const_type = null;
if ($source instanceof StatementsAnalyzer) {
$const_type = $source->node_data->getType($expr->getArgs()[0]->value);
}
if ($expr->getArgs()[0]->value instanceof PhpParser\Node\Expr\ClassConstFetch
&& $expr->getArgs()[0]->value->name instanceof PhpParser\Node\Identifier
&& $expr->getArgs()[0]->value->name->name !== 'class'
) {
$const_type = null;
if ($source instanceof StatementsAnalyzer) {
$const_type = $source->node_data->getType($expr->getArgs()[0]->value);
}
if ($const_type) {
if ($const_type->isSingleStringLiteral()) {
$first_var_name = $const_type->getSingleStringLiteral()->value;
} elseif ($const_type->isSingleIntLiteral()) {
$first_var_name = (string)$const_type->getSingleIntLiteral()->value;
} else {
$first_var_name = null;
}
if ($const_type) {
if ($const_type->isSingleStringLiteral()) {
$first_var_name = $const_type->getSingleStringLiteral()->value;
} elseif ($const_type->isSingleIntLiteral()) {
$first_var_name = (string)$const_type->getSingleIntLiteral()->value;
} else {
$first_var_name = null;
}
} elseif ($expr->getArgs()[0]->value instanceof PhpParser\Node\Expr\Variable
&& $source instanceof StatementsAnalyzer
&& ($first_var_type = $source->node_data->getType($expr->getArgs()[0]->value))
) {
foreach ($first_var_type->getLiteralStrings() as $array_literal_type) {
$if_types[$array_root . "['" . $array_literal_type->value . "']"] = [[new ArrayKeyExists()]];
}
foreach ($first_var_type->getLiteralInts() as $array_literal_type) {
$if_types[$array_root . "[" . $array_literal_type->value . "]"] = [[new ArrayKeyExists()]];
}
} else {
$first_var_name = null;
}
} elseif ($expr->getArgs()[0]->value instanceof PhpParser\Node\Expr\Variable
&& $source instanceof StatementsAnalyzer
&& ($first_var_type = $source->node_data->getType($expr->getArgs()[0]->value))
) {
foreach ($first_var_type->getLiteralStrings() as $array_literal_type) {
$if_types[$array_root . "['" . $array_literal_type->value . "']"] = [[new ArrayKeyExists()]];
}
foreach ($first_var_type->getLiteralInts() as $array_literal_type) {
$if_types[$array_root . "[" . $array_literal_type->value . "]"] = [[new ArrayKeyExists()]];
}
}
if ($first_var_name !== null
&& !strpos($first_var_name, '->')
&& !strpos($first_var_name, '[')
) {
$if_types[$array_root . '[' . $first_var_name . ']'] = [[new ArrayKeyExists()]];
}
if ($first_var_name !== null
&& !strpos($first_var_name, '->')
&& !strpos($first_var_name, '[')
) {
$if_types[$array_root . '[' . $first_var_name . ']'] = [[new ArrayKeyExists()]];
}
}

View File

@ -80,7 +80,7 @@ use const PHP_EOL;
/**
* @internal
*
* Contains methods that aid in the scanning of Psalm's codebase>
* Contains methods that aid in the scanning of Psalm's codebase
*/
class Scanner
{

View File

@ -378,6 +378,35 @@ class ArrayKeyExistsTest extends TestCase
return true;
}'
],
'arrayKeyExistsAssertBothWays' => [
'code' => '<?php
class a {
const STATE_A = 0;
const STATE_B = 1;
const STATE_C = 2;
/**
* @return array<self::STATE_*, non-empty-string>
* @psalm-pure
*/
public static function getStateLabels(): array {
return [
self::STATE_A => "A",
self::STATE_B => "B",
self::STATE_C => "C",
];
}
/**
* @param self::STATE_* $state
*/
public static function getStateLabelIf(int $state): string {
$states = self::getStateLabels();
if (array_key_exists($state, $states)) {
return $states[$state];
}
return "";
}
}'
],
];
}