1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +01:00

Fix #194 - carry over const definitions

This commit is contained in:
Matt Brown 2017-07-28 10:42:30 -04:00
parent c8ec0dc650
commit 22b6dafe3c
6 changed files with 67 additions and 18 deletions

View File

@ -643,6 +643,11 @@ class ProjectChecker
$included_file_storage->declaring_function_ids,
$storage->declaring_function_ids
);
$storage->declaring_constants = array_merge(
$included_file_storage->declaring_constants,
$storage->declaring_constants
);
}
$storage->populated = true;

View File

@ -392,6 +392,7 @@ class FetchChecker
default:
$const_type = $statements_checker->getConstType(
$statements_checker,
$const_name,
$stmt->name instanceof PhpParser\Node\Name\FullyQualified,
$context

View File

@ -35,11 +35,6 @@ class StatementsChecker extends SourceChecker implements StatementsSource
*/
private $all_vars = [];
/**
* @var array<string, array<string, Type\Union>>
*/
public static $user_constants = [];
/**
* @var array<string, Type\Union>
*/
@ -737,8 +732,12 @@ class StatementsChecker extends SourceChecker implements StatementsSource
*
* @return Type\Union|null
*/
public function getConstType($const_name, $is_fully_qualified, Context $context)
{
public function getConstType(
StatementsChecker $statements_checker,
$const_name,
$is_fully_qualified,
Context $context
) {
$fq_const_name = null;
$aliased_constants = $this->getAliases()->constants;
@ -769,6 +768,16 @@ class StatementsChecker extends SourceChecker implements StatementsSource
return $context->vars_in_scope[$const_name];
}
$file_path = $statements_checker->getFilePath();
$file_storage = FileChecker::$storage[strtolower($file_path)];
if (isset($file_storage->declaring_constants[$const_name])) {
$constant_file_path = $file_storage->declaring_constants[$const_name];
return FileChecker::$storage[strtolower($constant_file_path)]->constants[$const_name];
}
$predefined_constants = Config::getInstance()->getPredefinedConstants();
if (isset($predefined_constants[$fq_const_name ?: $const_name])) {
@ -796,8 +805,6 @@ class StatementsChecker extends SourceChecker implements StatementsSource
if ($this->source instanceof NamespaceChecker) {
$this->source->setConstType($const_name, $const_type);
} else {
self::$user_constants[$this->getFilePath()][$const_name] = $const_type;
}
}
@ -1060,7 +1067,6 @@ class StatementsChecker extends SourceChecker implements StatementsSource
*/
public static function clearCache()
{
self::$user_constants = [];
self::$stub_constants = [];
ExpressionChecker::clearCache();

View File

@ -12,13 +12,21 @@ class FileStorage
public $file_path;
/**
* @var array<FunctionLikeStorage>
* @var array<string, FunctionLikeStorage>
*/
public $functions = [];
/** @var array<string, string> */
public $declaring_function_ids = [];
/**
* @var array<string, \Psalm\Type\Union>
*/
public $constants = [];
/** @var array<string, string> */
public $declaring_constants = [];
/** @var array<string, string> */
public $included_file_paths = [];

View File

@ -299,12 +299,20 @@ class DependencyFinderVisitor extends PhpParser\NodeVisitorAbstract implements P
$this->queue_strings_as_possible_type = true;
}
if ($function_id === 'define' && $this->functionlike_storage) {
if ($function_id === 'define') {
$first_arg_value = isset($node->args[0]) ? $node->args[0]->value : null;
$second_arg_value = isset($node->args[1]) ? $node->args[1]->value : null;
if ($first_arg_value instanceof PhpParser\Node\Scalar\String_ && $second_arg_value) {
$this->functionlike_storage->defined_constants[$first_arg_value->value] =
StatementsChecker::getSimpleType($second_arg_value) ?: Type::getMixed();
$const_type = StatementsChecker::getSimpleType($second_arg_value) ?: Type::getMixed();
$const_name = $first_arg_value->value;
if ($this->functionlike_storage) {
$this->functionlike_storage->defined_constants[$const_name] = $const_type;
} else {
$file_storage = FileChecker::$storage[strtolower($this->file_path)];
$file_storage->constants[$const_name] = $const_type;
$file_storage->declaring_constants[$const_name] = $this->file_path;
}
}
}
}
@ -363,10 +371,16 @@ class DependencyFinderVisitor extends PhpParser\NodeVisitorAbstract implements P
}
}
} elseif ($node instanceof PhpParser\Node\Stmt\Const_) {
if ($this->project_checker->register_global_functions) {
foreach ($node->consts as $const) {
StatementsChecker::$stub_constants[$const->name] =
StatementsChecker::getSimpleType($const->value) ?: Type::getMixed();
foreach ($node->consts as $const) {
$const_type = StatementsChecker::getSimpleType($const->value) ?: Type::getMixed();
if ($this->project_checker->register_global_functions) {
StatementsChecker::$stub_constants[$const->name] = $const_type;
} else {
$file_storage = FileChecker::$storage[strtolower($this->file_path)];
$file_storage->constants[$const->name] = $const_type;
$file_storage->declaring_constants[$const->name] = $this->file_path;
}
}
}

View File

@ -143,6 +143,21 @@ class IncludeTest extends TestCase
getcwd() . DIRECTORY_SEPARATOR . 'file2.php',
],
],
'requireConstant' => [
'files' => [
getcwd() . DIRECTORY_SEPARATOR . 'file1.php' => '<?php
const FOO = 5;
define("BAR", "bat");',
getcwd() . DIRECTORY_SEPARATOR . 'file2.php' => '<?php
require("file1.php");
echo FOO;
echo BAR;',
],
'files_to_check' => [
getcwd() . DIRECTORY_SEPARATOR . 'file2.php',
],
],
'requireNamespacedWithUse' => [
'files' => [
getcwd() . DIRECTORY_SEPARATOR . 'file1.php' => '<?php