Skip to content

Commit b5f2a33

Browse files
committed
fix(RenameGarbageParamName): Improve detection of unused variables in function bodies
- Update the isUsedVariable method to consider functions with only Nop statements as having no relevant code - Enhance code readability and accuracy in identifying unused parameters - Prevent false positives in parameter renaming by better handling of empty or no-operation functions
1 parent 200f20a commit b5f2a33

File tree

5 files changed

+76
-5
lines changed

5 files changed

+76
-5
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@
373373
"ls -lr builds/rector-rules.phar"
374374
],
375375
"rector-rules:list-files": "Guanguans\\RectorRules\\Support\\ComposerScripts::listFiles",
376+
"rector-rules:phpdoc-parse": "Guanguans\\RectorRules\\Support\\ComposerScripts::phpdocParse",
376377
"rector:custom-rule": "@rector custom-rule",
377378
"rector:list-rules": "@rector list-rules",
378379
"rector:process": "@rector process --ansi",

phpstan.neon.dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ parameters:
130130
- identifier: argument.type
131131
- identifier: cast.int
132132
# - identifier: cast.string
133-
- identifier: empty.notAllowed
133+
# - identifier: empty.notAllowed
134134
- identifier: encapsedStringPart.nonString
135135
- identifier: method.childParameterType
136136
- identifier: return.type

src/Rector/FunctionLike/RenameGarbageParamNameRector.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use PhpParser\Node\Param;
2828
use PhpParser\Node\Stmt\ClassMethod;
2929
use PhpParser\Node\Stmt\Foreach_;
30+
use PhpParser\Node\Stmt\Nop;
3031
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
3132
use PHPStan\Reflection\ClassReflection;
3233
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
@@ -268,7 +269,11 @@ private function hasPrototypeMethod(FunctionLike $functionLikeNode): bool
268269
private function isUsedVariable(FunctionLike $node, Variable $variableNode): bool
269270
{
270271
// Skip abstract, interface, empty body function like and foreach.
271-
if (property_exists($node, 'stmts') && empty($node->stmts)) {
272+
if (
273+
property_exists($node, 'stmts') && collect($node->stmts)->every(
274+
static fn (Node $stmtNode): bool => $stmtNode instanceof Nop
275+
)
276+
) {
272277
return true;
273278
}
274279

src/Support/ComposerScripts.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,17 @@
1919
use Composer\Script\Event;
2020
use Illuminate\Support\Collection;
2121
use Illuminate\Support\Str;
22+
use PhpParser\Comment\Doc;
23+
use PhpParser\Node\Stmt\Nop;
24+
use PHPStan\PhpDocParser\Ast\AbstractNodeVisitor;
25+
use PHPStan\PhpDocParser\Ast\Attribute;
26+
use PHPStan\PhpDocParser\Ast\Node;
27+
use PHPStan\PhpDocParser\Ast\NodeTraverser;
28+
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
29+
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
2230
use Rector\Config\RectorConfig;
2331
use Rector\DependencyInjection\LazyContainerFactory;
32+
use Rector\PhpParser\Parser\SimplePhpParser;
2433
use Symfony\Component\Console\Application;
2534
use Symfony\Component\Console\Input\ArgvInput;
2635
use Symfony\Component\Console\Input\InputDefinition;
@@ -46,6 +55,8 @@ private function __construct() {}
4655

4756
/**
4857
* @see https://github.com/rectorphp/rector-src/blob/main/scoper.php
58+
* @see \PhpParser\Builder\
59+
* @see \PhpParser\BuilderHelpers
4960
* @see \Rector\Application\ChangedNodeScopeRefresher
5061
* @see \Rector\BetterPhpDocParser\Comment\CommentsMerger
5162
* @see \Rector\BetterPhpDocParser\PhpDocManipulator\
@@ -116,6 +127,52 @@ classes(
116127
return 0;
117128
}
118129

130+
/**
131+
*@see vendor/nikic/php-parser/bin/php-parse
132+
*
133+
* @throws \Illuminate\Contracts\Container\BindingResolutionException
134+
*
135+
* @noinspection ForgottenDebugOutputInspection
136+
* @noinspection DebugFunctionUsageInspection
137+
* @noinspection PhpVoidFunctionResultUsedInspection
138+
*/
139+
public static function phpdocParse(Event $event): void
140+
{
141+
self::requireAutoload($event);
142+
143+
$rectorConfig = self::makeRectorConfig();
144+
$path = self::makeArgvInput()->getParameterOption('--path', false, true);
145+
146+
if ($path) {
147+
$node = $rectorConfig->make(SimplePhpParser::class)->parseFile($path)[0];
148+
} else {
149+
do {
150+
$docComment = $event->getIO()->ask(\sprintf('Please provide a doc comment to parse:%s', \PHP_EOL));
151+
} while (blank($docComment));
152+
153+
$node = tap(new Nop)->setDocComment(new Doc($docComment));
154+
}
155+
156+
$phpDocNode = $rectorConfig->make(PhpDocInfoFactory::class)->createFromNodeOrEmpty($node)->getPhpDocNode();
157+
(new NodeTraverser([
158+
new class extends AbstractNodeVisitor {
159+
/**
160+
* @noinspection PhpMissingParentCallCommonInspection
161+
*/
162+
public function enterNode(Node $node): Node
163+
{
164+
// $node->setAttribute(Attribute::ORIGINAL_NODE, null);
165+
$node->setAttribute(PhpDocAttributeKey::ORIG_NODE, null);
166+
$node->setAttribute(PhpDocAttributeKey::PARENT, null);
167+
168+
return $node;
169+
}
170+
},
171+
]))->traverse($phpDocNode->children);
172+
173+
dump($phpDocNode, (string) $phpDocNode);
174+
}
175+
119176
public static function makeRectorConfig(): RectorConfig
120177
{
121178
static $rectorConfig;

tests/Rector/FunctionLike/RenameGarbageParamNameRector/Fixture/skips.php.inc

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
<?php
22

33
/** @noinspection ALL */
4+
5+
use PhpParser\Node;
6+
use Rector\Rector\AbstractRector;
7+
use Symfony\Component\OptionsResolver\OptionsResolver as OptionsResolver;
8+
49
abstract class Foo
510
{
611
// Skip abstract method.
712
abstract public function run($param): void;
13+
14+
// Skip nop method.
15+
protected function configureOptionsResolver(OptionsResolver $optionsResolver): void
16+
{
17+
// Configure options resolver...
18+
}
819
}
920

1021
interface Bar
@@ -13,9 +24,6 @@ interface Bar
1324
public function run($param): void;
1425
}
1526

16-
use PhpParser\Node;
17-
use Rector\Rector\AbstractRector;
18-
1927
final class FooRector extends AbstractRector
2028
{
2129
// Skip has prototype method.

0 commit comments

Comments
 (0)