Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
"Rector\\Renaming\\": "rules/renaming/src",
"Rector\\Restoration\\": "rules/restoration/src",
"Rector\\SOLID\\": "rules/solid/src",
"Rector\\NodeNestingScope\\": "packages/node-nesting-scope/src",
"Rector\\Sensio\\": "rules/sensio/src",
"Rector\\Shopware\\": "rules/shopware/src",
"Rector\\Silverstripe\\": "rules/silverstripe/src",
Expand Down
28 changes: 27 additions & 1 deletion docs/AllRectorsOverview.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# All 482 Rectors Overview
# All 483 Rectors Overview

- [Projects](#projects)
- [General](#general)
Expand Down Expand Up @@ -3001,6 +3001,32 @@ Remove unreachable statements

<br>

### `RemoveUnusedAssignVariableRector`

- class: [`Rector\DeadCode\Rector\Assign\RemoveUnusedAssignVariableRector`](/../master/rules/dead-code/src/Rector/Assign/RemoveUnusedAssignVariableRector.php)
- [test fixtures](/../master/rules/dead-code/tests/Rector/Assign/RemoveUnusedAssignVariableRector/Fixture)

Remove assigned unused variable

```diff
class SomeClass
{
public function run()
{
- $value = $this->process();
+ $this->process();
}

public function process()
{
// something going on
return 5;
}
}
```

<br>

### `RemoveUnusedClassConstantRector`

- class: [`Rector\DeadCode\Rector\ClassConst\RemoveUnusedClassConstantRector`](/../master/rules/dead-code/src/Rector/ClassConst/RemoveUnusedClassConstantRector.php)
Expand Down
8 changes: 8 additions & 0 deletions packages/node-nesting-scope/config/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
services:
_defaults:
public: true
autowire: true
autoconfigure: true

Rector\NodeNestingScope\:
resource: '../src'
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Rector\DeadCode;
namespace Rector\NodeNestingScope;

use PhpParser\Node;
use PhpParser\Node\FunctionLike;
Expand Down
26 changes: 26 additions & 0 deletions packages/node-nesting-scope/src/ParentScopeFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Rector\NodeNestingScope;

use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Namespace_;
use Rector\NodeTypeResolver\Node\AttributeKey;

final class ParentScopeFinder
{
/**
* @return ClassMethod|Function_|Class_|Namespace_|null
*/
public function find(Node $node): ?Node
{
return $node->getAttribute(AttributeKey::METHOD_NODE)
?? $node->getAttribute(AttributeKey::FUNCTION_NODE)
?? $node->getAttribute(AttributeKey::CLASS_NODE)
?? $node->getAttribute(AttributeKey::NAMESPACE_NODE);
}
}
60 changes: 60 additions & 0 deletions packages/node-nesting-scope/src/ScopeNestingComparator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace Rector\NodeNestingScope;

use PhpParser\Node;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\Case_;
use PhpParser\Node\Stmt\Catch_;
use PhpParser\Node\Stmt\Do_;
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\ElseIf_;
use PhpParser\Node\Stmt\For_;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\While_;
use Rector\Core\PhpParser\Node\BetterNodeFinder;

final class ScopeNestingComparator
{
/**
* @var class-string[]
*/
private const CONTROL_STRUCTURE_NODES = [
For_::class,
Foreach_::class,
If_::class,
While_::class,
Do_::class,
Else_::class,
ElseIf_::class,
Catch_::class,
Case_::class,
FunctionLike::class,
];

/**
* @var BetterNodeFinder
*/
private $betterNodeFinder;

public function __construct(BetterNodeFinder $betterNodeFinder)
{
$this->betterNodeFinder = $betterNodeFinder;
}

public function areScopeNestingEqual(Node $firstNode, Node $secondNode): bool
{
$firstNodeScopeNode = $this->findParentControlStructure($firstNode);
$secondNodeScopeNode = $this->findParentControlStructure($secondNode);

return $firstNodeScopeNode === $secondNodeScopeNode;
}

private function findParentControlStructure(Node $node): ?Node
{
return $this->betterNodeFinder->findFirstParentInstanceOf($node, self::CONTROL_STRUCTURE_NODES);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeNestingScope\ParentScopeFinder;
use Rector\NodeTypeResolver\Node\AttributeKey;

final class PregMatchTypeCorrector
Expand All @@ -33,14 +34,21 @@ final class PregMatchTypeCorrector
*/
private $betterStandardPrinter;

/**
* @var ParentScopeFinder
*/
private $parentScopeFinder;

public function __construct(
BetterNodeFinder $betterNodeFinder,
NodeNameResolver $nodeNameResolver,
BetterStandardPrinter $betterStandardPrinter
BetterStandardPrinter $betterStandardPrinter,
ParentScopeFinder $parentScopeFinder
) {
$this->betterNodeFinder = $betterNodeFinder;
$this->nodeNameResolver = $nodeNameResolver;
$this->betterStandardPrinter = $betterStandardPrinter;
$this->parentScopeFinder = $parentScopeFinder;
}

/**
Expand Down Expand Up @@ -93,8 +101,7 @@ public function correct(Node $node, Type $originalType): Type
*/
private function getVariableUsages(Variable $variable): array
{
$scope = $this->getScopeNode($variable);

$scope = $this->parentScopeFinder->find($variable);
if ($scope === null) {
return [];
}
Expand All @@ -103,11 +110,4 @@ private function getVariableUsages(Variable $variable): array
return $node instanceof Variable && $node->name === $variable->name;
});
}

private function getScopeNode(Node $node): ?Node
{
return $node->getAttribute(AttributeKey::METHOD_NODE)
?? $node->getAttribute(AttributeKey::FUNCTION_NODE)
?? $node->getAttribute(AttributeKey::NAMESPACE_NODE);
}
}
10 changes: 4 additions & 6 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,6 @@ parameters:
# node finder
- '#Method Rector\\(.*?) should return array<PhpParser\\Node\\(.*?)> but returns array<PhpParser\\Node\>#'

# known values
- '#Parameter \#2 \$variableName of class Rector\\DeadCode\\Data\\VariableNodeUseInfo constructor expects string, string\|null given#'
- '#Cannot call method getParentNode\(\) on Rector\\DeadCode\\Data\\VariableNodeUseInfo\|null#'

# part of test
- '#(.*?)(AttributeAwareNodeInterface|AttributeAware(.*?)TagValueNode)(.*?)#'

Expand Down Expand Up @@ -255,10 +251,12 @@ parameters:
- '#Method Rector\\BetterPhpDocParser\\AnnotationReader\\NodeAnnotationReader\:\:createClassReflectionFromNode\(\) return type with generic class ReflectionClass does not specify its types\: T#'
- '#Method Rector\\NodeCollector\\StaticAnalyzer\:\:hasStaticAnnotation\(\) has parameter \$reflectionClass with generic class ReflectionClass but does not specify its types\: T#'

- '#Method Rector\\BetterPhpDocParser\\AnnotationReader\\AnnotationReaderFactory\:\:create\(\) should return Doctrine\\Common\\Annotations\\Reader but returns Doctrine\\Common\\Annotations\\AnnotationReader\|Rector\\DoctrineAnnotationGenerated\\ConstantPreservingAnnotationReader#'

# mixed
- '#Property Rector\\Polyfill\\ValueObject\\BinaryToVersionCompareCondition\:\:\$expectedValue has no typehint specified#'
# node finder
- '#Method Rector\\Core\\PhpParser\\Node\\Manipulator\\MethodCallManipulator\:\:findAssignToVariableName\(\) should return PhpParser\\Node\\Expr\\Assign\|null but returns PhpParser\\Node\|null#'

# broken
- '#Cannot call method getParentNode\(\) on Rector\\DeadCode\\ValueObject\\VariableNodeUse\|null#'
- '#Method Rector\\DeadCode\\NodeFinder\\PreviousVariableAssignNodeFinder\:\:find\(\) should return PhpParser\\Node\\Expr\\Assign\|null but returns PhpParser\\Node\|null#'
- '#Parameter \#2 \$name of method Rector\\NodeNameResolver\\NodeNameResolver\:\:isName\(\) expects string, string\|null given#'
2 changes: 1 addition & 1 deletion rules/dead-code/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ services:
resource: '../src'
exclude:
- '../src/Rector/**/*Rector.php'
- '../src/Data/*'
- '../src/ValueObject/*'
83 changes: 83 additions & 0 deletions rules/dead-code/src/NodeFinder/NextVariableUsageNodeFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

declare(strict_types=1);

namespace Rector\DeadCode\NodeFinder;

use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\NodeTraverser;
use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\NodeNestingScope\ParentScopeFinder;
use Rector\NodeTypeResolver\Node\AttributeKey;

final class NextVariableUsageNodeFinder
{
/**
* @var CallableNodeTraverser
*/
private $callableNodeTraverser;

/**
* @var BetterStandardPrinter
*/
private $betterStandardPrinter;

/**
* @var ParentScopeFinder
*/
private $parentScopeFinder;

public function __construct(
ParentScopeFinder $parentScopeFinder,
CallableNodeTraverser $callableNodeTraverser,
BetterStandardPrinter $betterStandardPrinter
) {
$this->callableNodeTraverser = $callableNodeTraverser;
$this->betterStandardPrinter = $betterStandardPrinter;
$this->parentScopeFinder = $parentScopeFinder;
}

public function find(Assign $assign): ?Node
{
$scopeNode = $this->parentScopeFinder->find($assign);
if ($scopeNode === null) {
return null;
}

$expr = $assign->var;

$this->callableNodeTraverser->traverseNodesWithCallable((array) $scopeNode->stmts, function (Node $currentNode) use (
$expr,
&$nextUsageOfVariable
) {
// used above the assign
if ($currentNode->getStartTokenPos() < $expr->getStartTokenPos()) {
return null;
}

// skip self
if ($currentNode === $expr) {
return null;
}

if (! $this->betterStandardPrinter->areNodesEqual($currentNode, $expr)) {
return null;
}

$currentNodeParent = $currentNode->getAttribute(AttributeKey::PARENT_NODE);

// stop at next assign
if ($currentNodeParent instanceof Assign) {
return NodeTraverser::STOP_TRAVERSAL;
}

$nextUsageOfVariable = $currentNode;

return NodeTraverser::STOP_TRAVERSAL;
});

return $nextUsageOfVariable;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace Rector\DeadCode\NodeFinder;

use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeNameResolver\NodeNameResolver;

final class PreviousVariableAssignNodeFinder
{
/**
* @var BetterNodeFinder
*/
private $betterNodeFinder;

/**
* @var NodeNameResolver
*/
private $nodeNameResolver;

public function __construct(BetterNodeFinder $betterNodeFinder, NodeNameResolver $nodeNameResolver)
{
$this->betterNodeFinder = $betterNodeFinder;
$this->nodeNameResolver = $nodeNameResolver;
}

public function find(Assign $assign): ?Assign
{
$currentAssign = $assign;
$variableName = $this->nodeNameResolver->getName($assign->var);

return $this->betterNodeFinder->findFirstPrevious($assign, function (Node $node) use (
$variableName,
$currentAssign
): bool {
if (! $node instanceof Assign) {
return false;
}

// skil self
if ($node === $currentAssign) {
return false;
}

return $this->nodeNameResolver->isName($node->var, $variableName);
});
}
}
Loading