diff --git a/src/Psalm/Checker/Statements/Expression/CallChecker.php b/src/Psalm/Checker/Statements/Expression/CallChecker.php index f3894d144..826821776 100644 --- a/src/Psalm/Checker/Statements/Expression/CallChecker.php +++ b/src/Psalm/Checker/Statements/Expression/CallChecker.php @@ -162,6 +162,10 @@ class CallChecker (!$var_type_part instanceof TNamedObject || $var_type_part->value !== 'Closure') && !$var_type_part instanceof TCallable && (!$var_type_part instanceof TNamedObject || + !ClassLikeChecker::classOrInterfaceExists( + $var_type_part->value, + $statements_checker->getFileChecker() + ) || !MethodChecker::methodExists( $var_type_part->value . '::__invoke', $statements_checker->getFileChecker() diff --git a/tests/ClosureTest.php b/tests/ClosureTest.php index 3d1d98392..b595c0b70 100644 --- a/tests/ClosureTest.php +++ b/tests/ClosureTest.php @@ -12,9 +12,6 @@ class ClosureTest extends PHPUnit_Framework_TestCase /** @var \PhpParser\Parser */ protected static $parser; - /** @var TestConfig */ - protected static $config; - /** @var \Psalm\Checker\ProjectChecker */ protected $project_checker; @@ -24,7 +21,6 @@ class ClosureTest extends PHPUnit_Framework_TestCase public static function setUpBeforeClass() { self::$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); - self::$config = new TestConfig(); } /** @@ -34,7 +30,7 @@ class ClosureTest extends PHPUnit_Framework_TestCase { FileChecker::clearCache(); $this->project_checker = new \Psalm\Checker\ProjectChecker(); - $this->project_checker->setConfig(self::$config); + $this->project_checker->setConfig(new TestConfig()); } /** @@ -227,6 +223,36 @@ class ClosureTest extends PHPUnit_Framework_TestCase $file_checker->visitAndAnalyzeMethods($context); } + /** + * @expectedException \Psalm\Exception\CodeException + * @expectedExceptionMessage InvalidFunctionCall + * @return void + */ + public function testUndefinedCallableClass() + { + Config::getInstance()->setCustomErrorLevel('UndefinedClass', Config::REPORT_SUPPRESS); + + $stmts = self::$parser->parse('getFoo()($argOne, $argTwo); + } + } + '); + + $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); + $context = new Context(); + $file_checker->visitAndAnalyzeMethods($context); + } + + + /** * @expectedException \Psalm\Exception\CodeException * @expectedExceptionMessage InvalidFunctionCall