Skip to content

Commit b7fba75

Browse files
committed
Support dynamic name expressions in rules
1 parent 19df9a2 commit b7fba75

File tree

4 files changed

+88
-16
lines changed

4 files changed

+88
-16
lines changed

Diff for: src/Rules/Classes/ClassConstantRule.php

+20-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use PHPStan\Reflection\ReflectionProvider;
1212
use PHPStan\Rules\ClassNameCheck;
1313
use PHPStan\Rules\ClassNameNodePair;
14+
use PHPStan\Rules\IdentifierRuleError;
1415
use PHPStan\Rules\Rule;
1516
use PHPStan\Rules\RuleErrorBuilder;
1617
use PHPStan\Rules\RuleLevelHelper;
@@ -20,6 +21,7 @@
2021
use PHPStan\Type\Type;
2122
use PHPStan\Type\TypeCombinator;
2223
use PHPStan\Type\VerbosityLevel;
24+
use function array_map;
2325
use function array_merge;
2426
use function in_array;
2527
use function sprintf;
@@ -47,11 +49,26 @@ public function getNodeType(): string
4749

4850
public function processNode(Node $node, Scope $scope): array
4951
{
50-
if (!$node->name instanceof Node\Identifier) {
51-
return [];
52+
$errors = [];
53+
if ($node->name instanceof Node\Identifier) {
54+
$constantNames = [$node->name->name];
55+
} else {
56+
$fetchType = $scope->getType($node->name);
57+
$constantNames = array_map(static fn ($type): string => $type->getValue(), $fetchType->getConstantStrings());
58+
}
59+
60+
foreach ($constantNames as $constantName) {
61+
$errors = array_merge($errors, $this->processSingleClassConstFetch($scope, $node, $constantName));
5262
}
53-
$constantName = $node->name->name;
5463

64+
return $errors;
65+
}
66+
67+
/**
68+
* @return list<IdentifierRuleError>
69+
*/
70+
private function processSingleClassConstFetch(Scope $scope, ClassConstFetch $node, string $constantName): array
71+
{
5572
$class = $node->class;
5673
$messages = [];
5774
if ($class instanceof Node\Name) {

Diff for: src/Rules/Methods/CallMethodsRule.php

+20-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
use PHPStan\Internal\SprintfHelper;
99
use PHPStan\Reflection\ParametersAcceptorSelector;
1010
use PHPStan\Rules\FunctionCallParametersCheck;
11+
use PHPStan\Rules\IdentifierRuleError;
1112
use PHPStan\Rules\Rule;
13+
use PHPStan\Type\Constant\ConstantStringType;
14+
use function array_map;
1215
use function array_merge;
1316

1417
/**
@@ -31,12 +34,26 @@ public function getNodeType(): string
3134

3235
public function processNode(Node $node, Scope $scope): array
3336
{
34-
if (!$node->name instanceof Node\Identifier) {
35-
return [];
37+
$errors = [];
38+
if ($node->name instanceof Node\Identifier) {
39+
$methodNames = [$node->name->name];
40+
} else {
41+
$callType = $scope->getType($node->name);
42+
$methodNames = array_map(static fn (ConstantStringType $type): string => $type->getValue(), $callType->getConstantStrings());
3643
}
3744

38-
$methodName = $node->name->name;
45+
foreach ($methodNames as $methodName) {
46+
$errors = array_merge($errors, $this->processSingleMethodCall($scope, $node, $methodName));
47+
}
48+
49+
return $errors;
50+
}
3951

52+
/**
53+
* @return list<IdentifierRuleError>
54+
*/
55+
private function processSingleMethodCall(Scope $scope, MethodCall $node, string $methodName): array
56+
{
4057
[$errors, $methodReflection] = $this->methodCallCheck->check($scope, $methodName, $node->var);
4158
if ($methodReflection === null) {
4259
return $errors;

Diff for: src/Rules/Methods/CallStaticMethodsRule.php

+21-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
use PHPStan\Internal\SprintfHelper;
99
use PHPStan\Reflection\ParametersAcceptorSelector;
1010
use PHPStan\Rules\FunctionCallParametersCheck;
11+
use PHPStan\Rules\IdentifierRuleError;
1112
use PHPStan\Rules\Rule;
13+
use PHPStan\Type\Constant\ConstantStringType;
14+
use function array_map;
1215
use function array_merge;
1316
use function sprintf;
1417

@@ -32,11 +35,26 @@ public function getNodeType(): string
3235

3336
public function processNode(Node $node, Scope $scope): array
3437
{
35-
if (!$node->name instanceof Node\Identifier) {
36-
return [];
38+
$errors = [];
39+
if ($node->name instanceof Node\Identifier) {
40+
$methodNames = [$node->name->name];
41+
} else {
42+
$callType = $scope->getType($node->name);
43+
$methodNames = array_map(static fn (ConstantStringType $type): string => $type->getValue(), $callType->getConstantStrings());
3744
}
38-
$methodName = $node->name->name;
3945

46+
foreach ($methodNames as $methodName) {
47+
$errors = array_merge($errors, $this->processSingleMethodCall($scope, $node, $methodName));
48+
}
49+
50+
return $errors;
51+
}
52+
53+
/**
54+
* @return list<IdentifierRuleError>
55+
*/
56+
private function processSingleMethodCall(Scope $scope, StaticCall $node, string $methodName): array
57+
{
4058
[$errors, $method] = $this->methodCallCheck->check($scope, $methodName, $node->class);
4159
if ($method === null) {
4260
return $errors;

Diff for: src/Rules/Variables/DefinedVariableRule.php

+27-7
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
use PhpParser\Node;
66
use PhpParser\Node\Expr\Variable;
77
use PHPStan\Analyser\Scope;
8+
use PHPStan\Rules\IdentifierRuleError;
89
use PHPStan\Rules\Rule;
910
use PHPStan\Rules\RuleErrorBuilder;
11+
use PHPStan\Type\Constant\ConstantStringType;
12+
use function array_map;
13+
use function array_merge;
1014
use function in_array;
1115
use function is_string;
1216
use function sprintf;
@@ -31,11 +35,27 @@ public function getNodeType(): string
3135

3236
public function processNode(Node $node, Scope $scope): array
3337
{
34-
if (!is_string($node->name)) {
35-
return [];
38+
$errors = [];
39+
if (is_string($node->name)) {
40+
$variableNames = [$node->name];
41+
} else {
42+
$fetchType = $scope->getType($node->name);
43+
$variableNames = array_map(static fn (ConstantStringType $type): string => $type->getValue(), $fetchType->getConstantStrings());
44+
}
45+
46+
foreach ($variableNames as $name) {
47+
$errors = array_merge($errors, $this->processSingleVariable($scope, $node, $name));
3648
}
3749

38-
if ($this->cliArgumentsVariablesRegistered && in_array($node->name, [
50+
return $errors;
51+
}
52+
53+
/**
54+
* @return list<IdentifierRuleError>
55+
*/
56+
private function processSingleVariable(Scope $scope, Variable $node, string $variableName): array
57+
{
58+
if ($this->cliArgumentsVariablesRegistered && in_array($variableName, [
3959
'argc',
4060
'argv',
4161
], true)) {
@@ -49,18 +69,18 @@ public function processNode(Node $node, Scope $scope): array
4969
return [];
5070
}
5171

52-
if ($scope->hasVariableType($node->name)->no()) {
72+
if ($scope->hasVariableType($variableName)->no()) {
5373
return [
54-
RuleErrorBuilder::message(sprintf('Undefined variable: $%s', $node->name))
74+
RuleErrorBuilder::message(sprintf('Undefined variable: $%s', $variableName))
5575
->identifier('variable.undefined')
5676
->build(),
5777
];
5878
} elseif (
5979
$this->checkMaybeUndefinedVariables
60-
&& !$scope->hasVariableType($node->name)->yes()
80+
&& !$scope->hasVariableType($variableName)->yes()
6181
) {
6282
return [
63-
RuleErrorBuilder::message(sprintf('Variable $%s might not be defined.', $node->name))
83+
RuleErrorBuilder::message(sprintf('Variable $%s might not be defined.', $variableName))
6484
->identifier('variable.undefined')
6585
->build(),
6686
];

0 commit comments

Comments
 (0)