Skip to content
Permalink
Browse files

Fix #2279 - add parameter typehint by default

  • Loading branch information
muglug committed Dec 3, 2019
1 parent dd05f6e commit 97de060df935032b23b795983fedbfd69dcf05e2
@@ -1295,9 +1295,27 @@ public function addOrUpdateParamType(
$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 @@ public function addOrUpdateParamType(
$this->source->getAliasedClassesFlipped(),
$this->source->getFQCLN(),
true
),
$inferred_return_type->canBeFullyExpressedInPhp()
)
);
}

@@ -1957,7 +1957,8 @@ private function findPossibleMethodParamTypes(ClassLikeStorage $classlike_storag
$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 @@ private function __construct($file_path, FunctionLike $stmt, ProjectAnalyzer $pr
$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 @@ public function setReturnType($php_type, $new_type, $phpdoc_type, $is_php_compat
*
* @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 @@ private function getDocblock()
$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 @@ public static function getManipulationsForFile($file_path)
$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 C {}
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 @@ public function fooFoo($a): void {}
}
(new C)->fooFoo("hello");',
'7.1',
'5.6',
['MissingParamType'],
true,
],
@@ -90,10 +107,7 @@ public function fooFoo($a = true): void {}
(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 D extends C {}
(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 {}

0 comments on commit 97de060

Please sign in to comment.
You can’t perform that action at this time.