mirror of
https://github.com/danog/psalm.git
synced 2024-11-27 04:45:20 +01:00
Refine inferred type when possible
This commit is contained in:
parent
db89b3cc3f
commit
3a01afbe0a
@ -390,7 +390,8 @@ class Context
|
||||
public function inferType(
|
||||
PhpParser\Node\Expr $expr,
|
||||
FunctionLikeStorage $function_storage,
|
||||
Type\Union $inferred_type
|
||||
Type\Union $inferred_type,
|
||||
Codebase $codebase
|
||||
) {
|
||||
if (!isset($expr->inferredType)) {
|
||||
return;
|
||||
@ -398,20 +399,27 @@ class Context
|
||||
|
||||
$expr_type = $expr->inferredType;
|
||||
|
||||
if (($expr_type->hasMixed() || $expr_type->getId() === $inferred_type->getId())
|
||||
&& $expr instanceof PhpParser\Node\Expr\Variable
|
||||
if ($expr instanceof PhpParser\Node\Expr\Variable
|
||||
&& is_string($expr->name)
|
||||
&& !isset($this->assigned_var_ids['$' . $expr->name])
|
||||
&& array_key_exists($expr->name, $function_storage->param_types)
|
||||
&& !$function_storage->param_types[$expr->name]
|
||||
) {
|
||||
if (isset($this->possible_param_types[$expr->name])) {
|
||||
$this->possible_param_types[$expr->name] = Type::combineUnionTypes(
|
||||
$this->possible_param_types[$expr->name],
|
||||
$inferred_type
|
||||
);
|
||||
if (\Psalm\Internal\Analyzer\TypeAnalyzer::isContainedBy(
|
||||
$codebase,
|
||||
$inferred_type,
|
||||
$this->possible_param_types[$expr->name]
|
||||
)) {
|
||||
$this->possible_param_types[$expr->name] = clone $inferred_type;
|
||||
} else {
|
||||
$this->possible_param_types[$expr->name] = Type::combineUnionTypes(
|
||||
$this->possible_param_types[$expr->name],
|
||||
$inferred_type
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$this->possible_param_types[$expr->name] = $inferred_type;
|
||||
$this->possible_param_types[$expr->name] = clone $inferred_type;
|
||||
$this->vars_in_scope['$' . $expr->name] = clone $inferred_type;
|
||||
}
|
||||
}
|
||||
|
@ -551,8 +551,18 @@ class BinaryOpAnalyzer
|
||||
if ($source_analyzer instanceof FunctionLikeAnalyzer) {
|
||||
$function_storage = $source_analyzer->getFunctionLikeStorage($statements_analyzer);
|
||||
|
||||
$context->inferType($stmt->left, $function_storage, new Type\Union([new TInt, new TFloat]));
|
||||
$context->inferType($stmt->right, $function_storage, new Type\Union([new TInt, new TFloat]));
|
||||
$context->inferType(
|
||||
$stmt->left,
|
||||
$function_storage,
|
||||
new Type\Union([new TInt, new TFloat]),
|
||||
$codebase
|
||||
);
|
||||
$context->inferType(
|
||||
$stmt->right,
|
||||
$function_storage,
|
||||
new Type\Union([new TInt, new TFloat]),
|
||||
$codebase
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -657,8 +667,18 @@ class BinaryOpAnalyzer
|
||||
) {
|
||||
$function_storage = $source_analyzer->getFunctionLikeStorage($statements_source);
|
||||
|
||||
$context->inferType($left, $function_storage, new Type\Union([new TInt, new TFloat]));
|
||||
$context->inferType($right, $function_storage, new Type\Union([new TInt, new TFloat]));
|
||||
$context->inferType(
|
||||
$left,
|
||||
$function_storage,
|
||||
new Type\Union([new TInt, new TFloat]),
|
||||
$codebase
|
||||
);
|
||||
$context->inferType(
|
||||
$right,
|
||||
$function_storage,
|
||||
new Type\Union([new TInt, new TFloat]),
|
||||
$codebase
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1198,8 +1218,18 @@ class BinaryOpAnalyzer
|
||||
if ($source_analyzer instanceof FunctionLikeAnalyzer) {
|
||||
$function_storage = $source_analyzer->getFunctionLikeStorage($statements_analyzer);
|
||||
|
||||
$context->inferType($left, $function_storage, Type::getString());
|
||||
$context->inferType($right, $function_storage, Type::getString());
|
||||
$context->inferType(
|
||||
$left,
|
||||
$function_storage,
|
||||
new Type\Union([new Type\Atomic\TString, new Type\Atomic\TInt, new Type\Atomic\TFloat]),
|
||||
$codebase
|
||||
);
|
||||
$context->inferType(
|
||||
$right,
|
||||
$function_storage,
|
||||
new Type\Union([new Type\Atomic\TString, new Type\Atomic\TInt, new Type\Atomic\TFloat]),
|
||||
$codebase
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1768,7 +1768,8 @@ class CallAnalyzer
|
||||
$context->inferType(
|
||||
$input_expr,
|
||||
$source_analyzer->getFunctionLikeStorage($statements_analyzer),
|
||||
$param_type
|
||||
$param_type,
|
||||
$codebase
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1325,7 +1325,12 @@ class ExpressionAnalyzer
|
||||
}
|
||||
|
||||
if ($function_storage) {
|
||||
$context->inferType($part, $function_storage, Type::getString());
|
||||
$context->inferType(
|
||||
$part,
|
||||
$function_storage,
|
||||
new Type\Union([new Type\Atomic\TString, new Type\Atomic\TInt, new Type\Atomic\TFloat]),
|
||||
$statements_analyzer->getCodebase()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,7 +308,7 @@ class FunctionDocblockManipulator
|
||||
foreach ($parsed_docblock['specials']['param'] as &$param_block) {
|
||||
$doc_parts = CommentAnalyzer::splitDocLine($param_block);
|
||||
|
||||
if ($doc_parts[1] === '$' . $param_name) {
|
||||
if (($doc_parts[1] ?? null) === '$' . $param_name) {
|
||||
$param_block = $new_param_block;
|
||||
$found_in_params = true;
|
||||
break;
|
||||
|
@ -1323,12 +1323,30 @@ class FileManipulationTest extends TestCase
|
||||
function fooFoo($a): void {
|
||||
echo $a . "foo";
|
||||
}',
|
||||
'<?php
|
||||
/**
|
||||
* @param string|int|float $a
|
||||
*/
|
||||
function fooFoo($a): void {
|
||||
echo $a . "foo";
|
||||
}',
|
||||
'7.1',
|
||||
['MissingParamType'],
|
||||
true,
|
||||
],
|
||||
'noParamTypeButConcatAndStringUsage' => [
|
||||
'<?php
|
||||
function fooFoo($a): void {
|
||||
echo $a . "foo";
|
||||
echo substr($a, 4, 2);
|
||||
}',
|
||||
'<?php
|
||||
/**
|
||||
* @param string $a
|
||||
*/
|
||||
function fooFoo($a): void {
|
||||
echo $a . "foo";
|
||||
echo substr($a, 4, 2);
|
||||
}',
|
||||
'7.1',
|
||||
['MissingParamType'],
|
||||
@ -1371,12 +1389,30 @@ class FileManipulationTest extends TestCase
|
||||
function fooFoo($a): void {
|
||||
echo "$a";
|
||||
}',
|
||||
'<?php
|
||||
/**
|
||||
* @param string|int|float $a
|
||||
*/
|
||||
function fooFoo($a): void {
|
||||
echo "$a";
|
||||
}',
|
||||
'7.1',
|
||||
['MissingParamType'],
|
||||
true,
|
||||
],
|
||||
'noParamTypeButTemplatedStringAntStringUsage' => [
|
||||
'<?php
|
||||
function fooFoo($a): void {
|
||||
echo "$a";
|
||||
echo substr($a, 4, 2);
|
||||
}',
|
||||
'<?php
|
||||
/**
|
||||
* @param string $a
|
||||
*/
|
||||
function fooFoo($a): void {
|
||||
echo "$a";
|
||||
echo substr($a, 4, 2);
|
||||
}',
|
||||
'7.1',
|
||||
['MissingParamType'],
|
||||
|
Loading…
Reference in New Issue
Block a user