mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Merge pull request #6997 from zoonru/list_values_paradox
This commit is contained in:
commit
28a75652ac
@ -130,28 +130,26 @@ class IfElseAnalyzer
|
||||
$if_clauses = [];
|
||||
}
|
||||
|
||||
$if_clauses = array_values(
|
||||
array_map(
|
||||
/**
|
||||
* @return Clause
|
||||
*/
|
||||
function (Clause $c) use ($mixed_var_ids, $cond_object_id): Clause {
|
||||
$keys = array_keys($c->possibilities);
|
||||
$if_clauses = array_map(
|
||||
/**
|
||||
* @return Clause
|
||||
*/
|
||||
function (Clause $c) use ($mixed_var_ids, $cond_object_id): Clause {
|
||||
$keys = array_keys($c->possibilities);
|
||||
|
||||
$mixed_var_ids = \array_diff($mixed_var_ids, $keys);
|
||||
$mixed_var_ids = \array_diff($mixed_var_ids, $keys);
|
||||
|
||||
foreach ($keys as $key) {
|
||||
foreach ($mixed_var_ids as $mixed_var_id) {
|
||||
if (preg_match('/^' . preg_quote($mixed_var_id, '/') . '(\[|-)/', $key)) {
|
||||
return new Clause([], $cond_object_id, $cond_object_id, true);
|
||||
}
|
||||
foreach ($keys as $key) {
|
||||
foreach ($mixed_var_ids as $mixed_var_id) {
|
||||
if (preg_match('/^' . preg_quote($mixed_var_id, '/') . '(\[|-)/', $key)) {
|
||||
return new Clause([], $cond_object_id, $cond_object_id, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $c;
|
||||
},
|
||||
$if_clauses
|
||||
)
|
||||
return $c;
|
||||
},
|
||||
$if_clauses
|
||||
);
|
||||
|
||||
$entry_clauses = $context->clauses;
|
||||
|
@ -364,6 +364,39 @@ class NamedFunctionCallHandler
|
||||
return;
|
||||
}
|
||||
|
||||
if ($first_arg && $function_id === 'array_values') {
|
||||
$first_arg_type = $statements_analyzer->node_data->getType($first_arg->value);
|
||||
|
||||
if ($first_arg_type
|
||||
&& UnionTypeComparator::isContainedBy(
|
||||
$codebase,
|
||||
$first_arg_type,
|
||||
Type::getList()
|
||||
)
|
||||
) {
|
||||
if ($first_arg_type->from_docblock) {
|
||||
if (IssueBuffer::accepts(
|
||||
new \Psalm\Issue\RedundantCastGivenDocblockType(
|
||||
'The call to array_values is unnecessary given the list docblock type '.$first_arg_type,
|
||||
new CodeLocation($statements_analyzer, $function_name)
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
// fall through
|
||||
}
|
||||
} else {
|
||||
if (IssueBuffer::accepts(
|
||||
new \Psalm\Issue\RedundantCast(
|
||||
'The call to array_values is unnecessary, '.$first_arg_type.' is already a list',
|
||||
new CodeLocation($statements_analyzer, $function_name)
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($first_arg && $function_id === 'strtolower') {
|
||||
$first_arg_type = $statements_analyzer->node_data->getType($first_arg->value);
|
||||
|
||||
|
@ -209,7 +209,7 @@ class MatchAnalyzer
|
||||
}
|
||||
|
||||
$all_match_condition = self::convertCondsToConditional(
|
||||
\array_values($all_conds),
|
||||
$all_conds,
|
||||
$match_condition,
|
||||
$match_condition->getAttributes()
|
||||
);
|
||||
|
@ -83,28 +83,26 @@ class TernaryAnalyzer
|
||||
}
|
||||
}
|
||||
|
||||
$if_clauses = array_values(
|
||||
array_map(
|
||||
$if_clauses = array_map(
|
||||
/**
|
||||
* @return \Psalm\Internal\Clause
|
||||
*/
|
||||
function (\Psalm\Internal\Clause $c) use ($mixed_var_ids, $cond_id): \Psalm\Internal\Clause {
|
||||
$keys = array_keys($c->possibilities);
|
||||
function (\Psalm\Internal\Clause $c) use ($mixed_var_ids, $cond_id): \Psalm\Internal\Clause {
|
||||
$keys = array_keys($c->possibilities);
|
||||
|
||||
$mixed_var_ids = \array_diff($mixed_var_ids, $keys);
|
||||
$mixed_var_ids = \array_diff($mixed_var_ids, $keys);
|
||||
|
||||
foreach ($keys as $key) {
|
||||
foreach ($mixed_var_ids as $mixed_var_id) {
|
||||
if (preg_match('/^' . preg_quote($mixed_var_id, '/') . '(\[|-)/', $key)) {
|
||||
return new \Psalm\Internal\Clause([], $cond_id, $cond_id, true);
|
||||
}
|
||||
foreach ($keys as $key) {
|
||||
foreach ($mixed_var_ids as $mixed_var_id) {
|
||||
if (preg_match('/^' . preg_quote($mixed_var_id, '/') . '(\[|-)/', $key)) {
|
||||
return new \Psalm\Internal\Clause([], $cond_id, $cond_id, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $c;
|
||||
},
|
||||
$if_clauses
|
||||
)
|
||||
return $c;
|
||||
},
|
||||
$if_clauses
|
||||
);
|
||||
|
||||
// this will see whether any of the clauses in set A conflict with the clauses in set B
|
||||
|
@ -7,6 +7,8 @@ use Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier;
|
||||
use Psalm\Internal\Analyzer\StatementsAnalyzer;
|
||||
use Psalm\Type;
|
||||
|
||||
use function count;
|
||||
|
||||
class UnsetAnalyzer
|
||||
{
|
||||
public static function analyze(
|
||||
@ -50,7 +52,11 @@ class UnsetAnalyzer
|
||||
|| $var->dim instanceof PhpParser\Node\Scalar\LNumber
|
||||
) {
|
||||
if (isset($atomic_root_type->properties[$var->dim->value])) {
|
||||
$atomic_root_type->is_list = false;
|
||||
if ($atomic_root_type->is_list
|
||||
&& $var->dim->value !== count($atomic_root_type->properties)-1
|
||||
) {
|
||||
$atomic_root_type->is_list = false;
|
||||
}
|
||||
unset($atomic_root_type->properties[$var->dim->value]);
|
||||
$root_type->bustCache(); //remove id cache
|
||||
}
|
||||
|
@ -387,7 +387,7 @@ class Pool
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($terminationMessages);
|
||||
return $terminationMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -831,6 +831,7 @@ class ArrayAssignmentTest extends TestCase
|
||||
'keyedIntOffsetArrayValues' => [
|
||||
'<?php
|
||||
$a = ["hello", 5];
|
||||
/** @psalm-suppress RedundantCast */
|
||||
$a_values = array_values($a);
|
||||
$a_keys = array_keys($a);',
|
||||
'assertions' => [
|
||||
@ -2007,6 +2008,17 @@ class ArrayAssignmentTest extends TestCase
|
||||
}',
|
||||
'error_message' => 'RedundantCast',
|
||||
],
|
||||
'arrayValuesOnList' => [
|
||||
'<?php
|
||||
/**
|
||||
* @param list<int> $a
|
||||
* @return list<int>
|
||||
*/
|
||||
function foo(array $a) : array {
|
||||
return array_values($a);
|
||||
}',
|
||||
'error_message' => 'RedundantCast',
|
||||
],
|
||||
'assignToListWithUpdatedForeachKey' => [
|
||||
'<?php
|
||||
/**
|
||||
|
@ -13,7 +13,6 @@ use Psalm\Report\JsonReport;
|
||||
use Psalm\Report\ReportOptions;
|
||||
use Psalm\Tests\Internal\Provider;
|
||||
|
||||
use function array_values;
|
||||
use function file_get_contents;
|
||||
use function json_decode;
|
||||
use function ob_end_clean;
|
||||
@ -815,7 +814,7 @@ echo $a;';
|
||||
$json_report_options = ProjectAnalyzer::getFileReportOptions([__DIR__ . '/test-report.json'])[0];
|
||||
|
||||
$this->assertSame(
|
||||
array_values($issue_data),
|
||||
$issue_data,
|
||||
json_decode(IssueBuffer::getOutput(IssueBuffer::getIssuesData(), $json_report_options), true)
|
||||
);
|
||||
}
|
||||
|
@ -2287,6 +2287,7 @@ class ClassTemplateTest extends TestCase
|
||||
* @return static<U>
|
||||
*/
|
||||
public function map(callable $callback) {
|
||||
/** @psalm-suppress RedundantCast */
|
||||
return new static(array_values(array_map($callback, $this->elements)));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user