5
5
use PhpParser \Node ;
6
6
use PhpParser \Node \Expr \Variable ;
7
7
use PHPStan \Analyser \Scope ;
8
+ use PHPStan \Rules \IdentifierRuleError ;
8
9
use PHPStan \Rules \Rule ;
9
10
use PHPStan \Rules \RuleErrorBuilder ;
11
+ use PHPStan \Rules \RuleLevelHelper ;
12
+ use PHPStan \Type \Constant \ConstantStringType ;
13
+ use PHPStan \Type \VerbosityLevel ;
14
+ use function array_map ;
15
+ use function array_merge ;
10
16
use function in_array ;
11
17
use function is_string ;
12
18
use function sprintf ;
@@ -20,6 +26,7 @@ final class DefinedVariableRule implements Rule
20
26
public function __construct (
21
27
private bool $ cliArgumentsVariablesRegistered ,
22
28
private bool $ checkMaybeUndefinedVariables ,
29
+ // private RuleLevelHelper $ruleLevelHelper,
23
30
)
24
31
{
25
32
}
@@ -31,11 +38,33 @@ public function getNodeType(): string
31
38
32
39
public function processNode (Node $ node , Scope $ scope ): array
33
40
{
34
- if (!is_string ($ node ->name )) {
35
- return [];
41
+ $ errors = [];
42
+ if (is_string ($ node ->name )) {
43
+ $ variableNames = [$ node ->name ];
44
+ } else {
45
+ $ fetchType = $ scope ->getType ($ node ->name );
46
+ $ variableNames = array_map (static fn (ConstantStringType $ type ): string => $ type ->getValue (), $ fetchType ->getConstantStrings ());
47
+ $ fetchStringType = $ fetchType ->toString ();
48
+ if (! $ fetchStringType ->isString ()->yes ()) {
49
+ $ errors [] = RuleErrorBuilder::message (sprintf ('Cannot access variable with a non-stringable type %s. ' , $ fetchType ->describe (VerbosityLevel::typeOnly ())))
50
+ ->identifier ('variable.fetchInvalidExpression ' )
51
+ ->build ();
52
+ }
53
+ }
54
+
55
+ foreach ($ variableNames as $ name ) {
56
+ $ errors = array_merge ($ errors , $ this ->processSingleVariable ($ scope , $ node , $ name ));
36
57
}
37
58
38
- if ($ this ->cliArgumentsVariablesRegistered && in_array ($ node ->name , [
59
+ return $ errors ;
60
+ }
61
+
62
+ /**
63
+ * @return list<IdentifierRuleError>
64
+ */
65
+ private function processSingleVariable (Scope $ scope , Variable $ node , string $ variableName ): array
66
+ {
67
+ if ($ this ->cliArgumentsVariablesRegistered && in_array ($ variableName , [
39
68
'argc ' ,
40
69
'argv ' ,
41
70
], true )) {
@@ -49,18 +78,18 @@ public function processNode(Node $node, Scope $scope): array
49
78
return [];
50
79
}
51
80
52
- if ($ scope ->hasVariableType ($ node -> name )->no ()) {
81
+ if ($ scope ->hasVariableType ($ variableName )->no ()) {
53
82
return [
54
- RuleErrorBuilder::message (sprintf ('Undefined variable: $%s ' , $ node -> name ))
83
+ RuleErrorBuilder::message (sprintf ('Undefined variable: $%s ' , $ variableName ))
55
84
->identifier ('variable.undefined ' )
56
85
->build (),
57
86
];
58
87
} elseif (
59
88
$ this ->checkMaybeUndefinedVariables
60
- && !$ scope ->hasVariableType ($ node -> name )->yes ()
89
+ && !$ scope ->hasVariableType ($ variableName )->yes ()
61
90
) {
62
91
return [
63
- RuleErrorBuilder::message (sprintf ('Variable $%s might not be defined. ' , $ node -> name ))
92
+ RuleErrorBuilder::message (sprintf ('Variable $%s might not be defined. ' , $ variableName ))
64
93
->identifier ('variable.undefined ' )
65
94
->build (),
66
95
];
0 commit comments