mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Detect duplicate keys in array shapes
This commit is contained in:
parent
e784128902
commit
247d30f74c
@ -1478,6 +1478,10 @@ class TypeParser
|
||||
$had_optional = true;
|
||||
}
|
||||
|
||||
if (isset($properties[$property_key])) {
|
||||
throw new TypeParseTreeException("Duplicate key $property_key detected");
|
||||
}
|
||||
|
||||
$properties[$property_key] = $property_type;
|
||||
if ($class_string) {
|
||||
$class_strings[$property_key] = true;
|
||||
@ -1485,7 +1489,7 @@ class TypeParser
|
||||
}
|
||||
|
||||
if ($had_explicit && $had_implicit) {
|
||||
throw new TypeParseTreeException('Cannot mix explicit and implicit keys!');
|
||||
throw new TypeParseTreeException('Cannot mix explicit and implicit keys');
|
||||
}
|
||||
|
||||
if ($type === 'object') {
|
||||
@ -1500,7 +1504,7 @@ class TypeParser
|
||||
}
|
||||
|
||||
if ($callable && !$properties) {
|
||||
throw new TypeParseTreeException('A callable array cannot be empty!');
|
||||
throw new TypeParseTreeException('A callable array cannot be empty');
|
||||
}
|
||||
|
||||
if ($type !== 'array' && $type !== 'list') {
|
||||
@ -1508,7 +1512,7 @@ class TypeParser
|
||||
}
|
||||
|
||||
if ($type === 'list' && !$is_list) {
|
||||
throw new TypeParseTreeException('A list shape cannot describe a non-list!');
|
||||
throw new TypeParseTreeException('A list shape cannot describe a non-list');
|
||||
}
|
||||
|
||||
if (!$properties) {
|
||||
@ -1520,7 +1524,7 @@ class TypeParser
|
||||
$class_strings,
|
||||
$sealed
|
||||
? null
|
||||
: [$is_list ? Type::getInt() : Type::getArrayKey(), Type::getMixed()],
|
||||
: [$is_list ? Type::getListKey() : Type::getArrayKey(), Type::getMixed()],
|
||||
$is_list,
|
||||
$from_docblock,
|
||||
);
|
||||
|
@ -473,54 +473,60 @@ class TypeParseTest extends TestCase
|
||||
|
||||
public function testTKeyedListNonList(): void
|
||||
{
|
||||
$this->expectExceptionMessage('A list shape cannot describe a non-list!');
|
||||
$this->expectExceptionMessage('A list shape cannot describe a non-list');
|
||||
Type::parseString('list{a: 0, b: 1, c: 2}');
|
||||
}
|
||||
|
||||
|
||||
public function testTKeyedListNonListOptional(): void
|
||||
{
|
||||
$this->expectExceptionMessage('A list shape cannot describe a non-list!');
|
||||
$this->expectExceptionMessage('A list shape cannot describe a non-list');
|
||||
Type::parseString('list{a: 0, b?: 1, c?: 2}');
|
||||
}
|
||||
|
||||
public function testTKeyedListNonListOptionalWrongOrder1(): void
|
||||
{
|
||||
$this->expectExceptionMessage('A list shape cannot describe a non-list!');
|
||||
$this->expectExceptionMessage('A list shape cannot describe a non-list');
|
||||
Type::parseString('list{0?: 0, 1: 1, 2: 2}');
|
||||
}
|
||||
|
||||
public function testTKeyedListNonListOptionalWrongOrder2(): void
|
||||
{
|
||||
$this->expectExceptionMessage('A list shape cannot describe a non-list!');
|
||||
$this->expectExceptionMessage('A list shape cannot describe a non-list');
|
||||
Type::parseString('list{0: 0, 1?: 1, 2: 2}');
|
||||
}
|
||||
|
||||
|
||||
public function testTKeyedListWrongOrder(): void
|
||||
{
|
||||
$this->expectExceptionMessage('A list shape cannot describe a non-list!');
|
||||
$this->expectExceptionMessage('A list shape cannot describe a non-list');
|
||||
Type::parseString('list{1: 1, 0: 0}');
|
||||
}
|
||||
|
||||
public function testTKeyedListNonListKeys(): void
|
||||
{
|
||||
$this->expectExceptionMessage('A list shape cannot describe a non-list!');
|
||||
$this->expectExceptionMessage('A list shape cannot describe a non-list');
|
||||
Type::parseString('list{1: 1, 2: 2}');
|
||||
}
|
||||
|
||||
public function testTKeyedListNoExplicitAndImplicitKeys(): void
|
||||
{
|
||||
$this->expectExceptionMessage('Cannot mix explicit and implicit keys!');
|
||||
$this->expectExceptionMessage('Cannot mix explicit and implicit keys');
|
||||
Type::parseString('list{0: 0, 1}');
|
||||
}
|
||||
|
||||
public function testTKeyedArrayNoExplicitAndImplicitKeys(): void
|
||||
{
|
||||
$this->expectExceptionMessage('Cannot mix explicit and implicit keys!');
|
||||
$this->expectExceptionMessage('Cannot mix explicit and implicit keys');
|
||||
Type::parseString('array{0, test: 1}');
|
||||
}
|
||||
|
||||
public function testTKeyedArrayNoDuplicateKeys(): void
|
||||
{
|
||||
$this->expectExceptionMessage('Duplicate key a detected');
|
||||
Type::parseString('array{a: int, a: int}');
|
||||
}
|
||||
|
||||
public function testSimpleCallable(): void
|
||||
{
|
||||
$this->assertSame(
|
||||
|
Loading…
Reference in New Issue
Block a user