mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Fix #3210 - prevent possibly-null array access from destructure
This commit is contained in:
parent
132b5c9358
commit
3e0c4cfb75
@ -17,13 +17,17 @@ use Psalm\Internal\FileManipulation\FileManipulationBuffer;
|
||||
use Psalm\Issue\AssignmentToVoid;
|
||||
use Psalm\Issue\ImpureByReferenceAssignment;
|
||||
use Psalm\Issue\ImpurePropertyAssignment;
|
||||
use Psalm\Issue\InvalidArrayAccess;
|
||||
use Psalm\Issue\InvalidArrayOffset;
|
||||
use Psalm\Issue\InvalidDocblock;
|
||||
use Psalm\Issue\InvalidScope;
|
||||
use Psalm\Issue\LoopInvalidation;
|
||||
use Psalm\Issue\MissingDocblockType;
|
||||
use Psalm\Issue\MixedAssignment;
|
||||
use Psalm\Issue\MixedArrayAccess;
|
||||
use Psalm\Issue\NoValue;
|
||||
use Psalm\Issue\PossiblyInvalidArrayAccess;
|
||||
use Psalm\Issue\PossiblyNullArrayAccess;
|
||||
use Psalm\Issue\PossiblyUndefinedArrayOffset;
|
||||
use Psalm\Issue\ReferenceConstraintViolation;
|
||||
use Psalm\Issue\UnnecessaryVarAnnotation;
|
||||
@ -537,7 +541,60 @@ class AssignmentAnalyzer
|
||||
$doc_comment
|
||||
);
|
||||
|
||||
continue 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($assign_value_atomic_type instanceof Type\Atomic\TMixed) {
|
||||
if (IssueBuffer::accepts(
|
||||
new MixedArrayAccess(
|
||||
'Cannot access array value on mixed variable ' . $array_var_id,
|
||||
new CodeLocation($statements_analyzer->getSource(), $var)
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
// fall through
|
||||
}
|
||||
} elseif ($assign_value_atomic_type instanceof Type\Atomic\TNull) {
|
||||
if (IssueBuffer::accepts(
|
||||
new PossiblyNullArrayAccess(
|
||||
'Cannot access array value on null variable ' . $array_var_id,
|
||||
new CodeLocation($statements_analyzer->getSource(), $var)
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)
|
||||
) {
|
||||
// do nothing
|
||||
}
|
||||
} elseif (!$assign_value_atomic_type instanceof Type\Atomic\TArray
|
||||
&& !$assign_value_atomic_type instanceof Type\Atomic\ObjectLike
|
||||
&& !$assign_value_atomic_type instanceof Type\Atomic\TList
|
||||
) {
|
||||
if ($assign_value_type->hasArray()) {
|
||||
if (IssueBuffer::accepts(
|
||||
new PossiblyInvalidArrayAccess(
|
||||
'Cannot access array value on non-array variable '
|
||||
. $array_var_id . ' of type ' . $assign_value_atomic_type->getId(),
|
||||
new CodeLocation($statements_analyzer->getSource(), $var)
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)
|
||||
) {
|
||||
// do nothing
|
||||
}
|
||||
} else {
|
||||
if (IssueBuffer::accepts(
|
||||
new InvalidArrayAccess(
|
||||
'Cannot access array value on non-array variable '
|
||||
. $array_var_id . ' of type ' . $assign_value_atomic_type->getId(),
|
||||
new CodeLocation($statements_analyzer->getSource(), $var)
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)
|
||||
) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($var instanceof PhpParser\Node\Expr\List_
|
||||
@ -564,6 +621,8 @@ class AssignmentAnalyzer
|
||||
$context,
|
||||
$doc_comment
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($list_var_id) {
|
||||
|
@ -896,6 +896,7 @@ class ArrayAccessTest extends TestCase
|
||||
|
||||
$popped = array_pop($this->a);
|
||||
|
||||
/** @psalm-suppress MixedArrayAccess */
|
||||
[$this->b, $this->c] = $popped;
|
||||
}
|
||||
}'
|
||||
@ -1224,6 +1225,18 @@ class ArrayAccessTest extends TestCase
|
||||
}',
|
||||
'error_message' => 'InvalidArrayOffset'
|
||||
],
|
||||
'destructureNullable' => [
|
||||
'<?php
|
||||
/**
|
||||
* @return null|array
|
||||
*/
|
||||
function maybeReturnArray(): ?array {
|
||||
return rand(0, 1) ? null : ["key" => 1];
|
||||
}
|
||||
|
||||
["key" => $a] = maybeReturnArray();',
|
||||
'error_message' => 'PossiblyNullArrayAccess',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user