5
5
use PHPStan \Analyser \Scope ;
6
6
use PHPStan \PhpDoc \ResolvedPhpDocBlock ;
7
7
use PHPStan \PhpDocParser \Ast \PhpDoc \PhpDocTagNode ;
8
+ use PHPStan \Reflection \ClassReflection ;
8
9
use PHPStan \Reflection \MissingMethodFromReflectionException ;
10
+ use PHPStan \Reflection \ReflectionProvider ;
9
11
use PHPStan \Rules \RuleError ;
10
12
use PHPStan \Rules \RuleErrorBuilder ;
11
13
use function array_merge ;
14
+ use function count ;
15
+ use function explode ;
12
16
use function preg_match ;
13
17
use function sprintf ;
14
18
15
19
class DataProviderHelper
16
20
{
17
21
22
+ /**
23
+ * Reflection provider.
24
+ *
25
+ * @var ReflectionProvider
26
+ */
27
+ private $ reflectionProvider ;
28
+
29
+ public function __construct (ReflectionProvider $ reflectionProvider )
30
+ {
31
+ $ this ->reflectionProvider = $ reflectionProvider ;
32
+ }
33
+
18
34
/**
19
35
* @return array<PhpDocTagNode>
20
36
*/
@@ -48,57 +64,61 @@ public function processDataProvider(
48
64
bool $ deprecationRulesInstalled
49
65
): array
50
66
{
51
- $ dataProviderName = $ this ->getDataProviderName ($ phpDocTag );
52
- if ($ dataProviderName === null ) {
53
- // Missing name is already handled in NoMissingSpaceInMethodAnnotationRule
67
+ $ dataProviderValue = $ this ->getDataProviderValue ($ phpDocTag );
68
+ if ($ dataProviderValue === null ) {
69
+ // Missing value is already handled in NoMissingSpaceInMethodAnnotationRule
54
70
return [];
55
71
}
56
72
57
- $ classReflection = $ scope -> getClassReflection ( );
73
+ [ $ classReflection, $ method ] = $ this -> parseDataProviderValue ( $ scope , $ dataProviderValue );
58
74
if ($ classReflection === null ) {
59
- // Should not happen
60
- return [];
75
+ $ error = RuleErrorBuilder::message (sprintf (
76
+ '@dataProvider %s related class not found. ' ,
77
+ $ dataProviderValue
78
+ ))->build ();
79
+
80
+ return [$ error ];
61
81
}
62
82
63
83
try {
64
- $ dataProviderMethodReflection = $ classReflection ->getNativeMethod ($ dataProviderName );
84
+ $ dataProviderMethodReflection = $ classReflection ->getNativeMethod ($ method );
65
85
} catch (MissingMethodFromReflectionException $ missingMethodFromReflectionException ) {
66
86
$ error = RuleErrorBuilder::message (sprintf (
67
87
'@dataProvider %s related method not found. ' ,
68
- $ dataProviderName
88
+ $ dataProviderValue
69
89
))->build ();
70
90
71
91
return [$ error ];
72
92
}
73
93
74
94
$ errors = [];
75
95
76
- if ($ checkFunctionNameCase && $ dataProviderName !== $ dataProviderMethodReflection ->getName ()) {
96
+ if ($ checkFunctionNameCase && $ method !== $ dataProviderMethodReflection ->getName ()) {
77
97
$ errors [] = RuleErrorBuilder::message (sprintf (
78
98
'@dataProvider %s related method is used with incorrect case: %s. ' ,
79
- $ dataProviderName ,
99
+ $ dataProviderValue ,
80
100
$ dataProviderMethodReflection ->getName ()
81
101
))->build ();
82
102
}
83
103
84
104
if (!$ dataProviderMethodReflection ->isPublic ()) {
85
105
$ errors [] = RuleErrorBuilder::message (sprintf (
86
106
'@dataProvider %s related method must be public. ' ,
87
- $ dataProviderName
107
+ $ dataProviderValue
88
108
))->build ();
89
109
}
90
110
91
111
if ($ deprecationRulesInstalled && !$ dataProviderMethodReflection ->isStatic ()) {
92
112
$ errors [] = RuleErrorBuilder::message (sprintf (
93
113
'@dataProvider %s related method must be static. ' ,
94
- $ dataProviderName
114
+ $ dataProviderValue
95
115
))->build ();
96
116
}
97
117
98
118
return $ errors ;
99
119
}
100
120
101
- private function getDataProviderName (PhpDocTagNode $ phpDocTag ): ?string
121
+ private function getDataProviderValue (PhpDocTagNode $ phpDocTag ): ?string
102
122
{
103
123
if (preg_match ('/^[^ \t]+/ ' , (string ) $ phpDocTag ->value , $ matches ) !== 1 ) {
104
124
return null ;
@@ -107,4 +127,21 @@ private function getDataProviderName(PhpDocTagNode $phpDocTag): ?string
107
127
return $ matches [0 ];
108
128
}
109
129
130
+ /**
131
+ * @return array{ClassReflection|null, string}
132
+ */
133
+ private function parseDataProviderValue (Scope $ scope , string $ dataProviderValue ): array
134
+ {
135
+ $ parts = explode (':: ' , $ dataProviderValue , 2 );
136
+ if (count ($ parts ) <= 1 ) {
137
+ return [$ scope ->getClassReflection (), $ dataProviderValue ];
138
+ }
139
+
140
+ if ($ this ->reflectionProvider ->hasClass ($ parts [0 ])) {
141
+ return [$ this ->reflectionProvider ->getClass ($ parts [0 ]), $ parts [1 ]];
142
+ }
143
+
144
+ return [null , $ dataProviderValue ];
145
+ }
146
+
110
147
}
0 commit comments