mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +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\AssignmentToVoid;
|
||||||
use Psalm\Issue\ImpureByReferenceAssignment;
|
use Psalm\Issue\ImpureByReferenceAssignment;
|
||||||
use Psalm\Issue\ImpurePropertyAssignment;
|
use Psalm\Issue\ImpurePropertyAssignment;
|
||||||
|
use Psalm\Issue\InvalidArrayAccess;
|
||||||
use Psalm\Issue\InvalidArrayOffset;
|
use Psalm\Issue\InvalidArrayOffset;
|
||||||
use Psalm\Issue\InvalidDocblock;
|
use Psalm\Issue\InvalidDocblock;
|
||||||
use Psalm\Issue\InvalidScope;
|
use Psalm\Issue\InvalidScope;
|
||||||
use Psalm\Issue\LoopInvalidation;
|
use Psalm\Issue\LoopInvalidation;
|
||||||
use Psalm\Issue\MissingDocblockType;
|
use Psalm\Issue\MissingDocblockType;
|
||||||
use Psalm\Issue\MixedAssignment;
|
use Psalm\Issue\MixedAssignment;
|
||||||
|
use Psalm\Issue\MixedArrayAccess;
|
||||||
use Psalm\Issue\NoValue;
|
use Psalm\Issue\NoValue;
|
||||||
|
use Psalm\Issue\PossiblyInvalidArrayAccess;
|
||||||
|
use Psalm\Issue\PossiblyNullArrayAccess;
|
||||||
use Psalm\Issue\PossiblyUndefinedArrayOffset;
|
use Psalm\Issue\PossiblyUndefinedArrayOffset;
|
||||||
use Psalm\Issue\ReferenceConstraintViolation;
|
use Psalm\Issue\ReferenceConstraintViolation;
|
||||||
use Psalm\Issue\UnnecessaryVarAnnotation;
|
use Psalm\Issue\UnnecessaryVarAnnotation;
|
||||||
@ -537,7 +541,60 @@ class AssignmentAnalyzer
|
|||||||
$doc_comment
|
$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_
|
if ($var instanceof PhpParser\Node\Expr\List_
|
||||||
@ -564,6 +621,8 @@ class AssignmentAnalyzer
|
|||||||
$context,
|
$context,
|
||||||
$doc_comment
|
$doc_comment
|
||||||
);
|
);
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($list_var_id) {
|
if ($list_var_id) {
|
||||||
|
@ -896,6 +896,7 @@ class ArrayAccessTest extends TestCase
|
|||||||
|
|
||||||
$popped = array_pop($this->a);
|
$popped = array_pop($this->a);
|
||||||
|
|
||||||
|
/** @psalm-suppress MixedArrayAccess */
|
||||||
[$this->b, $this->c] = $popped;
|
[$this->b, $this->c] = $popped;
|
||||||
}
|
}
|
||||||
}'
|
}'
|
||||||
@ -1224,6 +1225,18 @@ class ArrayAccessTest extends TestCase
|
|||||||
}',
|
}',
|
||||||
'error_message' => 'InvalidArrayOffset'
|
'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