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:
parent
956972b4a4
commit
47cb74ddd1
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user