mirror of
https://github.com/danog/psalm.git
synced 2024-12-02 09:37:59 +01:00
Fix a false flag issue with InvalidConstantAssignmentValue being thrown for constants over a certain length. Usually happens with arrays or lists over 100+ entries in length.
Check if this type was defined via a dockblock or type hint otherwise the inferred type should always match the assigned type, and we don't even need to do additional checks There is an issue with constants over a certain length where additional values are added to fallback_params in the assigned_type but not in const_storage_type which causes a false flag for this error to appear. Usually happens with arrays/lists. Added two separate tests to cover both lists, and arrays to ensure this issue is fixed.
This commit is contained in:
parent
2b642804b7
commit
f553392454
@ -721,19 +721,27 @@ final class ClassConstAnalyzer
|
|||||||
|
|
||||||
// Check assigned type matches docblock type
|
// Check assigned type matches docblock type
|
||||||
if ($assigned_type = $statements_analyzer->node_data->getType($const->value)) {
|
if ($assigned_type = $statements_analyzer->node_data->getType($const->value)) {
|
||||||
if ($const_storage->type !== null
|
$const_storage_type = $const_storage->type;
|
||||||
|
|
||||||
|
if ($const_storage_type !== null
|
||||||
&& $const_storage->stmt_location !== null
|
&& $const_storage->stmt_location !== null
|
||||||
&& $assigned_type !== $const_storage->type
|
&& $assigned_type !== $const_storage_type
|
||||||
|
// Check if this type was defined via a dockblock or type hint otherwise the inferred type
|
||||||
|
// should always match the assigned type and we don't even need to do additional checks
|
||||||
|
// There is an issue with constants over a certain length where additional values
|
||||||
|
// are added to fallback_params in the assigned_type but not in const_storage_type
|
||||||
|
// which causes a false flag for this error to appear. Usually happens with arrays
|
||||||
|
&& ($const_storage_type->from_docblock || $const_storage_type->from_property)
|
||||||
&& !UnionTypeComparator::isContainedBy(
|
&& !UnionTypeComparator::isContainedBy(
|
||||||
$statements_analyzer->getCodebase(),
|
$statements_analyzer->getCodebase(),
|
||||||
$assigned_type,
|
$assigned_type,
|
||||||
$const_storage->type,
|
$const_storage_type,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
IssueBuffer::maybeAdd(
|
IssueBuffer::maybeAdd(
|
||||||
new InvalidConstantAssignmentValue(
|
new InvalidConstantAssignmentValue(
|
||||||
"{$class_storage->name}::{$const->name->name} with declared type "
|
"{$class_storage->name}::{$const->name->name} with declared type "
|
||||||
. "{$const_storage->type->getId()} cannot be assigned type {$assigned_type->getId()}",
|
. "{$const_storage_type->getId()} cannot be assigned type {$assigned_type->getId()}",
|
||||||
$const_storage->stmt_location,
|
$const_storage->stmt_location,
|
||||||
"{$class_storage->name}::{$const->name->name}",
|
"{$class_storage->name}::{$const->name->name}",
|
||||||
),
|
),
|
||||||
|
@ -824,6 +824,242 @@ class ConstantTest extends TestCase
|
|||||||
A::foo(2);
|
A::foo(2);
|
||||||
A::foo(3);',
|
A::foo(3);',
|
||||||
],
|
],
|
||||||
|
'tooLongArrayInvalidConstantAssignmentValueFalsePositiveWithArray' => [
|
||||||
|
'code' => '<?php
|
||||||
|
class TestInvalidConstantAssignmentValueFalsePositiveWithArray {
|
||||||
|
const LOOKUP = [
|
||||||
|
"00" => null,
|
||||||
|
"01" => null,
|
||||||
|
"02" => null,
|
||||||
|
"03" => null,
|
||||||
|
"04" => null,
|
||||||
|
"05" => null,
|
||||||
|
"06" => null,
|
||||||
|
"07" => null,
|
||||||
|
"08" => null,
|
||||||
|
"09" => null,
|
||||||
|
"10" => null,
|
||||||
|
"11" => null,
|
||||||
|
"12" => null,
|
||||||
|
"13" => null,
|
||||||
|
"14" => null,
|
||||||
|
"15" => null,
|
||||||
|
"16" => null,
|
||||||
|
"17" => null,
|
||||||
|
"18" => null,
|
||||||
|
"19" => null,
|
||||||
|
"20" => null,
|
||||||
|
"21" => null,
|
||||||
|
"22" => null,
|
||||||
|
"23" => null,
|
||||||
|
"24" => null,
|
||||||
|
"25" => null,
|
||||||
|
"26" => null,
|
||||||
|
"27" => null,
|
||||||
|
"28" => null,
|
||||||
|
"29" => null,
|
||||||
|
"30" => null,
|
||||||
|
"31" => null,
|
||||||
|
"32" => null,
|
||||||
|
"33" => null,
|
||||||
|
"34" => null,
|
||||||
|
"35" => null,
|
||||||
|
"36" => null,
|
||||||
|
"37" => null,
|
||||||
|
"38" => null,
|
||||||
|
"39" => null,
|
||||||
|
"40" => null,
|
||||||
|
"41" => null,
|
||||||
|
"42" => null,
|
||||||
|
"43" => null,
|
||||||
|
"44" => null,
|
||||||
|
"45" => null,
|
||||||
|
"46" => null,
|
||||||
|
"47" => null,
|
||||||
|
"48" => null,
|
||||||
|
"49" => null,
|
||||||
|
"50" => null,
|
||||||
|
"51" => null,
|
||||||
|
"52" => null,
|
||||||
|
"53" => null,
|
||||||
|
"54" => null,
|
||||||
|
"55" => null,
|
||||||
|
"56" => null,
|
||||||
|
"57" => null,
|
||||||
|
"58" => null,
|
||||||
|
"59" => null,
|
||||||
|
"60" => null,
|
||||||
|
"61" => null,
|
||||||
|
"62" => null,
|
||||||
|
"63" => null,
|
||||||
|
"64" => null,
|
||||||
|
"65" => null,
|
||||||
|
"66" => null,
|
||||||
|
"67" => null,
|
||||||
|
"68" => null,
|
||||||
|
"69" => null,
|
||||||
|
"70" => self::SUCCEED,
|
||||||
|
"71" => self::FAIL,
|
||||||
|
"72" => null,
|
||||||
|
"73" => null,
|
||||||
|
"74" => null,
|
||||||
|
"75" => null,
|
||||||
|
"76" => null,
|
||||||
|
"77" => null,
|
||||||
|
"78" => null,
|
||||||
|
"79" => null,
|
||||||
|
"80" => null,
|
||||||
|
"81" => null,
|
||||||
|
"82" => null,
|
||||||
|
"83" => null,
|
||||||
|
"84" => null,
|
||||||
|
"85" => null,
|
||||||
|
"86" => null,
|
||||||
|
"87" => null,
|
||||||
|
"88" => null,
|
||||||
|
"89" => null,
|
||||||
|
"90" => null,
|
||||||
|
"91" => null,
|
||||||
|
"92" => null,
|
||||||
|
"93" => null,
|
||||||
|
"94" => null,
|
||||||
|
"95" => null,
|
||||||
|
"96" => null,
|
||||||
|
"97" => null,
|
||||||
|
"98" => null,
|
||||||
|
"99" => null,
|
||||||
|
"100" => null,
|
||||||
|
"101" => null,
|
||||||
|
];
|
||||||
|
|
||||||
|
const SUCCEED = "SUCCEED";
|
||||||
|
const FAIL = "FAIL";
|
||||||
|
|
||||||
|
public static function will_succeed(string $code) : bool {
|
||||||
|
// Seems to fail when the array has over 100+ entries, and at least one value references
|
||||||
|
// another constant from the same class (even nested)
|
||||||
|
return (self::LOOKUP[$code] ?? null) === self::SUCCEED;
|
||||||
|
}
|
||||||
|
}',
|
||||||
|
],
|
||||||
|
'tooLongArrayInvalidConstantAssignmentValueFalsePositiveWithList' => [
|
||||||
|
'code' => '<?php
|
||||||
|
class TestInvalidConstantAssignmentValueFalsePositiveWithList {
|
||||||
|
const LOOKUP = [
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
self::SUCCEED,
|
||||||
|
self::FAIL,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
];
|
||||||
|
|
||||||
|
const SUCCEED = "SUCCEED";
|
||||||
|
const FAIL = "FAIL";
|
||||||
|
|
||||||
|
public static function will_succeed(int $code) : bool {
|
||||||
|
// Seems to fail when the array has over 100+ entries, and at least one value references
|
||||||
|
// another constant from the same class (even nested)
|
||||||
|
return (self::LOOKUP[$code] ?? null) === self::SUCCEED;
|
||||||
|
}
|
||||||
|
}',
|
||||||
|
],
|
||||||
'valueOf' => [
|
'valueOf' => [
|
||||||
'code' => '<?php
|
'code' => '<?php
|
||||||
class A {
|
class A {
|
||||||
|
Loading…
Reference in New Issue
Block a user