Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 416437c

Browse files
committedMar 18, 2025·
Support dynamic name expressions in rules
1 parent ef6cc0a commit 416437c

File tree

4 files changed

+85
-16
lines changed

4 files changed

+85
-16
lines changed
 

‎src/Rules/Classes/ClassConstantRule.php

+19-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use PHPStan\Type\Type;
2121
use PHPStan\Type\TypeCombinator;
2222
use PHPStan\Type\VerbosityLevel;
23+
use function array_map;
2324
use function array_merge;
2425
use function in_array;
2526
use function sprintf;
@@ -47,11 +48,26 @@ public function getNodeType(): string
4748

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

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

‎src/Rules/Methods/CallMethodsRule.php

+19-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
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 function array_map;
1214
use function array_merge;
1315

1416
/**
@@ -31,12 +33,26 @@ public function getNodeType(): string
3133

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

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

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

‎src/Rules/Methods/CallStaticMethodsRule.php

+20-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
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 function array_map;
1214
use function array_merge;
1315
use function sprintf;
1416

@@ -32,11 +34,26 @@ public function getNodeType(): string
3234

3335
public function processNode(Node $node, Scope $scope): array
3436
{
35-
if (!$node->name instanceof Node\Identifier) {
36-
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 ($type): string => $type->getValue(), $callType->getConstantStrings());
3743
}
38-
$methodName = $node->name->name;
3944

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

‎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)
Please sign in to comment.