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

Fix #2279 - add parameter typehint by default

This commit is contained in:
Matthew Brown 2019-12-03 01:49:43 -05:00
parent dd05f6e3ca
commit 97de060df9
4 changed files with 113 additions and 22 deletions

View File

@ -1295,9 +1295,27 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer
$this->getMethodId(),
$this->function
);
$codebase = $project_analyzer->getCodebase();
$is_final = true;
$fqcln = $this->source->getFQCLN();
if ($fqcln !== null && $this->function instanceof ClassMethod) {
$class_storage = $codebase->classlike_storage_provider->get($fqcln);
$is_final = $this->function->isFinal() || $class_storage->final;
}
$allow_native_type = !$docblock_only
&& $codebase->php_major_version >= 7
&& (
$codebase->allow_backwards_incompatible_changes
|| $is_final
|| !$this->function instanceof PhpParser\Node\Stmt\ClassMethod
);
$manipulator->setParamType(
$param_name,
!$docblock_only && $project_analyzer->getCodebase()->php_major_version >= 7
$allow_native_type
? $inferred_return_type->toPhpString(
$this->source->getNamespace(),
$this->source->getAliasedClassesFlipped(),
@ -1316,8 +1334,7 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer
$this->source->getAliasedClassesFlipped(),
$this->source->getFQCLN(),
true
),
$inferred_return_type->canBeFullyExpressedInPhp()
)
);
}

View File

@ -1957,7 +1957,8 @@ class ClassLikes
$project_analyzer,
$param_name,
$possible_type,
true
$possible_type->from_docblock
&& $project_analyzer->only_replace_php_types_with_non_docblock_types
);
}
} else {

View File

@ -1,8 +1,8 @@
<?php
namespace Psalm\Internal\FileManipulation;
use PhpParser;
use function count;
use function ltrim;
use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\Closure;
@ -72,9 +72,6 @@ class FunctionDocblockManipulator
/** @var array<string, string> */
private $new_php_param_types = [];
/** @var array<string, bool> */
private $param_type_is_php_compatible = [];
/** @var array<string, string> */
private $new_phpdoc_param_types = [];
@ -87,6 +84,12 @@ class FunctionDocblockManipulator
/** @var string|null */
private $return_type_description;
/** @var array<string, int> */
private $param_offsets = [];
/** @var array<string, array{int, int}> */
private $param_typehint_offsets = [];
/**
* @param string $file_path
* @param string $function_id
@ -124,6 +127,21 @@ class FunctionDocblockManipulator
$this->docblock_end = $function_start = (int)$stmt->getAttribute('startFilePos');
$function_end = (int)$stmt->getAttribute('endFilePos');
foreach ($stmt->params as $param) {
if ($param->var instanceof PhpParser\Node\Expr\Variable
&& \is_string($param->var->name)
) {
$this->param_offsets[$param->var->name] = (int) $param->var->getAttribute('startFilePos');
if ($param->type) {
$this->param_typehint_offsets[$param->var->name] = [
(int) $param->type->getAttribute('startFilePos'),
(int) $param->type->getAttribute('endFilePos')
];
}
}
}
$codebase = $project_analyzer->getCodebase();
$file_contents = $codebase->getFileContents($file_path);
@ -273,16 +291,22 @@ class FunctionDocblockManipulator
*
* @return void
*/
public function setParamType($param_name, $php_type, $new_type, $phpdoc_type, $is_php_compatible)
{
public function setParamType(
string $param_name,
?string $php_type,
string $new_type,
string $phpdoc_type
) {
$new_type = str_replace(['<mixed, mixed>', '<array-key, mixed>', '<empty, empty>'], '', $new_type);
if ($php_type) {
$this->new_php_param_types[$param_name] = $php_type;
}
$this->new_phpdoc_param_types[$param_name] = $phpdoc_type;
$this->new_psalm_param_types[$param_name] = $new_type;
$this->param_type_is_php_compatible[$param_name] = $is_php_compatible;
if ($php_type !== $new_type) {
$this->new_phpdoc_param_types[$param_name] = $phpdoc_type;
$this->new_psalm_param_types[$param_name] = $new_type;
}
}
/**
@ -333,6 +357,10 @@ class FunctionDocblockManipulator
$parsed_docblock['specials']['psalm-return'] = [$this->new_psalm_return_type];
}
if (!$parsed_docblock['specials'] && !$parsed_docblock['description']) {
return '';
}
return DocComment::render($parsed_docblock, $this->indentation);
}
@ -387,6 +415,40 @@ class FunctionDocblockManipulator
$manipulator->getDocblock()
);
}
foreach ($manipulator->new_php_param_types as $param_name => $new_php_param_type) {
if (!isset($manipulator->param_offsets[$param_name])) {
continue;
}
$param_offset = $manipulator->param_offsets[$param_name];
$typehint_offsets = $manipulator->param_typehint_offsets[$param_name] ?? null;
if ($new_php_param_type) {
if ($typehint_offsets) {
$file_manipulations[$typehint_offsets[0]] = new FileManipulation(
$typehint_offsets[0],
$typehint_offsets[1],
$new_php_param_type
);
} else {
$file_manipulations[$param_offset] = new FileManipulation(
$param_offset,
$param_offset,
$new_php_param_type . ' '
);
}
} elseif ($new_php_param_type === ''
&& $typehint_offsets
) {
$file_manipulations[$typehint_offsets[0]] = new FileManipulation(
$typehint_offsets[0],
$param_offset,
''
);
}
}
}
return $file_manipulations;

View File

@ -62,6 +62,23 @@ class ParamTypeManipulationTest extends FileManipulationTest
true,
],
'noStringParamType' => [
'<?php
class C {
public function fooFoo($a): void {}
}
(new C)->fooFoo("hello");',
'<?php
class C {
public function fooFoo(string $a): void {}
}
(new C)->fooFoo("hello");',
'7.1',
['MissingParamType'],
true,
],
'noStringParamType56' => [
'<?php
class C {
public function fooFoo($a): void {}
@ -77,7 +94,7 @@ class ParamTypeManipulationTest extends FileManipulationTest
}
(new C)->fooFoo("hello");',
'7.1',
'5.6',
['MissingParamType'],
true,
],
@ -90,10 +107,7 @@ class ParamTypeManipulationTest extends FileManipulationTest
(new C)->fooFoo(false);',
'<?php
class C {
/**
* @param bool $a
*/
public function fooFoo($a = true): void {}
public function fooFoo(bool $a = true): void {}
}
(new C)->fooFoo(false);',
@ -112,10 +126,7 @@ class ParamTypeManipulationTest extends FileManipulationTest
(new D)->fooFoo("hello");',
'<?php
class C {
/**
* @param string $a
*/
public function fooFoo($a): void {}
public function fooFoo(string $a): void {}
}
class D extends C {}