1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Fix issue where namespaced function could be treated as root

This commit is contained in:
Matthew Brown 2018-02-25 11:13:00 -05:00
parent 956972b4a4
commit 47cb74ddd1
3 changed files with 68 additions and 12 deletions

View File

@ -216,6 +216,9 @@ class FunctionCallChecker extends \Psalm\Checker\Statements\Expression\CallCheck
$is_predefined = true;
$is_maybe_root_function = !$stmt->name instanceof PhpParser\Node\Name\FullyQualified
&& count($stmt->name->parts) === 1;
if (!$in_call_map) {
$predefined_functions = $config->getPredefinedFunctions();
$is_predefined = isset($predefined_functions[$function_id]);
@ -233,13 +236,18 @@ class FunctionCallChecker extends \Psalm\Checker\Statements\Expression\CallCheck
if (self::checkFunctionExists(
$statements_checker,
$function_id,
$code_location
$code_location,
$is_maybe_root_function
) === false
) {
return false;
}
} else {
$function_id = self::getExistingFunctionId($statements_checker, $function_id);
$function_id = self::getExistingFunctionId(
$statements_checker,
$function_id,
$is_maybe_root_function
);
}
$function_exists = $is_stubbed || $codebase_functions->functionExists(

View File

@ -1269,7 +1269,8 @@ class CallChecker
if (self::checkFunctionExists(
$statements_checker,
$function_id,
$code_location
$code_location,
false
) === false
) {
return false;
@ -1377,13 +1378,15 @@ class CallChecker
* @param StatementsChecker $statements_checker
* @param string $function_id
* @param CodeLocation $code_location
* @param bool $can_be_in_root_scope if true, the function can be shortened to the root version
*
* @return bool
*/
protected static function checkFunctionExists(
StatementsChecker $statements_checker,
&$function_id,
CodeLocation $code_location
CodeLocation $code_location,
$can_be_in_root_scope
) {
$cased_function_id = $function_id;
$function_id = strtolower($function_id);
@ -1393,7 +1396,8 @@ class CallChecker
if (!$codebase->functions->functionExists($statements_checker, $function_id)) {
$root_function_id = preg_replace('/.*\\\/', '', $function_id);
if ($function_id !== $root_function_id
if ($can_be_in_root_scope
&& $function_id !== $root_function_id
&& $codebase->functions->functionExists($statements_checker, $root_function_id)
) {
$function_id = $root_function_id;
@ -1418,11 +1422,15 @@ class CallChecker
/**
* @param StatementsChecker $statements_checker
* @param string $function_id
* @param bool $can_be_in_root_scope if true, the function can be shortened to the root version
*
* @return string
*/
protected static function getExistingFunctionId(StatementsChecker $statements_checker, $function_id)
{
protected static function getExistingFunctionId(
StatementsChecker $statements_checker,
$function_id,
$can_be_in_root_scope
) {
$function_id = strtolower($function_id);
$codebase = $statements_checker->getFileChecker()->project_checker->codebase;
@ -1431,6 +1439,10 @@ class CallChecker
return $function_id;
}
if (!$can_be_in_root_scope) {
return $function_id;
}
$root_function_id = preg_replace('/.*\\\/', '', $function_id);
if ($function_id !== $root_function_id

View File

@ -4,6 +4,7 @@ namespace Psalm\Tests;
class NamespaceTest extends TestCase
{
use Traits\FileCheckerValidCodeParseTestTrait;
use Traits\FileCheckerInvalidCodeParseTestTrait;
/**
* @return array
@ -16,17 +17,17 @@ class NamespaceTest extends TestCase
namespace A {
/** @return void */
function foo() {
}
class Bar {
}
}
namespace {
A\foo();
\A\foo();
(new A\Bar);
}',
],
@ -40,7 +41,7 @@ class NamespaceTest extends TestCase
function foo() {
echo \Aye\Bee\HELLO;
}
class Bar {
/** @return void */
public function foo() {
@ -51,4 +52,39 @@ class NamespaceTest extends TestCase
],
];
}
/**
* @return array
*/
public function providerFileCheckerInvalidCodeParse()
{
return [
'callNamespacedFunctionFromEmptyNamespace' => [
'<?php
namespace A {
/** @return void */
function foo() {
}
}
namespace {
foo();
}',
'error_message' => 'UndefinedFunction',
],
'callRootFunctionFromNamespace' => [
'<?php
namespace {
/** @return void */
function foo() {
}
}
namespace A {
\A\foo();
}',
'error_message' => 'UndefinedFunction',
],
];
}
}