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:
parent
dd05f6e3ca
commit
97de060df9
@ -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()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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 {}
|
||||
|
Loading…
Reference in New Issue
Block a user