create(ParserFactory::PREFER_PHP7); } public function testReconciliation() { $this->assertEquals('Object', \CodeInspector\TypeChecker::reconcileTypes('!null', ['Object'])); $this->assertEquals('Object', \CodeInspector\TypeChecker::reconcileTypes('!null', ['Object', 'null'])); $this->assertEquals('Object|false', \CodeInspector\TypeChecker::reconcileTypes('!null', ['Object', 'false'])); $this->assertEquals('Object', \CodeInspector\TypeChecker::reconcileTypes('!empty', ['Object'])); $this->assertEquals('Object', \CodeInspector\TypeChecker::reconcileTypes('!empty', ['Object', 'null'])); $this->assertEquals('Object', \CodeInspector\TypeChecker::reconcileTypes('!empty', ['Object', 'false'])); $this->assertEquals('null', \CodeInspector\TypeChecker::reconcileTypes('null', ['Object', 'null'])); $this->assertEquals('null', \CodeInspector\TypeChecker::reconcileTypes('null', ['Object'])); $this->assertEquals('null', \CodeInspector\TypeChecker::reconcileTypes('null', ['Object', 'false'])); $this->assertEquals('null', \CodeInspector\TypeChecker::reconcileTypes('empty', ['Object'])); $this->assertEquals('false', \CodeInspector\TypeChecker::reconcileTypes('empty', ['Object', 'false'])); $this->assertEquals('false', \CodeInspector\TypeChecker::reconcileTypes('empty', ['Object', 'bool'])); $this->assertEquals('bool', \CodeInspector\TypeChecker::reconcileTypes('!Object', ['Object', 'bool'])); $this->assertEquals('Object', \CodeInspector\TypeChecker::reconcileTypes('Object', ['Object', 'bool'])); $this->assertEquals('null', \CodeInspector\TypeChecker::reconcileTypes('!Object', ['Object', 'null'])); $this->assertEquals('ObjectA', \CodeInspector\TypeChecker::reconcileTypes('ObjectA', ['ObjectA', 'ObjectB'])); $this->assertEquals('ObjectB', \CodeInspector\TypeChecker::reconcileTypes('!ObjectA', ['ObjectA', 'ObjectB'])); $this->assertEquals('mixed', \CodeInspector\TypeChecker::reconcileTypes('!empty', ['mixed'])); $this->assertEquals('mixed', \CodeInspector\TypeChecker::reconcileTypes('!null', ['mixed'])); $this->assertEquals('mixed', \CodeInspector\TypeChecker::reconcileTypes('mixed', ['mixed'])); } /** * @expectedException CodeInspector\CodeException */ public function testNullableMethodCall() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithTernaryGuard() { $stmts = self::$_parser->parse('foo() : null; } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithTernaryIfNullGuard() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithTernaryEmptyGuard() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithTernaryIsNullGuard() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithIfGuard() { $stmts = self::$_parser->parse('foo(); } } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException CodeInspector\CodeException */ public function testNullableMethodCallWithThis() { $stmts = self::$_parser->parse('a = $a; $this->a->foo(); } }'); $file_checker = new \CodeInspector\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 \CodeInspector\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 \CodeInspector\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 \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException CodeInspector\CodeException */ public function testNullableMethodWithWrongIfGuard() { $stmts = self::$_parser->parse('foo(); } } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithExceptionThrown() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithRedefinitionAndElse() { $stmts = self::$_parser->parse('two = 3; } $one->foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException CodeInspector\CodeException */ public function testNullableMethodWithWrongBooleanIfGuard() { $stmts = self::$_parser->parse('foo(); } } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithBooleanIfGuard() { $stmts = self::$_parser->parse('foo(); } } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithNonNullBooleanIfGuard() { $stmts = self::$_parser->parse('foo(); } } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithNonNullBooleanIfGuardAndBooleanAnd() { $stmts = self::$_parser->parse('foo(); } } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodInConditionWithIfGuardBefore() { $stmts = self::$_parser->parse('a && $one->foo()) { // do something } } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException CodeInspector\CodeException */ public function testNullableMethodWithWrongIfGuardBefore() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithBooleanIfGuardBefore() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException CodeInspector\CodeException */ public function testNullableMethodWithWrongBooleanIfGuardBefore() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedRedefinition() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedRedefinitionInElse() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testMethodWithMeaninglessCheck() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException CodeInspector\CodeException */ public function testNullableMethodWithGuardedNestedIncompleteRedefinition() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedNestedRedefinition() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedSwitchRedefinition() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedNestedRedefinitionWithReturn() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedNestedRedefinitionWithElseReturn() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException CodeInspector\CodeException */ public function testNullableMethodWithGuardedNestedRedefinitionWithUselessElseReturn() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedNestedRedefinitionWithElseifReturn() { $stmts = self::$_parser->parse('foo(); } }'); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testNullableMethodWithGuardedSwitchBreak() { $stmts = self::$_parser->parse('foo(); break; } } }'); $file_checker = new \CodeInspector\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 \CodeInspector\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 \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testVariableReassignmentInIf() { $stmts = self::$_parser->parse('bar(); } '); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException CodeInspector\CodeException */ public function testVariableReassignmentInIfWithOutsideCall() { $stmts = self::$_parser->parse('bar(); } $one->bar(); '); $file_checker = new \CodeInspector\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 \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testUnnecessaryInstanceof() { $stmts = self::$_parser->parse('foo(); } '); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } /** * @expectedException CodeInspector\CodeException */ public function testUnNegatableInstanceof() { $stmts = self::$_parser->parse('foo(); } else { // do something } '); $file_checker = new \CodeInspector\FileChecker('somefile.php', $stmts); $file_checker->check(); } public function testTypeAdjustment() { $stmts = self::$_parser->parse('check(); $method_stmts = $stmts[0]->stmts[0]->stmts; $return_stmt = array_pop($method_stmts); $this->assertSame('int|string', (string) $return_stmt->inferredType); } public function testTypeMixedAdjustment() { $stmts = self::$_parser->parse('check(); $method_stmts = $stmts[0]->stmts[0]->stmts; $return_stmt = array_pop($method_stmts); $this->assertSame('mixed', (string) $return_stmt->inferredType); } public function testSwitchVariableWithContinue() { $stmts = self::$_parser->parse('check(); } public function testTryCatchVar() { $stmts = self::$_parser->parse('check(); $conditional = $stmts[2]->cond; $this->assertSame('bool', (string) $conditional->inferredType); } }