create(ParserFactory::PREFER_PHP7); } public function setUp() { $config = new TestConfig(); $config->use_docblock_types = true; FileChecker::clearCache(); $this->project_checker = new \Psalm\Checker\ProjectChecker(); } public function testNullableReturnType() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); $this->assertEquals('string|null', (string) $context->vars_in_scope['$a']); } public function testNullableArgument() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); } public function testPrivateClassConst() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InaccessibleClassConstant */ public function testInvalidPrivateClassConstFetch() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InaccessibleClassConstant */ public function testInvalidPrivateClassConstFetchFromSubclass() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); } public function testProtectedClassConst() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InaccessibleClassConstant */ public function testInvalidProtectedClassConstFetch() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); } public function testPublicClassConstFetch() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); } public function testArrayDestructuring() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); $this->assertEquals('string|int', (string) $context->vars_in_scope['$id1']); $this->assertEquals('string|int', (string) $context->vars_in_scope['$name1']); $this->assertEquals('string|int', (string) $context->vars_in_scope['$id2']); $this->assertEquals('string|int', (string) $context->vars_in_scope['$name2']); } public function testArrayDestructuringInForeach() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); } public function testArrayDestructuringWithKeys() { $stmts = self::$parser->parse(' 1, "name" => "Tom"], ["id" => 2, "name" => "Fred"], ]; // list() style list("id" => $id1, "name" => $name1) = $data[0]; // [] style ["id" => $id2, "name" => $name2] = $data[1]; '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); $this->assertEquals('int', (string) $context->vars_in_scope['$id1']); $this->assertEquals('string', (string) $context->vars_in_scope['$name1']); $this->assertEquals('int', (string) $context->vars_in_scope['$id2']); $this->assertEquals('string', (string) $context->vars_in_scope['$name2']); } public function testArrayListDestructuringInForeachWithKeys() { $stmts = self::$parser->parse(' 1, "name" => "Tom"], ["id" => 2, "name" => "Fred"], ]; $last_id = null; $last_name = null; // list() style foreach ($data as list("id" => $id, "name" => $name)) { $last_id = $id; $last_name = $name; } '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); $this->assertEquals('null|int', (string) $context->vars_in_scope['$last_id']); $this->assertEquals('null|string', (string) $context->vars_in_scope['$last_name']); } public function testArrayDestructuringInForeachWithKeys() { $stmts = self::$parser->parse(' 1, "name" => "Tom"], ["id" => 2, "name" => "Fred"], ]; $last_id = null; $last_name = null; // [] style foreach ($data as ["id" => $id, "name" => $name]) { $last_id = $id; $last_name = $name; } '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); $this->assertEquals('null|int', (string) $context->vars_in_scope['$last_id']); $this->assertEquals('null|string', (string) $context->vars_in_scope['$last_name']); } public function testIterableArg() { $stmts = self::$parser->parse(' $iter */ function iterator(iterable $iter) : void { foreach ($iter as $val) { // } } iterator([1, 2, 3, 4]); iterator(new SplFixedArray(5)); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InvalidArgument */ public function testInvalidIterableArg() { $stmts = self::$parser->parse(' $iter */ function iterator(iterable $iter) : void { foreach ($iter as $val) { // } } class A { } iterator(new A()); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context('somefile.php'); $file_checker->visitAndCheckMethods($context); } }