mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Allow empty offset sets on arrayaccess objects
This commit is contained in:
parent
7f8b47c5cf
commit
8f1dbc072d
@ -225,7 +225,7 @@ class ArrayAssignmentAnalyzer
|
||||
true,
|
||||
$array_var_id,
|
||||
$context,
|
||||
$child_stmts ? null : $assign_value,
|
||||
$assign_value,
|
||||
$child_stmts ? null : $assignment_type
|
||||
);
|
||||
|
||||
|
@ -792,8 +792,14 @@ class ArrayFetchAnalyzer
|
||||
$iterator_class_type = $fake_method_call->inferredType ?? null;
|
||||
$array_access_type = $iterator_class_type ?: Type::getMixed();
|
||||
} else {
|
||||
$suppressed_issues = $statements_analyzer->getSuppressedIssues();
|
||||
|
||||
if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, true)) {
|
||||
$statements_analyzer->addSuppressedIssues(['PossiblyInvalidMethodCall']);
|
||||
}
|
||||
|
||||
if ($in_assignment) {
|
||||
$fake_method_call = new PhpParser\Node\Expr\MethodCall(
|
||||
$fake_set_method_call = new PhpParser\Node\Expr\MethodCall(
|
||||
$stmt->var,
|
||||
new PhpParser\Node\Identifier('offsetSet', $stmt->var->getAttributes()),
|
||||
[
|
||||
@ -814,41 +820,43 @@ class ArrayFetchAnalyzer
|
||||
),
|
||||
]
|
||||
);
|
||||
} else {
|
||||
$fake_method_call = new PhpParser\Node\Expr\MethodCall(
|
||||
|
||||
\Psalm\Internal\Analyzer\Statements\Expression\Call\MethodCallAnalyzer::analyze(
|
||||
$statements_analyzer,
|
||||
$fake_set_method_call,
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
if ($stmt->dim) {
|
||||
$fake_get_method_call = new PhpParser\Node\Expr\MethodCall(
|
||||
$stmt->var,
|
||||
new PhpParser\Node\Identifier('offsetGet', $stmt->var->getAttributes()),
|
||||
[
|
||||
new PhpParser\Node\Arg(
|
||||
$stmt->dim
|
||||
? $stmt->dim
|
||||
: new PhpParser\Node\Expr\ConstFetch(
|
||||
new PhpParser\Node\Name('null'),
|
||||
$stmt->var->getAttributes()
|
||||
)
|
||||
)
|
||||
]
|
||||
);
|
||||
|
||||
\Psalm\Internal\Analyzer\Statements\Expression\Call\MethodCallAnalyzer::analyze(
|
||||
$statements_analyzer,
|
||||
$fake_get_method_call,
|
||||
$context
|
||||
);
|
||||
|
||||
$iterator_class_type = $fake_get_method_call->inferredType ?? null;
|
||||
} else {
|
||||
$iterator_class_type = Type::getVoid();
|
||||
}
|
||||
|
||||
$suppressed_issues = $statements_analyzer->getSuppressedIssues();
|
||||
$has_array_access = true;
|
||||
|
||||
if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, true)) {
|
||||
$statements_analyzer->addSuppressedIssues(['PossiblyInvalidMethodCall']);
|
||||
}
|
||||
|
||||
\Psalm\Internal\Analyzer\Statements\Expression\Call\MethodCallAnalyzer::analyze(
|
||||
$statements_analyzer,
|
||||
$fake_method_call,
|
||||
$context
|
||||
);
|
||||
$array_access_type = $iterator_class_type ?: Type::getMixed();
|
||||
|
||||
if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, true)) {
|
||||
$statements_analyzer->removeSuppressedIssues(['PossiblyInvalidMethodCall']);
|
||||
}
|
||||
|
||||
$iterator_class_type = $fake_method_call->inferredType ?? null;
|
||||
$array_access_type = $iterator_class_type ?: Type::getMixed();
|
||||
}
|
||||
} elseif (!$array_type->hasMixed()) {
|
||||
$non_array_types[] = (string)$type;
|
||||
|
@ -353,6 +353,90 @@ class ArrayAccessTest extends TestCase
|
||||
[],
|
||||
['MixedArrayAccess', 'MixedArgument'],
|
||||
],
|
||||
'arrayAccessOnObjectWithNullGet' => [
|
||||
'<?php
|
||||
class C implements ArrayAccess
|
||||
{
|
||||
/**
|
||||
* @var array<C|scalar>
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* @param array<scalar|array> $array
|
||||
* @psalm-suppress MixedAssignment
|
||||
* @psalm-suppress MixedTypeCoercion
|
||||
*/
|
||||
public function __construct(array $array)
|
||||
{
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$this->data[$key] = new static($value);
|
||||
} else {
|
||||
$this->data[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return C|scalar
|
||||
*/
|
||||
public function offsetGet($name)
|
||||
{
|
||||
return $this->data[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ?string $name
|
||||
* @param scalar|array $value
|
||||
* @psalm-suppress MixedTypeCoercion
|
||||
*/
|
||||
public function offsetSet($name, $value) : void
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$value = new static($value);
|
||||
}
|
||||
|
||||
if (null === $name) {
|
||||
$this->data[] = $value;
|
||||
} else {
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function __isset(string $name) : bool
|
||||
{
|
||||
return isset($this->data[$name]);
|
||||
}
|
||||
|
||||
public function __unset(string $name) : void
|
||||
{
|
||||
unset($this->data[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-suppress MixedArgument
|
||||
*/
|
||||
public function offsetExists($offset) : bool
|
||||
{
|
||||
return $this->__isset($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-suppress MixedArgument
|
||||
*/
|
||||
public function offsetUnset($offset) : void
|
||||
{
|
||||
$this->__unset($offset);
|
||||
}
|
||||
}
|
||||
|
||||
$array = new C([]);
|
||||
$array["key"] = [];
|
||||
/** @psalm-suppress PossiblyInvalidArrayAssignment */
|
||||
$array["key"][] = "testing";'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user