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

Mutation checks should not care about return type

This commit is contained in:
Brown 2019-03-06 11:12:36 -05:00
parent ae69695f89
commit 9442805763
3 changed files with 150 additions and 108 deletions

View File

@ -62,7 +62,7 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements
protected $source;
/**
* @var array<string, array<string, Type\Union>>
* @var ?array<string, Type\Union>
*/
protected $return_vars_in_scope = [];
@ -72,7 +72,7 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements
protected $possible_param_types = [];
/**
* @var array<string, array<string, bool>>
* @var ?array<string, bool>
*/
protected $return_vars_possibly_in_scope = [];
@ -582,7 +582,7 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements
return false;
}
if ($context->collect_initializations) {
if ($context->collect_initializations || $context->collect_mutations) {
$statements_analyzer->addSuppressedIssues([
'DocblockTypeContradiction',
'InvalidReturnStatement',
@ -854,17 +854,17 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements
}
if ($add_mutations) {
if (isset($this->return_vars_in_scope[''])) {
if ($this->return_vars_in_scope !== null) {
$context->vars_in_scope = TypeAnalyzer::combineKeyedTypes(
$context->vars_in_scope,
$this->return_vars_in_scope['']
$this->return_vars_in_scope
);
}
if (isset($this->return_vars_possibly_in_scope[''])) {
if ($this->return_vars_possibly_in_scope !== null) {
$context->vars_possibly_in_scope = array_merge(
$context->vars_possibly_in_scope,
$this->return_vars_possibly_in_scope['']
$this->return_vars_possibly_in_scope
);
}
@ -967,24 +967,24 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements
*
* @return void
*/
public function addReturnTypes($return_type, Context $context)
public function addReturnTypes(Context $context)
{
if (isset($this->return_vars_in_scope[$return_type])) {
$this->return_vars_in_scope[$return_type] = TypeAnalyzer::combineKeyedTypes(
if ($this->return_vars_in_scope !== null) {
$this->return_vars_in_scope = TypeAnalyzer::combineKeyedTypes(
$context->vars_in_scope,
$this->return_vars_in_scope[$return_type]
$this->return_vars_in_scope
);
} else {
$this->return_vars_in_scope[$return_type] = $context->vars_in_scope;
$this->return_vars_in_scope = $context->vars_in_scope;
}
if (isset($this->return_vars_possibly_in_scope[$return_type])) {
$this->return_vars_possibly_in_scope[$return_type] = array_merge(
if ($this->return_vars_possibly_in_scope !== null) {
$this->return_vars_possibly_in_scope = array_merge(
$context->vars_possibly_in_scope,
$this->return_vars_possibly_in_scope[$return_type]
$this->return_vars_possibly_in_scope
);
} else {
$this->return_vars_possibly_in_scope[$return_type] = $context->vars_possibly_in_scope;
$this->return_vars_possibly_in_scope = $context->vars_possibly_in_scope;
}
}

View File

@ -119,10 +119,7 @@ class ReturnAnalyzer
if ($source instanceof FunctionLikeAnalyzer
&& !($source->getSource() instanceof TraitAnalyzer)
) {
$source->addReturnTypes(
$stmt->expr ? (string) $stmt->inferredType : '',
$context
);
$source->addReturnTypes($context);
$source->examineParamTypes($statements_analyzer, $context, $codebase, $stmt);

View File

@ -106,6 +106,51 @@ class MethodMutationTest extends TestCase
$this->assertTrue($method_context->vars_possibly_in_scope['$this->title']);
}
/**
* @return void
*/
public function testNotSettingUser()
{
$this->addFile(
'somefile.php',
'<?php
class User {}
class FooController {
/** @var User|null */
public $user;
public function doThingWithUser(): array
{
if (!$this->user) {
return [];
}
return ["hello"];
}
public function barBar(): void {
$this->user = rand(0, 1) ? new User() : null;
$this->doThingWithUser();
}
}'
);
new FileAnalyzer($this->project_analyzer, 'somefile.php', 'somefile.php');
$this->project_analyzer->getCodebase()->scanFiles();
$method_context = new Context();
$method_context->collect_mutations = true;
$this->project_analyzer->getMethodMutations(
'FooController::barBar',
$method_context,
'somefile.php',
'somefile.php'
);
$this->assertSame('null|User', (string)$method_context->vars_in_scope['$this->user']);
}
/**
* @return void
*/