1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-27 04:45:20 +01:00

Don’t emit MissingClosureReturnType when inside call and type can be inferred

This commit is contained in:
Matthew Brown 2019-05-06 20:47:55 -04:00
parent fec1a60e90
commit 4f8d6a50d8
5 changed files with 54 additions and 32 deletions

View File

@ -62,6 +62,13 @@ class Context
*/
public $inside_class_exists = false;
/**
* Whether or not we're inside a function/method call
*
* @var bool
*/
public $inside_call = false;
/**
* @var null|CodeLocation
*/

View File

@ -56,7 +56,8 @@ class ReturnTypeAnalyzer
Type\Union $return_type = null,
$fq_class_name = null,
CodeLocation $return_type_location = null,
array $compatible_method_ids = []
array $compatible_method_ids = [],
bool $closure_inside_call = false
) {
$suppressed_issues = $function_like_analyzer->getSuppressedIssues();
$codebase = $source->getCodebase();
@ -246,36 +247,38 @@ class ReturnTypeAnalyzer
if (!$return_type) {
if ($function instanceof Closure) {
if ($codebase->alter_code
&& isset($project_analyzer->getIssuesToFix()['MissingClosureReturnType'])
) {
if ($inferred_return_type->hasMixed() || $inferred_return_type->isNull()) {
if (!$closure_inside_call || $inferred_return_type->isMixed()) {
if ($codebase->alter_code
&& isset($project_analyzer->getIssuesToFix()['MissingClosureReturnType'])
) {
if ($inferred_return_type->hasMixed() || $inferred_return_type->isNull()) {
return null;
}
self::addOrUpdateReturnType(
$function,
$project_analyzer,
$inferred_return_type,
$source,
$function_like_analyzer,
($project_analyzer->only_replace_php_types_with_non_docblock_types
|| $unsafe_return_type)
&& $inferred_return_type->from_docblock,
$function_like_storage
);
return null;
}
self::addOrUpdateReturnType(
$function,
$project_analyzer,
$inferred_return_type,
$source,
$function_like_analyzer,
($project_analyzer->only_replace_php_types_with_non_docblock_types
|| $unsafe_return_type)
&& $inferred_return_type->from_docblock,
$function_like_storage
);
return null;
}
if (IssueBuffer::accepts(
new MissingClosureReturnType(
'Closure does not have a return type, expecting ' . $inferred_return_type,
new CodeLocation($function_like_analyzer, $function, null, true)
),
$suppressed_issues
)) {
// fall through
if (IssueBuffer::accepts(
new MissingClosureReturnType(
'Closure does not have a return type, expecting ' . $inferred_return_type,
new CodeLocation($function_like_analyzer, $function, null, true)
),
$suppressed_issues
)) {
// fall through
}
}
return null;

View File

@ -708,7 +708,8 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements
$statements_analyzer,
$storage->return_type,
$this->source->getFQCLN(),
$storage->return_type_location
$storage->return_type_location,
$global_context && $global_context->inside_call
);
$closure_yield_types = [];
@ -931,7 +932,8 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements
StatementsAnalyzer $statements_analyzer,
Type\Union $return_type = null,
$fq_class_name = null,
CodeLocation $return_type_location = null
CodeLocation $return_type_location = null,
bool $closure_inside_call = false
) {
ReturnTypeAnalyzer::verifyReturnType(
$this->function,
@ -939,7 +941,9 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements
$this,
$return_type,
$fq_class_name,
$return_type_location
$return_type_location,
[],
$closure_inside_call
);
}

View File

@ -448,10 +448,18 @@ class CallAnalyzer
}
}
$was_inside_call = $context->inside_call;
$context->inside_call = true;
if (ExpressionAnalyzer::analyze($statements_analyzer, $arg->value, $context) === false) {
return false;
}
if (!$was_inside_call) {
$context->inside_call = false;
}
if ($context->collect_references
&& ($arg->value instanceof PhpParser\Node\Expr\AssignOp
|| $arg->value instanceof PhpParser\Node\Expr\PreInc

View File

@ -2178,7 +2178,7 @@ class TemplateTest extends TestCase
*/
function expandOptions(Collection $collection) : Collection {
return $collection->map(
function ($optional) : string {
function ($optional) {
return $optional->get();
}
);