create(ParserFactory::PREFER_PHP7); $config = Config::getInstance(); $config->throw_exception = true; } public function setUp() { FileChecker::clearCache(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testNullableMethodCall() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithTernaryGuard() { $stmts = self::$parser->parse('foo() : null; } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithTernaryIfNullGuard() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithTernaryEmptyGuard() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithTernaryIsNullGuard() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithIfGuard() { $stmts = self::$parser->parse('foo(); } } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testNullableMethodCallWithThis() { $stmts = self::$parser->parse('a = $a; $this->a->foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithTernaryGuardWithThis() { $stmts = self::$parser->parse('a = $a; $b = $this->a ? $this->a->foo() : null; } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithTernaryIfNullGuardWithThis() { $stmts = self::$parser->parse('a = $a; $b = $this->a === null ? null : $this->a->foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithIfGuardWithThis() { $stmts = self::$parser->parse('a = $a; if ($this->a) { $this->a->foo(); } } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testNullableMethodWithWrongIfGuard() { $stmts = self::$parser->parse('foo(); } } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithExceptionThrown() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithRedefinitionAndElse() { $stmts = self::$parser->parse('two = 3; } $one->foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testNullableMethodWithWrongBooleanIfGuard() { $stmts = self::$parser->parse('foo(); } } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithBooleanIfGuard() { $stmts = self::$parser->parse('foo(); } } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithNonNullBooleanIfGuard() { $stmts = self::$parser->parse('foo(); } } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithNonNullBooleanIfGuardAndBooleanAnd() { $stmts = self::$parser->parse('foo(); } } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodInConditionWithIfGuardBefore() { $stmts = self::$parser->parse('a && $one->foo()) { // do something } } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testNullableMethodWithWrongIfGuardBefore() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithBooleanIfGuardBefore() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testNullableMethodWithWrongBooleanIfGuardBefore() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedRedefinition() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedRedefinitionInElse() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testMethodWithMeaninglessCheck() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testNullableMethodWithGuardedNestedIncompleteRedefinition() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedNestedRedefinition() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedSwitchRedefinition() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testNullableMethodWithGuardedSwitchRedefinitionNoDefault() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testNullableMethodWithGuardedSwitchRedefinitionEmptyDefault() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedSwitchRedefinitionDueToException() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedSwitchThatAlwaysReturns() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedNestedRedefinitionWithReturn() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedNestedRedefinitionWithElseReturn() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testNullableMethodWithGuardedNestedRedefinitionWithUselessElseReturn() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedNestedRedefinitionWithElseifReturn() { $stmts = self::$parser->parse('foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedSwitchBreak() { $stmts = self::$parser->parse('foo(); break; } } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedRedefinitionOnThis() { $stmts = self::$parser->parse('one = $one; if ($this->one === null) { $this->one = new One(); } $this->one->foo(); } }'); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testArrayUnionTypeAssertion() { $stmts = self::$parser->parse('check(); } public function testArrayUnionTypeAssertionWithIsArray() { $stmts = self::$parser->parse('check(); } public function testVariableReassignment() { $stmts = self::$parser->parse('bar(); '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testVariableReassignmentInIf() { $stmts = self::$parser->parse('bar(); } '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testVariableReassignmentInIfWithOutsideCall() { $stmts = self::$parser->parse('bar(); } $one->bar(); '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testUnionTypeFlow() { $stmts = self::$parser->parse('foo(); } else { if ($var instanceof Two) { $var->bar(); } else if ($var) { $var->baz(); } } '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testUnionTypeFlowWithThrow() { $stmts = self::$parser->parse('foo(); } } '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testUnionTypeFlowWithElseif() { $stmts = self::$parser->parse('foo(); } '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testUnnecessaryInstanceof() { $stmts = self::$parser->parse('foo(); } '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testUnNegatableInstanceof() { $stmts = self::$parser->parse('foo(); } else { // do something } '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testTypeAdjustment() { $stmts = self::$parser->parse('check(true, true, $context); $this->assertEquals('int|string', (string) $context->vars_in_scope['$var']); } public function testTypeMixedAdjustment() { $stmts = self::$parser->parse('check(true, true, $context); $this->assertEquals('int|string', (string) $context->vars_in_scope['$var']); } public function testTypeAdjustmentIfNull() { $stmts = self::$parser->parse(' 5 ? new A : null; if ($var === null) { $var = new B; } '); $file_checker = new FileChecker('somefile.php', $stmts); $context = new Context('somefile.php'); $file_checker->check(true, true, $context); $this->assertEquals('A|B', (string) $context->vars_in_scope['$var']); } public function testWhileTrue() { $stmts = self::$parser->parse('foo()) { $row[0] = "bad"; } } } '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testWrongParam() { $stmts = self::$parser->parse('bar(5); '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testPassingParam() { $stmts = self::$parser->parse('bar(new A); '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullToNullableParam() { $stmts = self::$parser->parse('bar(null); '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testIntToNullableObjectParam() { $stmts = self::$parser->parse('bar(5); '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testObjectToNullableObjectParam() { $stmts = self::$parser->parse('bar(new A); '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException \Psalm\Exception\CodeException */ public function testParamCoercionWithBadArg() { $stmts = self::$parser->parse('bar(); } } } '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testParamCoercion() { $stmts = self::$parser->parse('bar(); } } } '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testParamElseifCoercion() { $stmts = self::$parser->parse('bar(); } elseif ($a instanceof C) { $a->baz(); } } } '); $file_checker = new FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testAssignInsideForeach() { $stmts = self::$parser->parse('check(true, true, $context); $this->assertSame('bool', (string) $context->vars_in_scope['$b']); } public function testAssignInsideForeachWithBreak() { $stmts = self::$parser->parse('check(true, true, $context); $this->assertSame('bool', (string) $context->vars_in_scope['$b']); } /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage NullReference */ public function testNullCheckInsideForeachWithNoLeaveStatement() { $stmts = self::$parser->parse(' */ public static function loadMultiple() { return [new A, null]; } /** @return void */ public function bar() { } } foreach (A::loadMultiple() as $a) { if ($a === null) { // do nothing } $a->bar(); } '); $file_checker = new FileChecker('somefile.php', $stmts); $context = new Context('somefile.php'); $file_checker->check(); } public function testNullCheckInsideForeachWithContinue() { $stmts = self::$parser->parse(' */ public static function loadMultiple() { return [new A, null]; } /** @return void */ public function bar() { } } foreach (A::loadMultiple() as $a) { if ($a === null) { continue; } $a->bar(); } '); $file_checker = new FileChecker('somefile.php', $stmts); $context = new Context('somefile.php'); $file_checker->check(); } }