create(ParserFactory::PREFER_PHP7); self::$config = new TestConfig(); } /** * @return void */ public function setUp() { FileChecker::clearCache(); $this->project_checker = new \Psalm\Checker\ProjectChecker(); $this->project_checker->setConfig(self::$config); } /** * @return void */ public function testNullableReturnType() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('string|null', (string) $context->vars_in_scope['$a']); } /** * @return void */ public function testNullableReturnTypeInDocblock() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('null|string', (string) $context->vars_in_scope['$a']); } /** * @return void */ public function testNullableArgument() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testPrivateClassConst() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InaccessibleClassConstant * @return void */ public function testInvalidPrivateClassConstFetch() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InaccessibleClassConstant * @return void */ public function testInvalidPrivateClassConstFetchFromSubclass() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testProtectedClassConst() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InaccessibleClassConstant * @return void */ public function testInvalidProtectedClassConstFetch() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testPublicClassConstFetch() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testArrayDestructuring() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($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']); } /** * @return void */ public function testArrayDestructuringInForeach() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ 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(); $file_checker->visitAndAnalyzeMethods($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']); } /** * @return void */ 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(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('null|int', (string) $context->vars_in_scope['$last_id']); $this->assertEquals('null|string', (string) $context->vars_in_scope['$last_name']); } /** * @return void */ 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(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('null|int', (string) $context->vars_in_scope['$last_id']); $this->assertEquals('null|string', (string) $context->vars_in_scope['$last_name']); } /** * @return void */ 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(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InvalidArgument * @return void */ 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(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testTraversableObject() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } }