1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-14 02:07:37 +01:00
psalm/src/Psalm/Checker/FunctionChecker.php

150 lines
4.9 KiB
PHP
Raw Normal View History

2016-01-08 00:28:27 +01:00
<?php
namespace Psalm\Checker;
2016-01-08 00:28:27 +01:00
2016-02-04 15:22:46 +01:00
use PhpParser;
use Psalm\StatementsSource;
use Psalm\Config;
2016-08-14 05:26:45 +02:00
use Psalm\Type;
2016-01-08 00:28:27 +01:00
2016-08-14 05:26:45 +02:00
class FunctionChecker extends FunctionLikeChecker
2016-01-08 00:28:27 +01:00
{
protected static $function_return_types = [];
protected static $function_namespaces = [];
protected static $existing_functions = [];
protected static $deprecated_functions = [];
protected static $have_registered_function = [];
2016-08-14 05:26:45 +02:00
protected static $file_function_params = [];
protected static $builtin_function_params = [];
protected static $builtin_functions = [];
2016-05-16 22:12:02 +02:00
2016-06-16 02:16:40 +02:00
/**
2016-08-14 05:26:45 +02:00
* @param PhpParser\Node\Stmt\Function_ $function
* @param StatementsSource $source
* @param string $base_file_name
2016-06-16 02:16:40 +02:00
*/
2016-08-14 05:26:45 +02:00
public function __construct(PhpParser\Node\Stmt\Function_ $function, StatementsSource $source, $base_file_name)
2016-05-16 22:12:02 +02:00
{
2016-08-14 05:26:45 +02:00
parent::__construct($function, $source);
2016-05-16 22:12:02 +02:00
2016-08-14 05:26:45 +02:00
$this->registerFunction($function, $base_file_name);
2016-01-08 00:28:27 +01:00
}
2016-08-14 05:26:45 +02:00
public static function functionExists($function_id, $file_name)
{
2016-08-14 05:26:45 +02:00
if (isset(self::$existing_functions[$file_name][$function_id])) {
return true;
}
2016-08-14 05:26:45 +02:00
if (strpos($function_id, '::') !== false) {
$function_id = preg_replace('/^[^:]+::/', '', $function_id);
}
2016-08-14 05:26:45 +02:00
if (!isset(self::$builtin_functions[$function_id])) {
self::extractReflectionInfo($function_id);
}
2016-08-14 05:26:45 +02:00
return self::$builtin_functions[$function_id];
}
2016-08-11 01:21:03 +02:00
2016-08-14 05:26:45 +02:00
public static function getParams($function_id, $file_name)
2016-08-11 01:21:03 +02:00
{
2016-08-14 05:26:45 +02:00
if (isset(self::$builtin_functions[$function_id]) && self::$builtin_functions[$function_id]) {
return self::$builtin_function_params[$function_id];
2016-08-11 01:21:03 +02:00
}
2016-08-14 05:26:45 +02:00
return self::$file_function_params[$file_name][$function_id];
2016-08-11 01:21:03 +02:00
}
2016-08-14 05:26:45 +02:00
protected static function extractReflectionInfo($function_id)
2016-08-11 01:21:03 +02:00
{
2016-08-14 05:26:45 +02:00
try {
$reflection_function = new \ReflectionFunction($function_id);
2016-08-11 01:21:03 +02:00
2016-08-14 05:26:45 +02:00
$reflection_params = $reflection_function->getParameters();
2016-08-11 01:21:03 +02:00
2016-08-14 05:26:45 +02:00
self::$builtin_function_params[$function_id] = [];
2016-08-11 01:21:03 +02:00
2016-08-14 05:26:45 +02:00
foreach ($reflection_params as $param) {
self::$builtin_function_params[$function_id][] = self::getReflectionParamArray($param);
2016-08-11 01:21:03 +02:00
}
2016-08-14 05:26:45 +02:00
self::$builtin_functions[$function_id] = true;
}
catch (\ReflectionException $e) {
self::$builtin_functions[$function_id] = false;
2016-08-11 01:21:03 +02:00
}
}
2016-08-14 19:13:53 +02:00
public static function getFunctionReturnTypes($function_id, $file_name)
{
if (!isset(self::$function_return_types[$file_name][$function_id])) {
throw new \InvalidArgumentException('Do not know function');
}
return self::$function_return_types[$file_name][$function_id]
? clone self::$function_return_types[$file_name][$function_id]
: null;
}
protected function registerFunction(PhpParser\Node\Stmt\Function_ $function, $file_name)
2016-08-11 01:21:03 +02:00
{
$function_id = $function->name;
if (isset(self::$have_registered_function[$file_name][$function_id])) {
2016-08-15 05:24:16 +02:00
return;
2016-08-11 01:21:03 +02:00
}
self::$have_registered_function[$file_name][$function_id] = true;
2016-08-11 01:21:03 +02:00
self::$function_namespaces[$file_name][$function_id] = $this->namespace;
2016-08-14 05:26:45 +02:00
self::$existing_functions[$file_name][$function_id] = true;
2016-08-11 01:21:03 +02:00
2016-08-14 05:26:45 +02:00
self::$file_function_params[$file_name][$function_id] = [];
2016-08-11 01:21:03 +02:00
$function_param_names = [];
foreach ($function->getParams() as $param) {
$param_array = $this->getParamArray($param);
2016-08-14 05:26:45 +02:00
self::$file_function_params[$file_name][$function_id][] = $param_array;
2016-08-11 01:21:03 +02:00
$function_param_names[$param->name] = $param_array['type'];
}
$config = Config::getInstance();
$return_type = null;
$docblock_info = CommentChecker::extractDocblockInfo($function->getDocComment());
if ($docblock_info['deprecated']) {
self::$deprecated_functions[$file_name][$function_id] = true;
2016-08-11 01:21:03 +02:00
}
$this->suppressed_issues = $docblock_info['suppress'];
2016-08-11 01:21:03 +02:00
if ($config->use_docblock_types) {
if ($docblock_info['return_type']) {
$return_type =
Type::parseString(
self::fixUpLocalType(
$docblock_info['return_type'],
null,
$this->namespace,
$this->aliased_classes
2016-08-11 01:21:03 +02:00
)
);
}
if ($docblock_info['params']) {
$this->improveParamsFromDocblock(
$docblock_info['params'],
$function_param_names,
2016-08-14 05:26:45 +02:00
self::$file_function_params[$file_name][$function_id],
2016-08-11 01:21:03 +02:00
$function->getLine()
);
}
}
self::$function_return_types[$file_name][$function_id] = $return_type;
2016-08-11 01:21:03 +02:00
}
2016-01-08 00:28:27 +01:00
}