create(ParserFactory::PREFER_PHP7); } /** * @return void */ public function setUp() { FileChecker::clearCache(); $this->project_checker = new \Psalm\Checker\ProjectChecker(); $this->project_checker->setConfig(new TestConfig()); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InvalidScalarArgument * @return void */ public function testInvalidScalarArgument() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage MixedArgument * @return void */ public function testMixedArgument() { Config::getInstance()->setCustomErrorLevel('MixedAssignment', Config::REPORT_SUPPRESS); $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage NullArgument * @return void */ public function testNullArgument() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage TooFewArguments * @return void */ public function testTooFewArguments() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage TooManyArguments * @return void */ public function testTooManyArguments() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage TypeCoercion * @return void */ public function testTypeCoercion() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage TypeCoercion * @return void */ public function testArrayTypeCoercion() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testTypedArrayWithDefault() { $stmts = self::$parser->parse(' $a */ function fooFoo(array $a = []) : void { } '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage DuplicateParam * @return void */ public function testDuplicateParam() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InvalidParamDefault * @return void */ public function testInvalidParamDefault() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InvalidParamDefault * @return void */ public function testInvalidDocblockParamDefault() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testValidDocblockParamDefault() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testByRef() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InvalidPassByReference * @return void */ public function testBadByRef() { $this->markTestSkipped('Does not throw an error'); $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testNamespaced() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testNamespacedRootFunctionCall() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testNamespacedAliasedFunctionCall() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testArrayKeys() { $stmts = self::$parser->parse(' 1, "b" => 2]); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('array', (string) $context->vars_in_scope['$a']); } /** * @return void */ public function testArrayKeysMixed() { Config::getInstance()->setCustomErrorLevel('MixedArgument', Config::REPORT_SUPPRESS); $stmts = self::$parser->parse(' 5]; $a = array_keys($b); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('array', (string) $context->vars_in_scope['$a']); } /** * @return void */ public function testArrayValues() { $stmts = self::$parser->parse(' 1, "b" => 2]); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('array', (string) $context->vars_in_scope['$b']); } /** * @return void */ public function testArrayCombine() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('array', (string) $context->vars_in_scope['$c']); } /** * @return void */ public function testArrayMerge() { $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('array', (string) $context->vars_in_scope['$d']); } /** * @return void */ public function testArrayDiff() { $stmts = self::$parser->parse(' 5, "b" => 12], [5]); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('array', (string) $context->vars_in_scope['$d']); } /** * @return void */ public function testArrayFilter() { $stmts = self::$parser->parse(' 5, "b" => 12, "c" => null]); $e = array_filter(["a" => 5, "b" => 12, "c" => null], function(?int $i) : bool { return true; }); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('array', (string) $context->vars_in_scope['$d']); $this->assertEquals('array', (string) $context->vars_in_scope['$e']); if (version_compare((string)phpversion(), '5.6.0', '>=')) { $stmts = self::$parser->parse(' 5, "b" => 12, "c" => null], function(?int $val, string $key) : bool { return true; }, ARRAY_FILTER_USE_BOTH); $g = array_filter(["a" => 5, "b" => 12, "c" => null], function(string $val) : bool { return true; }, ARRAY_FILTER_USE_KEY); $bar = "bar"; $foo = [ $bar => function () : string { return "baz"; }, ]; $foo = array_filter( $foo, function (string $key) : bool { return $key === "bar"; }, ARRAY_FILTER_USE_KEY ); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('array', (string) $context->vars_in_scope['$f']); $this->assertEquals('array', (string) $context->vars_in_scope['$g']); } } /** * @return void */ public function testArrayFilterUseKey() { if (version_compare((string)phpversion(), '5.6.0', '>=')) { $stmts = self::$parser->parse(' function () : string { return "baz"; }, ]; $foo = array_filter( $foo, function (string $key) : bool { return $key === "bar"; }, ARRAY_FILTER_USE_KEY ); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } } /** * @return void */ public function testByRefAfterCallable() { Config::getInstance()->setCustomErrorLevel('MixedAssignment', Config::REPORT_SUPPRESS); Config::getInstance()->setCustomErrorLevel('MixedArrayAccess', Config::REPORT_SUPPRESS); $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InvalidScalarArgument * @return void */ public function testInvalidArgAfterCallable() { Config::getInstance()->setCustomErrorLevel('MixedAssignment', Config::REPORT_SUPPRESS); Config::getInstance()->setCustomErrorLevel('MixedArrayAccess', Config::REPORT_SUPPRESS); $stmts = self::$parser->parse('project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } /** * @return void */ public function testExtractVarCheck() { Config::getInstance()->setCustomErrorLevel('MixedAssignment', Config::REPORT_SUPPRESS); Config::getInstance()->setCustomErrorLevel('MixedArrayAccess', Config::REPORT_SUPPRESS); $stmts = self::$parser->parse(' "bar"]; extract($a); takesString($foo); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } }