1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Allow MissingParamType alteration to be done in multithreaded mode

This commit is contained in:
Brown 2019-05-31 11:55:24 -04:00
parent 534e4c034b
commit a060da95bf
9 changed files with 108 additions and 46 deletions

View File

@ -172,7 +172,7 @@ abstract class ClassLikeAnalyzer extends SourceAnalyzer implements StatementsSou
}
}
public function getFunctionLikeAnalyzer(string $method_name) : FunctionLikeAnalyzer
public function getFunctionLikeAnalyzer(string $method_name) : ?FunctionLikeAnalyzer
{
foreach ($this->class->stmts as $stmt) {
if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod &&
@ -182,7 +182,7 @@ abstract class ClassLikeAnalyzer extends SourceAnalyzer implements StatementsSou
}
}
throw new \UnexpectedValueException('Should return a function analyzer');
return null;
}
/**

View File

@ -340,12 +340,12 @@ class FileAnalyzer extends SourceAnalyzer implements StatementsSource
}
}
public function getFunctionLikeAnalyzer(string $method_id) : FunctionLikeAnalyzer
public function getFunctionLikeAnalyzer(string $method_id) : ?FunctionLikeAnalyzer
{
list($fq_class_name, $method_name) = explode('::', $method_id);
if (!isset($this->class_analyzers_to_analyze[strtolower($fq_class_name)])) {
throw new \UnexpectedValueException('Should not happen');
return null;
}
$class_analyzer_to_examine = $this->class_analyzers_to_analyze[strtolower($fq_class_name)];

View File

@ -953,7 +953,7 @@ class ProjectAnalyzer
$file_analyzer->interface_analyzers_to_analyze = [];
}
public function getFunctionLikeAnalyzer(string $method_id, string $file_path) : FunctionLikeAnalyzer
public function getFunctionLikeAnalyzer(string $method_id, string $file_path) : ?FunctionLikeAnalyzer
{
$file_analyzer = new FileAnalyzer(
$this,

View File

@ -2223,15 +2223,18 @@ class CallAnalyzer
$declaring_method_id = $codebase->methods->getDeclaringMethodId($cased_method_id);
if ($declaring_method_id) {
$method_storage = $codebase->methods->getStorage($declaring_method_id);
$id_lc = strtolower($declaring_method_id);
if (!isset($method_storage->possible_param_types[$argument_offset])) {
$method_storage->possible_param_types[$argument_offset] = clone $input_type;
if (!isset($codebase->analyzer->possible_method_param_types[$id_lc][$argument_offset])) {
$codebase->analyzer->possible_method_param_types[$id_lc][$argument_offset]
= clone $input_type;
} else {
$method_storage->possible_param_types[$argument_offset] = Type::combineUnionTypes(
$method_storage->possible_param_types[$argument_offset],
clone $input_type
);
$codebase->analyzer->possible_method_param_types[$id_lc][$argument_offset]
= Type::combineUnionTypes(
$codebase->analyzer->possible_method_param_types[$id_lc][$argument_offset],
clone $input_type,
$codebase
);
}
}
}

View File

@ -51,7 +51,8 @@ use Psalm\Progress\Progress;
* >,
* class_locations: array<string, array<int, \Psalm\CodeLocation>>,
* class_method_locations: array<string, array<int, \Psalm\CodeLocation>>,
* class_property_locations: array<string, array<int, \Psalm\CodeLocation>>
* class_property_locations: array<string, array<int, \Psalm\CodeLocation>>,
* possible_method_param_types: array<string, array<int, \Psalm\Type\Union>>
* }
*/
@ -135,6 +136,11 @@ class Analyzer
*/
private $type_map = [];
/**
* @var array<string, array<int, \Psalm\Type\Union>>
*/
public $possible_method_param_types = [];
public function __construct(
Config $config,
FileProvider $file_provider,
@ -299,6 +305,7 @@ class Analyzer
'class_locations' => $file_reference_provider->getAllClassLocations(),
'class_method_locations' => $file_reference_provider->getAllClassMethodLocations(),
'class_property_locations' => $file_reference_provider->getAllClassPropertyLocations(),
'possible_method_param_types' => $analyzer->getPossibleMethodParamTypes(),
];
},
$task_done_closure
@ -363,6 +370,26 @@ class Analyzer
}
}
foreach ($pool_data['possible_method_param_types'] as $declaring_method_id => $possible_param_types) {
if (!isset($this->possible_method_param_types[$declaring_method_id])) {
$this->possible_method_param_types[$declaring_method_id] = $possible_param_types;
} else {
foreach ($possible_param_types as $offset => $possible_param_type) {
if (!isset($this->possible_method_param_types[$declaring_method_id][$offset])) {
$this->possible_method_param_types[$declaring_method_id][$offset]
= $possible_param_type;
} else {
$this->possible_method_param_types[$declaring_method_id][$offset]
= \Psalm\Type::combineUnionTypes(
$this->possible_method_param_types[$declaring_method_id][$offset],
$possible_param_type,
$codebase
);
}
}
}
}
foreach ($pool_data['file_manipulations'] as $file_path => $manipulations) {
FileManipulationBuffer::add($file_path, $manipulations);
}
@ -1223,6 +1250,14 @@ class Analyzer
];
}
/**
* @return array<string, array<int, \Psalm\Type\Union>>
*/
public function getPossibleMethodParamTypes()
{
return $this->possible_method_param_types;
}
/**
* @param string $file_path
* @param string $method_id

View File

@ -929,30 +929,43 @@ class ClassLikes
} else {
if ($codebase->alter_code
&& isset($project_analyzer->getIssuesToFix()['MissingParamType'])
&& isset($codebase->analyzer->possible_method_param_types[strtolower($method_id)])
) {
if ($method_storage->possible_param_types && $method_storage->location) {
if ($method_storage->location) {
$function_analyzer = $project_analyzer->getFunctionLikeAnalyzer(
$method_id,
$method_storage->location->file_path
);
foreach ($method_storage->possible_param_types as $offset => $possible_type) {
if (!isset($method_storage->params[$offset])) {
continue;
$possible_param_types
= $codebase->analyzer->possible_method_param_types[strtolower($method_id)];
if ($function_analyzer && $possible_param_types) {
foreach ($possible_param_types as $offset => $possible_type) {
if (!isset($method_storage->params[$offset])) {
continue;
}
$param_name = $method_storage->params[$offset]->name;
if ($possible_type->hasMixed() || $possible_type->isNull()) {
continue;
}
if ($method_storage->params[$offset]->default_type) {
$possible_type = \Psalm\Type::combineUnionTypes(
$possible_type,
$method_storage->params[$offset]->default_type
);
}
$function_analyzer->addOrUpdateParamType(
$project_analyzer,
$param_name,
$possible_type,
true
);
}
$param_name = $method_storage->params[$offset]->name;
if ($possible_type->hasMixed() || $possible_type->isNull()) {
continue;
}
$function_analyzer->addOrUpdateParamType(
$project_analyzer,
$param_name,
$possible_type,
true
);
}
}
}

View File

@ -169,11 +169,6 @@ class FunctionLikeStorage
*/
public $unused_docblock_params;
/**
* @var array<int, Type\Union>|null
*/
public $possible_param_types;
public function __toString()
{
$symbol_text = 'function ' . $this->cased_name . '(' . implode(

View File

@ -368,19 +368,15 @@ if ($config->find_unused_code) {
$find_unused_code = true;
}
foreach ($keyed_issues as $issue_name => $_) {
// MissingParamType requires the scanning of all files to inform possible params
if (strpos($issue_name, 'Unused') !== false || $issue_name === 'MissingParamType') {
$find_unused_code = true;
}
}
if ($find_unused_code) {
$project_analyzer->getCodebase()->reportUnusedCode();
} else {
foreach ($keyed_issues as $issue_name => $_) {
if (strpos($issue_name, 'Unused') !== false) {
die(
'Error: Psalm can only fix issue '
. $issue_name
. ' if you enable unused code detection with --find-unused-code'
. PHP_EOL
);
}
}
}
$project_analyzer->alterCodeAfterCompletion(

View File

@ -85,6 +85,26 @@ class ParamTypeManipulationTest extends FileManipulationTest
['MissingParamType'],
true,
],
'noBoolParamTypeWithDefault' => [
'<?php
class C {
public function fooFoo($a = true): void {}
}
(new C)->fooFoo(false);',
'<?php
class C {
/**
* @param bool $a
*/
public function fooFoo($a = true): void {}
}
(new C)->fooFoo(false);',
'7.1',
['MissingParamType'],
true,
],
'noStringParamTypeParent' => [
'<?php
class C {