1
0
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:
Bruce Weirdan 2021-11-29 00:47:12 +02:00 committed by GitHub
commit 28a75652ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 83 additions and 36 deletions

View File

@ -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;

View File

@ -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);

View File

@ -209,7 +209,7 @@ class MatchAnalyzer
}
$all_match_condition = self::convertCondsToConditional(
\array_values($all_conds),
$all_conds,
$match_condition,
$match_condition->getAttributes()
);

View File

@ -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

View File

@ -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
}

View File

@ -387,7 +387,7 @@ class Pool
}
}
return array_values($terminationMessages);
return $terminationMessages;
}
/**

View File

@ -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
/**

View File

@ -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)
);
}

View File

@ -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)));
}
}