1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Fix #97 - is_callable shouldn’t prevent evaluation of calls to existing functions

This commit is contained in:
Matthew Brown 2017-02-16 20:51:53 -05:00
parent 2d58531631
commit 9579460c59
2 changed files with 98 additions and 62 deletions

View File

@ -131,7 +131,7 @@ class CallChecker
$code_location = new CodeLocation($statements_checker->getSource(), $stmt);
$defined_constants = [];
if ($context->check_functions) {
$function_exists = false;
if ($stmt->name instanceof PhpParser\Node\Expr) {
if (ExpressionChecker::analyze($statements_checker, $stmt->name, $context) === false) {
@ -153,6 +153,8 @@ class CallChecker
$stmt->inferredType = $var_type_part->return_type;
}
}
$function_exists = true;
} elseif (!$var_type_part instanceof TMixed &&
(!$var_type_part instanceof TNamedObject || $var_type_part->value !== 'Closure') &&
!$var_type_part instanceof TCallable &&
@ -202,11 +204,8 @@ class CallChecker
$method_id = FunctionChecker::getFQFunctionNameFromString($method_id, $statements_checker);
}
if ($context->self) {
//$method_id = $statements_checker->getFQCLN() . '::' . $method_id;
}
if (!$in_call_map && !$is_stubbed) {
if ($context->check_functions) {
if (self::checkFunctionExists(
$statements_checker,
$method_id,
@ -217,6 +216,15 @@ class CallChecker
}
}
$function_exists = FunctionChecker::functionExists(
strtolower($method_id),
$statements_checker->getFilePath()
);
} else {
$function_exists = true;
}
if ($function_exists) {
if (!$in_call_map || $is_stubbed) {
$function_storage = FunctionChecker::getStorage(
strtolower($method_id),
@ -249,7 +257,7 @@ class CallChecker
// fall through
}
if ($context->check_functions) {
if ($function_exists) {
$generic_params = null;
if ($stmt->name instanceof PhpParser\Node\Name && $method_id) {

View File

@ -481,4 +481,32 @@ class FunctionCallTest extends PHPUnit_Framework_TestCase
$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('<?php
/**
* @param callable $callback
* @return void
*/
function route($callback) {
if (!is_callable($callback)) { }
takes_int("string");
}
function takes_int(int $i) {}
');
$file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts);
$context = new Context();
$file_checker->visitAndAnalyzeMethods($context);
}
}