diff --git a/src/Psalm/Internal/Codebase/Analyzer.php b/src/Psalm/Internal/Codebase/Analyzer.php index 0222c49f5..e45f1b0a8 100644 --- a/src/Psalm/Internal/Codebase/Analyzer.php +++ b/src/Psalm/Internal/Codebase/Analyzer.php @@ -86,7 +86,7 @@ class Analyzer /** * Used to store counts of mixed vs non-mixed variables * - * @var array */ private $mixed_counts = []; diff --git a/src/Psalm/Internal/Type/ParseTree.php b/src/Psalm/Internal/Type/ParseTree.php index 2986fde36..e5ff42bbf 100644 --- a/src/Psalm/Internal/Type/ParseTree.php +++ b/src/Psalm/Internal/Type/ParseTree.php @@ -531,6 +531,16 @@ class ParseTree } } + if ($current_leaf !== $parse_tree + && ($parse_tree instanceof ParseTree\GenericTree + || $parse_tree instanceof ParseTree\CallableTree + || $parse_tree instanceof ParseTree\ObjectLikeTree) + ) { + throw new TypeParseTreeException( + 'Unterminated bracket' + ); + } + return $parse_tree; } diff --git a/tests/CodebaseTest.php b/tests/CodebaseTest.php index bd070e3bd..d506cde64 100644 --- a/tests/CodebaseTest.php +++ b/tests/CodebaseTest.php @@ -43,7 +43,7 @@ class CodebaseTest extends TestCase ); } - /** @return iterable */ public function typeContainments() { yield ['int', 'int|string', true]; @@ -74,7 +74,7 @@ class CodebaseTest extends TestCase ); } - /** @return iterable */ public function typeIntersections() { yield ['int', 'int|string', true]; @@ -114,11 +114,11 @@ class CodebaseTest extends TestCase ); } - /** @return iterable */ public function iterableParams() { yield ['iterable', ['int', 'string']]; - yield ['iterable', ['int|string', 'bool|float']]; } /** diff --git a/tests/TypeParseTest.php b/tests/TypeParseTest.php index 291a63296..0d8fa091a 100644 --- a/tests/TypeParseTest.php +++ b/tests/TypeParseTest.php @@ -100,11 +100,18 @@ class TypeParseTest extends TestCase /** * @return void */ - public function testArray() + public function testArrayWithClosingBracket() { $this->assertSame('array', (string) Type::parseString('array')); - $this->assertSame('array', (string) Type::parseString('array')); - $this->assertSame('array', (string) Type::parseString('array')); + } + + /** + * @return void + */ + public function testArrayWithoutClosingBracket() + { + $this->expectException(\Psalm\Exception\TypeParseTreeException::class); + Type::parseString('arrayassertSame('array{a:int, b:string}', (string) Type::parseString('array{a:int, b:string}')); } + /** + * @return void + */ + public function testObjectLikeWithoutClosingBracket() + { + $this->expectException(\Psalm\Exception\TypeParseTreeException::class); + Type::parseString('array{a:int, b:string'); + } + /** * @return void */ @@ -396,6 +412,15 @@ class TypeParseTest extends TestCase ); } + /** + * @return void + */ + public function testCallableWithoutClosingBracket() + { + $this->expectException(\Psalm\Exception\TypeParseTreeException::class); + Type::parseString('callable(int, string'); + } + /** * @return void */ diff --git a/tests/UnusedVariableTest.php b/tests/UnusedVariableTest.php index 1c4dabda4..5ddf86ffa 100644 --- a/tests/UnusedVariableTest.php +++ b/tests/UnusedVariableTest.php @@ -100,7 +100,7 @@ class UnusedVariableTest extends TestCase } /** - * @return array */ public function providerValidCodeParse() {