Skip to content

Commit 8e2e9f6

Browse files
committed
Detect unused variable
2 parents 0fbac5b + 5195842 commit 8e2e9f6

234 files changed

Lines changed: 5957 additions & 774 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎conf/bleedingEdge.neon‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,5 @@ parameters:
2828
checkImportedClassNameCase: true
2929
sortWithoutEffect: true
3030
unresolvedTemplateArguments: true
31+
unusedVariable: true
32+
unusedParameters: true

‎conf/config.level4.neon‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ conditionalTags:
1818
phpstan.rules.rule: %featureToggles.finiteTypesInHaystack%
1919
PHPStan\Rules\Comparison\SwitchConditionRule:
2020
phpstan.rules.rule: %featureToggles.switchConditionAlwaysFalse%
21+
PHPStan\Rules\DeadCode\UnusedVariableRule:
22+
phpstan.rules.rule: %featureToggles.unusedVariable%
23+
PHPStan\Rules\Functions\UnusedFunctionParametersRule:
24+
phpstan.rules.rule: %featureToggles.unusedParameters%
25+
PHPStan\Rules\Methods\UnusedMethodParametersRule:
26+
phpstan.rules.rule: %featureToggles.unusedParameters%
2127

2228
parameters:
2329
checkAdvancedIsset: true
@@ -49,3 +55,12 @@ services:
4955
class: PHPStan\Rules\Comparison\SwitchConditionRule
5056
arguments:
5157
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
58+
59+
-
60+
class: PHPStan\Rules\DeadCode\UnusedVariableRule
61+
62+
-
63+
class: PHPStan\Rules\Functions\UnusedFunctionParametersRule
64+
65+
-
66+
class: PHPStan\Rules\Methods\UnusedMethodParametersRule

‎conf/config.neon‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ parameters:
5959
checkImportedClassNameCase: false
6060
sortWithoutEffect: false
6161
unresolvedTemplateArguments: false
62+
unusedVariable: false
63+
unusedParameters: false
6264
fileExtensions:
6365
- php
6466
checkAdvancedIsset: false
@@ -154,6 +156,7 @@ parameters:
154156
- ../stubs/ReflectionMethod.stub
155157
- ../stubs/ReflectionParameter.stub
156158
- ../stubs/ReflectionProperty.stub
159+
- ../stubs/ReflectionType.stub
157160
- ../stubs/iterable.stub
158161
- ../stubs/ArrayObject.stub
159162
- ../stubs/WeakReference.stub

‎conf/parametersSchema.neon‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ parametersSchema:
5757
checkImportedClassNameCase: bool()
5858
sortWithoutEffect: bool()
5959
unresolvedTemplateArguments: bool()
60+
unusedVariable: bool()
61+
unusedParameters: bool()
6062
])
6163
fileExtensions: listOf(string())
6264
checkAdvancedIsset: bool()

‎e2e/ignore-error-extension/phpstan-baseline.neon‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
parameters:
22
ignoreErrors:
33
-
4-
message: '#^This is an error from a rule that uses a collector$#'
4+
message: '#^This is an error from a rule that uses a collector\: ClassCollector$#'
55
identifier: class.name
66
count: 1
77
path: src/ClassCollector.php
88

99
-
10-
message: '#^This is an error from a rule that uses a collector$#'
10+
message: '#^This is an error from a rule that uses a collector\: ClassRule$#'
1111
identifier: class.name
1212
count: 1
1313
path: src/ClassRule.php
1414

1515
-
16-
message: '#^This is an error from a rule that uses a collector$#'
16+
message: '#^This is an error from a rule that uses a collector\: ControllerActionReturnTypeIgnoreExtension$#'
1717
identifier: class.name
1818
count: 1
1919
path: src/ControllerActionReturnTypeIgnoreExtension.php
2020

2121
-
22-
message: '#^This is an error from a rule that uses a collector$#'
22+
message: '#^This is an error from a rule that uses a collector\: ControllerClassNameIgnoreExtension$#'
2323
identifier: class.name
2424
count: 1
2525
path: src/ControllerClassNameIgnoreExtension.php

‎e2e/ignore-error-extension/src/ClassRule.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function processNode(Node $node, Scope $scope) : array
2929

3030
foreach ($node->get(ClassCollector::class) as $file => $data) {
3131
foreach ($data as [$className, $line]) {
32-
$errors[] = RuleErrorBuilder::message('This is an error from a rule that uses a collector')
32+
$errors[] = RuleErrorBuilder::message(sprintf('This is an error from a rule that uses a collector: %s', $className))
3333
->file($file)
3434
->line($line)
3535
->identifier('class.name')

‎e2e/trait-caching/data/TestClassUsingTrait.php‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public function doBar()
1515
return $this->doFoo();
1616
}
1717

18-
public function doBaz(): void
18+
public function doBaz(): \stdClass
1919
{
2020
$class = new class() {
2121

@@ -29,6 +29,8 @@ public function doBar()
2929
return $this->doFoo();
3030
}
3131
};
32+
33+
return $class->doBar();
3234
}
3335

3436
}

‎src/Analyser/ArgsResult.php‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ final class ArgsResult
2222

2323
/**
2424
* @param array<int, ExpressionResult> $argResults keyed by spl_object_id of each argument's value expression
25+
* @param array<int, true> $byRefArguments
2526
*/
2627
public function __construct(
2728
private ExpressionResult $expressionResult,
2829
private ?ParametersAcceptor $resolvedParametersAcceptor,
2930
private array $argResults,
31+
private array $byRefArguments = [],
3032
)
3133
{
3234
}
@@ -72,6 +74,11 @@ public function requireArgResult(Expr $argValue): ExpressionResult
7274
return $result;
7375
}
7476

77+
public function isPassedByReference(Expr $arg): bool
78+
{
79+
return isset($this->byRefArguments[spl_object_id($arg)]);
80+
}
81+
7582
public function getScope(): MutatingScope
7683
{
7784
return $this->expressionResult->getScope();

‎src/Analyser/ExprHandler/ArrayDimFetchHandler.php‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
use PHPStan\Analyser\NodeScopeResolver;
2424
use PHPStan\Analyser\SpecifiedTypes;
2525
use PHPStan\Analyser\TypeSpecifierContext;
26+
use PHPStan\Analyser\VariableFlow;
27+
use PHPStan\Analyser\VariableFlowBuilder;
2628
use PHPStan\DependencyInjection\AutowiredService;
2729
use PHPStan\Node\Expr\TypeExpr;
2830
use PHPStan\Reflection\ParametersAcceptorSelector;
@@ -84,6 +86,7 @@ public function composeResult(NodeScopeResolver $nodeScopeResolver, Stmt $stmt,
8486
$scope,
8587
beforeScope: $beforeScope,
8688
expr: $expr,
89+
variableFlow: $varResult->getVariableFlow(),
8790
hasYield: $varResult->hasYield(),
8891
isAlwaysTerminating: $varResult->isAlwaysTerminating(),
8992
throwPoints: $varResult->getThrowPoints(),
@@ -118,6 +121,7 @@ public function composeResult(NodeScopeResolver $nodeScopeResolver, Stmt $stmt,
118121
$scope,
119122
beforeScope: $beforeScope,
120123
expr: $expr,
124+
variableFlow: VariableFlow::sequence($varResult->getVariableFlow(), $dimResult->getVariableFlow(), VariableFlowBuilder::throws($expr, $throwPoints)),
121125
hasYield: $dimResult->hasYield() || $varResult->hasYield(),
122126
isAlwaysTerminating: $dimResult->isAlwaysTerminating() || $varResult->isAlwaysTerminating(),
123127
throwPoints: $throwPoints,

‎src/Analyser/ExprHandler/ArrayHandler.php‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
use PHPStan\Analyser\MutatingScope;
1717
use PHPStan\Analyser\NodeScopeResolver;
1818
use PHPStan\Analyser\SpecifiedTypes;
19+
use PHPStan\Analyser\VariableFlow;
20+
use PHPStan\Analyser\VariableFlowBuilder;
1921
use PHPStan\DependencyInjection\AutowiredService;
2022
use PHPStan\Node\LiteralArrayItem;
2123
use PHPStan\Node\LiteralArrayNode;
@@ -53,6 +55,7 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex
5355
$beforeScope = $scope;
5456
$itemNodes = [];
5557
$itemResults = [];
58+
$variableFlows = [];
5659
$hasYield = false;
5760
$throwPoints = [];
5861
$impurePoints = [];
@@ -63,6 +66,7 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex
6366
if ($arrayItem->key !== null) {
6467
$keyResult = $nodeScopeResolver->processExprNode($stmt, $arrayItem->key, $scope, $storage, $nodeCallback, $context->enterDeep());
6568
$itemResults[spl_object_id($arrayItem->key)] = $keyResult;
69+
$variableFlows[] = $keyResult->getVariableFlow();
6670
$hasYield = $hasYield || $keyResult->hasYield();
6771
$throwPoints = array_merge($throwPoints, $keyResult->getThrowPoints());
6872
$impurePoints = array_merge($impurePoints, $keyResult->getImpurePoints());
@@ -72,6 +76,10 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex
7276

7377
$valueResult = $nodeScopeResolver->processExprNode($stmt, $arrayItem->value, $scope, $storage, $nodeCallback, $context->enterDeep());
7478
$itemResults[spl_object_id($arrayItem->value)] = $valueResult;
79+
$variableFlows[] = $valueResult->getVariableFlow();
80+
if ($arrayItem->byRef) {
81+
$variableFlows[] = VariableFlowBuilder::escapeRoot($arrayItem->value);
82+
}
7583
$hasYield = $hasYield || $valueResult->hasYield();
7684
$throwPoints = array_merge($throwPoints, $valueResult->getThrowPoints());
7785
$impurePoints = array_merge($impurePoints, $valueResult->getImpurePoints());
@@ -88,6 +96,7 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex
8896
$scope,
8997
beforeScope: $beforeScope,
9098
expr: $expr,
99+
variableFlow: VariableFlow::sequence(...$variableFlows),
91100
hasYield: $hasYield,
92101
isAlwaysTerminating: $isAlwaysTerminating,
93102
throwPoints: $throwPoints,

0 commit comments

Comments
 (0)