2020-08-14 21:25:21 +02:00
|
|
|
<?php
|
|
|
|
namespace Psalm\Internal\PhpVisitor;
|
|
|
|
|
|
|
|
use PhpParser;
|
|
|
|
use Psalm\FileManipulation;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*/
|
2020-10-15 19:23:35 +02:00
|
|
|
class ParamReplacementVisitor extends PhpParser\NodeVisitorAbstract
|
2020-08-14 21:25:21 +02:00
|
|
|
{
|
|
|
|
/** @var string */
|
|
|
|
private $old_name;
|
|
|
|
|
|
|
|
/** @var string */
|
|
|
|
private $new_name;
|
|
|
|
|
|
|
|
/** @var list<FileManipulation> */
|
|
|
|
private $replacements = [];
|
|
|
|
|
|
|
|
/** @var bool */
|
|
|
|
private $new_name_replaced = false;
|
|
|
|
|
|
|
|
/** @var bool */
|
|
|
|
private $new_new_name_used = false;
|
|
|
|
|
|
|
|
public function __construct(string $old_name, string $new_name)
|
|
|
|
{
|
|
|
|
$this->old_name = $old_name;
|
|
|
|
$this->new_name = $new_name;
|
|
|
|
}
|
|
|
|
|
2020-09-13 22:39:06 +02:00
|
|
|
public function enterNode(PhpParser\Node $node): ?int
|
2020-08-14 21:25:21 +02:00
|
|
|
{
|
|
|
|
if ($node instanceof PhpParser\Node\Expr\Variable) {
|
|
|
|
if ($node->name === $this->old_name) {
|
|
|
|
$this->replacements[] = new FileManipulation(
|
|
|
|
(int) $node->getAttribute('startFilePos') + 1,
|
|
|
|
(int) $node->getAttribute('endFilePos') + 1,
|
|
|
|
$this->new_name
|
|
|
|
);
|
|
|
|
} elseif ($node->name === $this->new_name) {
|
|
|
|
if ($this->new_new_name_used) {
|
|
|
|
$this->replacements = [];
|
|
|
|
return PhpParser\NodeTraverser::STOP_TRAVERSAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->replacements[] = new FileManipulation(
|
|
|
|
(int) $node->getAttribute('startFilePos') + 1,
|
|
|
|
(int) $node->getAttribute('endFilePos') + 1,
|
|
|
|
$this->new_name . '_new'
|
|
|
|
);
|
|
|
|
|
|
|
|
$this->new_name_replaced = true;
|
|
|
|
} elseif ($node->name === $this->new_name . '_new') {
|
|
|
|
if ($this->new_name_replaced) {
|
|
|
|
$this->replacements = [];
|
|
|
|
return PhpParser\NodeTraverser::STOP_TRAVERSAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->new_new_name_used = true;
|
|
|
|
}
|
2020-08-14 22:26:55 +02:00
|
|
|
} elseif ($node instanceof PhpParser\Node\Stmt\ClassMethod
|
|
|
|
&& ($docblock = $node->getDocComment())
|
|
|
|
) {
|
|
|
|
$parsed_docblock = \Psalm\Internal\Scanner\DocblockParser::parse($docblock->getText());
|
|
|
|
|
|
|
|
$replaced = false;
|
|
|
|
|
|
|
|
foreach ($parsed_docblock->tags as $tag_name => $tags) {
|
|
|
|
foreach ($tags as $i => $tag) {
|
|
|
|
if ($tag_name === 'param'
|
|
|
|
|| $tag_name === 'psalm-param'
|
|
|
|
|| $tag_name === 'phpstan-param'
|
|
|
|
|| $tag_name === 'phan-param'
|
|
|
|
) {
|
|
|
|
$parts = \Psalm\Internal\Analyzer\CommentAnalyzer::splitDocLine($tag);
|
|
|
|
|
|
|
|
if (($parts[1] ?? '') === '$' . $this->old_name) {
|
|
|
|
$parsed_docblock->tags[$tag_name][$i] = \str_replace(
|
|
|
|
'$' . $this->old_name,
|
|
|
|
'$' . $this->new_name,
|
|
|
|
$tag
|
|
|
|
);
|
|
|
|
$replaced = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($replaced) {
|
|
|
|
$this->replacements[] = new FileManipulation(
|
2020-09-20 14:56:49 +02:00
|
|
|
$docblock->getStartFilePos(),
|
|
|
|
$docblock->getStartFilePos() + \strlen($docblock->getText()),
|
2020-08-14 22:26:55 +02:00
|
|
|
\rtrim($parsed_docblock->render($parsed_docblock->first_line_padding)),
|
|
|
|
false,
|
|
|
|
false
|
|
|
|
);
|
|
|
|
}
|
2020-08-14 21:25:21 +02:00
|
|
|
}
|
2020-09-13 22:39:06 +02:00
|
|
|
|
|
|
|
return null;
|
2020-08-14 21:25:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return list<FileManipulation>
|
|
|
|
*/
|
2020-09-12 17:24:05 +02:00
|
|
|
public function getReplacements(): array
|
2020-08-14 21:25:21 +02:00
|
|
|
{
|
|
|
|
return $this->replacements;
|
|
|
|
}
|
|
|
|
}
|