mirror of
https://github.com/rectorphp/rector.git
synced 2024-05-30 07:50:53 +00:00
[DeadCode] Add RemoveUnusedAssignVariableRector
This commit is contained in:
parent
d254821f7a
commit
a7f5abe2f1
|
@ -1,4 +1,4 @@
|
|||
# All 482 Rectors Overview
|
||||
# All 483 Rectors Overview
|
||||
|
||||
- [Projects](#projects)
|
||||
- [General](#general)
|
||||
|
@ -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)
|
||||
|
|
|
@ -13,6 +13,7 @@ use PHPStan\Type\MixedType;
|
|||
use PHPStan\Type\Type;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
|
||||
use Rector\DeadCode\ScopeNesting\ParentScopeFinder;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,8 +101,7 @@ final class PregMatchTypeCorrector
|
|||
*/
|
||||
private function getVariableUsages(Variable $variable): array
|
||||
{
|
||||
$scope = $this->getScopeNode($variable);
|
||||
|
||||
$scope = $this->parentScopeFinder->find($variable);
|
||||
if ($scope === null) {
|
||||
return [];
|
||||
}
|
||||
|
@ -103,11 +110,4 @@ final class PregMatchTypeCorrector
|
|||
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
phpstan.neon
10
phpstan.neon
|
@ -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)(.*?)#'
|
||||
|
||||
|
@ -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#'
|
||||
|
|
|
@ -7,4 +7,4 @@ services:
|
|||
resource: '../src'
|
||||
exclude:
|
||||
- '../src/Rector/**/*Rector.php'
|
||||
- '../src/Data/*'
|
||||
- '../src/ValueObject/*'
|
||||
|
|
|
@ -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\DeadCode\ScopeNesting\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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -12,18 +12,11 @@ use PhpParser\Node\Expr\PropertyFetch;
|
|||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Expr\StaticPropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
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\Expression;
|
||||
use PhpParser\Node\Stmt\Foreach_;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
use PhpParser\Node\Stmt\While_;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\DeadCode\ScopeNesting\ScopeNestingComparator;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
/**
|
||||
|
@ -32,18 +25,14 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
|
|||
final class RemoveDoubleAssignRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
* @var ScopeNestingComparator
|
||||
*/
|
||||
private const CONTROL_STRUCTURE_NODES = [
|
||||
Foreach_::class,
|
||||
If_::class,
|
||||
While_::class,
|
||||
Do_::class,
|
||||
Else_::class,
|
||||
ElseIf_::class,
|
||||
Catch_::class,
|
||||
Case_::class,
|
||||
];
|
||||
private $scopeNestingComparator;
|
||||
|
||||
public function __construct(ScopeNestingComparator $scopeNestingComparator)
|
||||
{
|
||||
$this->scopeNestingComparator = $scopeNestingComparator;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
|
@ -113,11 +102,7 @@ PHP
|
|||
return true;
|
||||
}
|
||||
|
||||
if ($this->shouldSkipDueToForeachOverride($assign, $anotherNode)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->shouldSkipForDifferenceParent($assign, $anotherNode);
|
||||
return ! $this->scopeNestingComparator->areScopeNestingEqual($assign, $anotherNode);
|
||||
}
|
||||
|
||||
private function isSelfReferencing(Assign $assign): bool
|
||||
|
@ -134,33 +119,4 @@ PHP
|
|||
$previousExpression->getAttribute(AttributeKey::METHOD_NODE)
|
||||
);
|
||||
}
|
||||
|
||||
private function shouldSkipDueToForeachOverride(Assign $assign, Node $node): bool
|
||||
{
|
||||
// is nested in a foreach and the previous expression is not?
|
||||
$nodePreviousForeach = $this->betterNodeFinder->findFirstParentInstanceOf($assign, Foreach_::class);
|
||||
|
||||
$previousExpressionPreviousForeach = $this->betterNodeFinder->findFirstParentInstanceOf(
|
||||
$node,
|
||||
Foreach_::class
|
||||
);
|
||||
return $nodePreviousForeach !== $previousExpressionPreviousForeach;
|
||||
}
|
||||
|
||||
private function shouldSkipForDifferenceParent(Node $firstNode, Node $secondNode): bool
|
||||
{
|
||||
$firstNodeParent = $this->findParentControlStructure($firstNode);
|
||||
$secondNodeParent = $this->findParentControlStructure($secondNode);
|
||||
|
||||
if ($firstNodeParent === null || $secondNodeParent === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! $this->areNodesEqual($firstNodeParent, $secondNodeParent);
|
||||
}
|
||||
|
||||
private function findParentControlStructure(Node $node): ?Node
|
||||
{
|
||||
return $this->betterNodeFinder->findFirstParentInstanceOf($node, self::CONTROL_STRUCTURE_NODES);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Rector\Assign;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\DeadCode\NodeFinder\NextVariableUsageNodeFinder;
|
||||
use Rector\DeadCode\NodeFinder\PreviousVariableAssignNodeFinder;
|
||||
use Rector\DeadCode\ScopeNesting\ScopeNestingComparator;
|
||||
use Rector\DeadCode\SideEffect\SideEffectNodeDetector;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
/**
|
||||
* @see \Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\RemoveUnusedAssignVariableRectorTest
|
||||
*/
|
||||
final class RemoveUnusedAssignVariableRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var SideEffectNodeDetector
|
||||
*/
|
||||
private $sideEffectNodeDetector;
|
||||
|
||||
/**
|
||||
* @var PreviousVariableAssignNodeFinder
|
||||
*/
|
||||
private $previousVariableAssignNodeFinder;
|
||||
|
||||
/**
|
||||
* @var ScopeNestingComparator
|
||||
*/
|
||||
private $scopeNestingComparator;
|
||||
|
||||
/**
|
||||
* @var NextVariableUsageNodeFinder
|
||||
*/
|
||||
private $nextVariableUsageNodeFinder;
|
||||
|
||||
public function __construct(
|
||||
SideEffectNodeDetector $sideEffectNodeDetector,
|
||||
PreviousVariableAssignNodeFinder $previousVariableAssignNodeFinder,
|
||||
ScopeNestingComparator $scopeNestingComparator,
|
||||
NextVariableUsageNodeFinder $nextVariableUsageNodeFinder
|
||||
) {
|
||||
$this->sideEffectNodeDetector = $sideEffectNodeDetector;
|
||||
$this->previousVariableAssignNodeFinder = $previousVariableAssignNodeFinder;
|
||||
$this->scopeNestingComparator = $scopeNestingComparator;
|
||||
$this->nextVariableUsageNodeFinder = $nextVariableUsageNodeFinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Assign::class];
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Remove assigned unused variable', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$value = $this->process();
|
||||
}
|
||||
|
||||
public function process()
|
||||
{
|
||||
// something going on
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$this->process();
|
||||
}
|
||||
|
||||
public function process()
|
||||
{
|
||||
// something going on
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Assign $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if ($this->shouldSkipAssign($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->isVariableTypeInScope($node) && ! $this->isPreviousVariablePartOfOverridingAssign($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// is scalar assign? remove whole
|
||||
if (! $this->sideEffectNodeDetector->detect($node->expr)) {
|
||||
$this->removeNode($node);
|
||||
return null;
|
||||
}
|
||||
|
||||
return $node->expr;
|
||||
}
|
||||
|
||||
private function shouldSkipAssign(Assign $assign): bool
|
||||
{
|
||||
if (! $assign->var instanceof Variable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// unable to resolve name
|
||||
$variableName = $this->getName($assign->var);
|
||||
if ($variableName === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->isNestedAssign($assign)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$nextUsedVariable = $this->nextVariableUsageNodeFinder->find($assign);
|
||||
return $nextUsedVariable !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nested assign, e.g "$oldValues = <$values> = 5;"
|
||||
*/
|
||||
private function isNestedAssign(Assign $assign): bool
|
||||
{
|
||||
$parentNode = $assign->getAttribute(AttributeKey::PARENT_NODE);
|
||||
return $parentNode instanceof Assign;
|
||||
}
|
||||
|
||||
private function isPreviousVariablePartOfOverridingAssign(Assign $assign): bool
|
||||
{
|
||||
// is previous variable node as part of assign?
|
||||
$previousVariableAssign = $this->previousVariableAssignNodeFinder->find($assign);
|
||||
if ($previousVariableAssign === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->scopeNestingComparator->areScopeNestingEqual($assign, $previousVariableAssign);
|
||||
}
|
||||
|
||||
private function isVariableTypeInScope(Assign $assign): bool
|
||||
{
|
||||
/** @var Scope|null $scope */
|
||||
$scope = $assign->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $scope instanceof Scope) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var string $variableName */
|
||||
$variableName = $this->getName($assign->var);
|
||||
|
||||
return ! $scope->hasVariableType($variableName)->no();
|
||||
}
|
||||
}
|
|
@ -12,8 +12,8 @@ use Rector\Core\Context\ContextAnalyzer;
|
|||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\DeadCode\Data\VariableNodeUseInfo;
|
||||
use Rector\DeadCode\FlowOfControlLocator;
|
||||
use Rector\DeadCode\ScopeNesting\FlowOfControlLocator;
|
||||
use Rector\DeadCode\ValueObject\VariableNodeUse;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
/**
|
||||
|
@ -180,7 +180,7 @@ PHP
|
|||
/**
|
||||
* @param Variable[] $assignedVariables
|
||||
* @param Variable[] $assignedVariablesUse
|
||||
* @return VariableNodeUseInfo[]
|
||||
* @return VariableNodeUse[]
|
||||
*/
|
||||
private function collectNodesByTypeAndPosition(
|
||||
array $assignedVariables,
|
||||
|
@ -199,10 +199,13 @@ PHP
|
|||
$assignNode = $assignedVariable->getAttribute(AttributeKey::PARENT_NODE);
|
||||
$nestingHash = $this->flowOfControlLocator->resolveNestingHashFromFunctionLike($functionLike, $assignNode);
|
||||
|
||||
$nodesByTypeAndPosition[] = new VariableNodeUseInfo(
|
||||
/** @var string $variableName */
|
||||
$variableName = $this->getName($assignedVariable);
|
||||
|
||||
$nodesByTypeAndPosition[] = new VariableNodeUse(
|
||||
$startTokenPos,
|
||||
$this->getName($assignedVariable),
|
||||
VariableNodeUseInfo::TYPE_ASSIGN,
|
||||
$variableName,
|
||||
VariableNodeUse::TYPE_ASSIGN,
|
||||
$assignedVariable,
|
||||
$nestingHash
|
||||
);
|
||||
|
@ -212,10 +215,13 @@ PHP
|
|||
/** @var int $startTokenPos */
|
||||
$startTokenPos = $assignedVariableUse->getAttribute(AttributeKey::START_TOKEN_POSITION);
|
||||
|
||||
$nodesByTypeAndPosition[] = new VariableNodeUseInfo(
|
||||
/** @var string $variableName */
|
||||
$variableName = $this->getName($assignedVariableUse);
|
||||
|
||||
$nodesByTypeAndPosition[] = new VariableNodeUse(
|
||||
$startTokenPos,
|
||||
$this->getName($assignedVariableUse),
|
||||
VariableNodeUseInfo::TYPE_USE,
|
||||
$variableName,
|
||||
VariableNodeUse::TYPE_USE,
|
||||
$assignedVariableUse
|
||||
);
|
||||
}
|
||||
|
@ -223,11 +229,8 @@ PHP
|
|||
// sort
|
||||
usort(
|
||||
$nodesByTypeAndPosition,
|
||||
function (
|
||||
VariableNodeUseInfo $firstVariableNodeUseInfo,
|
||||
VariableNodeUseInfo $secondVariableNodeUseInfo
|
||||
): int {
|
||||
return $firstVariableNodeUseInfo->getStartTokenPosition() <=> $secondVariableNodeUseInfo->getStartTokenPosition();
|
||||
function (VariableNodeUse $firstVariableNodeUse, VariableNodeUse $secondVariableNodeUse): int {
|
||||
return $firstVariableNodeUse->getStartTokenPosition() <=> $secondVariableNodeUse->getStartTokenPosition();
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -236,7 +239,7 @@ PHP
|
|||
|
||||
/**
|
||||
* @param string[] $assignedVariableNames
|
||||
* @param VariableNodeUseInfo[] $nodesByTypeAndPosition
|
||||
* @param VariableNodeUse[] $nodesByTypeAndPosition
|
||||
* @return Node[]
|
||||
*/
|
||||
private function resolveNodesToRemove(array $assignedVariableNames, array $nodesByTypeAndPosition): array
|
||||
|
@ -244,7 +247,7 @@ PHP
|
|||
$nodesToRemove = [];
|
||||
|
||||
foreach ($assignedVariableNames as $assignedVariableName) {
|
||||
/** @var VariableNodeUseInfo|null $previousNode */
|
||||
/** @var VariableNodeUse|null $previousNode */
|
||||
$previousNode = null;
|
||||
|
||||
foreach ($nodesByTypeAndPosition as $nodeByTypeAndPosition) {
|
||||
|
@ -257,6 +260,7 @@ PHP
|
|||
|
||||
// instant override → remove
|
||||
} elseif ($this->shouldRemoveAssignNode($previousNode, $nodeByTypeAndPosition)) {
|
||||
/** @var VariableNodeUse $previousNode */
|
||||
$nodesToRemove[] = $previousNode->getParentNode();
|
||||
}
|
||||
|
||||
|
@ -268,31 +272,31 @@ PHP
|
|||
}
|
||||
|
||||
private function isAssignNodeUsed(
|
||||
?VariableNodeUseInfo $previousNode,
|
||||
VariableNodeUseInfo $nodeByTypeAndPosition
|
||||
?VariableNodeUse $previousNode,
|
||||
VariableNodeUse $nodeByTypeAndPosition
|
||||
): bool {
|
||||
// this node was just used, skip to next one
|
||||
if ($previousNode === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $previousNode->isType(VariableNodeUseInfo::TYPE_ASSIGN)) {
|
||||
if (! $previousNode->isType(VariableNodeUse::TYPE_ASSIGN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $nodeByTypeAndPosition->isType(VariableNodeUseInfo::TYPE_USE);
|
||||
return $nodeByTypeAndPosition->isType(VariableNodeUse::TYPE_USE);
|
||||
}
|
||||
|
||||
private function shouldRemoveAssignNode(
|
||||
?VariableNodeUseInfo $previousNode,
|
||||
VariableNodeUseInfo $nodeByTypeAndPosition
|
||||
?VariableNodeUse $previousNode,
|
||||
VariableNodeUse $nodeByTypeAndPosition
|
||||
): bool {
|
||||
if ($previousNode === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $previousNode->isType(VariableNodeUseInfo::TYPE_ASSIGN) || ! $nodeByTypeAndPosition->isType(
|
||||
VariableNodeUseInfo::TYPE_ASSIGN
|
||||
if (! $previousNode->isType(VariableNodeUse::TYPE_ASSIGN) || ! $nodeByTypeAndPosition->isType(
|
||||
VariableNodeUse::TYPE_ASSIGN
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode;
|
||||
namespace Rector\DeadCode\ScopeNesting;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\FunctionLike;
|
26
rules/dead-code/src/ScopeNesting/ParentScopeFinder.php
Normal file
26
rules/dead-code/src/ScopeNesting/ParentScopeFinder.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\ScopeNesting;
|
||||
|
||||
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
rules/dead-code/src/ScopeNesting/ScopeNestingComparator.php
Normal file
60
rules/dead-code/src/ScopeNesting/ScopeNestingComparator.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\ScopeNesting;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
119
rules/dead-code/src/SideEffect/PureFunctionDetector.php
Normal file
119
rules/dead-code/src/SideEffect/PureFunctionDetector.php
Normal file
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\SideEffect;
|
||||
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
|
||||
final class PureFunctionDetector
|
||||
{
|
||||
/**
|
||||
* @see https://github.com/vimeo/psalm/blob/d470903722cfcbc1cd04744c5491d3e6d13ec3d9/src/Psalm/Internal/Codebase/Functions.php#L288
|
||||
* @var string[]
|
||||
*/
|
||||
private const IMPURE_FUNCTIONS = [
|
||||
'chdir', 'chgrp', 'chmod', 'chown', 'chroot', 'closedir', 'copy', 'file_put_contents',
|
||||
'fopen', 'fread', 'fwrite', 'fclose', 'touch', 'fpassthru', 'fputs', 'fscanf', 'fseek',
|
||||
'ftruncate', 'fprintf', 'symlink', 'mkdir', 'unlink', 'rename', 'rmdir', 'popen', 'pclose',
|
||||
'fputcsv', 'umask', 'finfo_close', 'readline_add_history', 'stream_set_timeout', 'fflush',
|
||||
|
||||
// stream/socket io
|
||||
'stream_context_set_option', 'socket_write', 'stream_set_blocking', 'socket_close',
|
||||
'socket_set_option', 'stream_set_write_buffer',
|
||||
|
||||
// meta calls
|
||||
'call_user_func', 'call_user_func_array', 'define', 'create_function',
|
||||
|
||||
// http
|
||||
'header', 'header_remove', 'http_response_code', 'setcookie',
|
||||
|
||||
// output buffer
|
||||
'ob_start', 'ob_end_clean', 'readfile', 'printf', 'var_dump', 'phpinfo',
|
||||
'ob_implicit_flush', 'vprintf',
|
||||
|
||||
// mcrypt
|
||||
'mcrypt_generic_init', 'mcrypt_generic_deinit', 'mcrypt_module_close',
|
||||
|
||||
// internal optimisation
|
||||
'opcache_compile_file', 'clearstatcache',
|
||||
|
||||
// process-related
|
||||
'pcntl_signal', 'posix_kill', 'cli_set_process_title', 'pcntl_async_signals', 'proc_close',
|
||||
'proc_nice', 'proc_open', 'proc_terminate',
|
||||
|
||||
// curl
|
||||
'curl_setopt', 'curl_close', 'curl_multi_add_handle', 'curl_multi_remove_handle',
|
||||
'curl_multi_select', 'curl_multi_close', 'curl_setopt_array',
|
||||
|
||||
// apc, apcu
|
||||
'apc_store', 'apc_delete', 'apc_clear_cache', 'apc_add', 'apc_inc', 'apc_dec', 'apc_cas',
|
||||
'apcu_store', 'apcu_delete', 'apcu_clear_cache', 'apcu_add', 'apcu_inc', 'apcu_dec', 'apcu_cas',
|
||||
|
||||
// gz
|
||||
'gzwrite', 'gzrewind', 'gzseek', 'gzclose',
|
||||
|
||||
// newrelic
|
||||
'newrelic_start_transaction', 'newrelic_name_transaction', 'newrelic_add_custom_parameter',
|
||||
'newrelic_add_custom_tracer', 'newrelic_background_job', 'newrelic_end_transaction',
|
||||
'newrelic_set_appname',
|
||||
|
||||
// execution
|
||||
'shell_exec', 'exec', 'system', 'passthru', 'pcntl_exec',
|
||||
|
||||
// well-known functions
|
||||
'libxml_use_internal_errors', 'libxml_disable_entity_loader', 'curl_exec',
|
||||
'mt_srand', 'openssl_pkcs7_sign',
|
||||
'mt_rand', 'rand', 'random_int', 'random_bytes',
|
||||
'wincache_ucache_delete', 'wincache_ucache_set', 'wincache_ucache_inc',
|
||||
'class_alias',
|
||||
|
||||
// php environment
|
||||
'ini_set', 'sleep', 'usleep', 'register_shutdown_function',
|
||||
'error_reporting', 'register_tick_function', 'unregister_tick_function',
|
||||
'set_error_handler', 'user_error', 'trigger_error', 'restore_error_handler',
|
||||
'date_default_timezone_set', 'assert_options', 'setlocale',
|
||||
'set_exception_handler', 'set_time_limit', 'putenv', 'spl_autoload_register',
|
||||
'microtime', 'array_rand',
|
||||
|
||||
// logging
|
||||
'openlog', 'syslog', 'error_log', 'define_syslog_variables',
|
||||
|
||||
// session
|
||||
'session_id', 'session_name', 'session_set_cookie_params', 'session_set_save_handler',
|
||||
'session_regenerate_id', 'mb_internal_encoding', 'session_start',
|
||||
|
||||
// ldap
|
||||
'ldap_set_option',
|
||||
|
||||
// iterators
|
||||
'rewind', 'iterator_apply',
|
||||
|
||||
// mysqli
|
||||
'mysqli_select_db', 'mysqli_dump_debug_info', 'mysqli_kill', 'mysqli_multi_query',
|
||||
'mysqli_next_result', 'mysqli_options', 'mysqli_ping', 'mysqli_query', 'mysqli_report',
|
||||
'mysqli_rollback', 'mysqli_savepoint', 'mysqli_set_charset', 'mysqli_ssl_set',
|
||||
|
||||
// postgres
|
||||
'pg_exec', 'pg_execute', 'pg_connect', 'pg_query_params',
|
||||
|
||||
// ftp
|
||||
'ftp_close',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var NodeNameResolver
|
||||
*/
|
||||
private $nodeNameResolver;
|
||||
|
||||
public function __construct(NodeNameResolver $nodeNameResolver)
|
||||
{
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
}
|
||||
|
||||
public function detect(FuncCall $funcCall): bool
|
||||
{
|
||||
return ! $this->nodeNameResolver->isNames($funcCall, self::IMPURE_FUNCTIONS);
|
||||
}
|
||||
}
|
84
rules/dead-code/src/SideEffect/SideEffectNodeDetector.php
Normal file
84
rules/dead-code/src/SideEffect/SideEffectNodeDetector.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\SideEffect;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\BinaryOp\Concat;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Scalar\Encapsed;
|
||||
use PHPStan\Type\ConstantType;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
|
||||
final class SideEffectNodeDetector
|
||||
{
|
||||
/**
|
||||
* @var class-string[]
|
||||
*/
|
||||
private const SIDE_EFFECT_NODE_TYPES = [Encapsed::class, New_::class, Concat::class, PropertyFetch::class];
|
||||
|
||||
/**
|
||||
* @var PureFunctionDetector
|
||||
*/
|
||||
private $pureFunctionDetector;
|
||||
|
||||
/**
|
||||
* @var NodeTypeResolver
|
||||
*/
|
||||
private $nodeTypeResolver;
|
||||
|
||||
public function __construct(PureFunctionDetector $pureFunctionDetector, NodeTypeResolver $nodeTypeResolver)
|
||||
{
|
||||
$this->pureFunctionDetector = $pureFunctionDetector;
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
}
|
||||
|
||||
public function detect(Expr $expr): bool
|
||||
{
|
||||
if ($expr instanceof Assign) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$exprStaticType = $this->nodeTypeResolver->resolve($expr);
|
||||
if ($exprStaticType instanceof ConstantType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (self::SIDE_EFFECT_NODE_TYPES as $sideEffectNodeType) {
|
||||
if (is_a($expr, $sideEffectNodeType, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($expr instanceof FuncCall) {
|
||||
return ! $this->pureFunctionDetector->detect($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Variable || $expr instanceof ArrayDimFetch) {
|
||||
$variable = $this->resolveVariable($expr);
|
||||
// variables don't have side effects
|
||||
return ! $variable instanceof Variable;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function resolveVariable(Expr $expr): ?Variable
|
||||
{
|
||||
while ($expr instanceof ArrayDimFetch) {
|
||||
$expr = $expr->var;
|
||||
}
|
||||
|
||||
if (! $expr instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $expr;
|
||||
}
|
||||
}
|
|
@ -64,7 +64,6 @@ final class ClassUnusedPrivateClassMethodResolver
|
|||
$unusedMethods = array_diff($classPublicMethodNames, $usedMethodNames);
|
||||
|
||||
$unusedMethods = $this->filterOutSystemMethods($unusedMethods);
|
||||
|
||||
$unusedMethods = $this->filterOutInterfaceRequiredMethods($class, $unusedMethods);
|
||||
|
||||
return $this->filterOutParentAbstractMethods($class, $unusedMethods);
|
||||
|
|
|
@ -2,14 +2,14 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Data;
|
||||
namespace Rector\DeadCode\ValueObject;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
final class VariableNodeUseInfo
|
||||
final class VariableNodeUse
|
||||
{
|
||||
/**
|
||||
* @var string
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignConCat
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$removeMe = 'a' . 5 . 'b';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignConCat
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignDouble
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$days = [1 => 'one', 'two'];
|
||||
|
||||
$days = ['something_else'];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignDouble
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignFuncCallInternal
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$days = substr('lololo', 5);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignFuncCallInternal
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
final class AssignMultiFirstToGo
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$peValId = $values = 0;
|
||||
if ($values) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
final class AssignMultiFirstToGo
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$values = 0;
|
||||
if ($values) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
final class AssignMultiSameLine
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$me = $this->createMe();
|
||||
$me = $this->createMe();
|
||||
$me = $this->createMe();
|
||||
|
||||
return $me;
|
||||
}
|
||||
|
||||
public function createMe()
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
final class AssignMultiSameLine
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$this->createMe();
|
||||
$this->createMe();
|
||||
$me = $this->createMe();
|
||||
|
||||
return $me;
|
||||
}
|
||||
|
||||
public function createMe()
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignNewInstance
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$days = new \stdClass();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignNewInstance
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignProperty
|
||||
{
|
||||
private $days = '123';
|
||||
|
||||
public function run()
|
||||
{
|
||||
$days = $this->days;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignProperty
|
||||
{
|
||||
private $days = '123';
|
||||
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignScalar
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$days = [1 => 'one', 'two'];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignScalar
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignSession
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$days = $_SESSION['ID'];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignSession
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignHereDoc
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$removeMe = <<<EOF
|
||||
Value: {$embed}<br />
|
||||
EOF;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class AssignHereDoc
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$value = $this->process();
|
||||
}
|
||||
|
||||
public function process()
|
||||
{
|
||||
// something going on
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$this->process();
|
||||
}
|
||||
|
||||
public function process()
|
||||
{
|
||||
// something going on
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
final class SkipAssignEmbedHtml
|
||||
{
|
||||
public function content()
|
||||
{
|
||||
for ($c = 0; $c <= \pg_numrows($result); $c++) {
|
||||
if ($a !== $b) {
|
||||
if ($row === 0) {
|
||||
StaticCaller::callMe($suspect);
|
||||
}
|
||||
$suspect = 0;
|
||||
}
|
||||
if ($row[5] === 1) {
|
||||
$suspect = $row[6];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class SkipCommented
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
/* multi
|
||||
line */
|
||||
$employCount = \pg_num_rows($result);
|
||||
SomeClassMe::callStatic('Items', $employCount);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class SkipFor
|
||||
{
|
||||
public function run($nesting = 100)
|
||||
{
|
||||
for ($j = 2; $j < $nesting; $j++) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class SkipIfAssignNestedUse
|
||||
{
|
||||
public function run($token)
|
||||
{
|
||||
if (($id = $this->get($token))) {
|
||||
pg_query_params('SELECT ... =$1', [
|
||||
$id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class SkipMultiAssign
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$values = $peValId = $peColId = $auto = 0;
|
||||
|
||||
if ($values) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
final class SkipProperty
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $days;
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->days = [1 => 'one', 'two'];
|
||||
}
|
||||
|
||||
public function useMe()
|
||||
{
|
||||
return $this->days;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
class SkipUseAnd
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
if (($format = $this->getImageFormat()) && $format !== false) {
|
||||
return 'png';
|
||||
}
|
||||
|
||||
return 'non_png';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector\Fixture;
|
||||
|
||||
final class SkipVarOverrideAndReUse
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$sep = '';
|
||||
while ($row = \pg_fetch_assoc($query)) {
|
||||
$text .= "{$sep}" . ($row['b'] ?: $row['a']);
|
||||
$sep = ', ';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Assign\RemoveUnusedAssignVariableRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\DeadCode\Rector\Assign\RemoveUnusedAssignVariableRector;
|
||||
|
||||
final class RemoveUnusedAssignVariableRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(string $file): void
|
||||
{
|
||||
$this->doTestFile($file);
|
||||
}
|
||||
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return RemoveUnusedAssignVariableRector::class;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user