55namespace Rector \TypeDeclaration \Rector \ClassMethod ;
66
77use PhpParser \Node ;
8- use PhpParser \Node \ArrayItem ;
9- use PhpParser \Node \Expr \Array_ ;
10- use PhpParser \Node \Expr \Yield_ ;
118use PhpParser \Node \Stmt \Class_ ;
129use PhpParser \Node \Stmt \ClassMethod ;
13- use PhpParser \Node \Stmt \Return_ ;
14- use PHPStan \Type \Constant \ConstantArrayType ;
1510use PHPStan \Type \MixedType ;
16- use PHPStan \Type \Type ;
17- use PHPStan \Type \TypeCombinator ;
18- use Rector \NodeTypeResolver \PHPStan \Type \TypeFactory ;
19- use Rector \PhpParser \Node \BetterNodeFinder ;
2011use Rector \PHPStanStaticTypeMapper \Enum \TypeKind ;
2112use Rector \PHPUnit \NodeAnalyzer \TestsNodeAnalyzer ;
2213use Rector \Rector \AbstractRector ;
2314use Rector \StaticTypeMapper \StaticTypeMapper ;
15+ use Rector \TypeDeclaration \TypeAnalyzer \ParameterTypeFromDataProviderResolver ;
2416use Rector \TypeDeclaration \ValueObject \DataProviderNodes ;
2517use Rector \TypeDeclarationDocblocks \NodeFinder \DataProviderMethodsFinder ;
2618use Symplify \RuleDocGenerator \ValueObject \CodeSample \CodeSample ;
@@ -37,10 +29,9 @@ final class AddParamTypeBasedOnPHPUnitDataProviderRector extends AbstractRector
3729 private const ERROR_MESSAGE = 'Adds param type declaration based on PHPUnit provider return type declaration ' ;
3830
3931 public function __construct (
40- private readonly TypeFactory $ typeFactory ,
4132 private readonly TestsNodeAnalyzer $ testsNodeAnalyzer ,
4233 private readonly DataProviderMethodsFinder $ dataProviderMethodsFinder ,
43- private readonly BetterNodeFinder $ betterNodeFinder ,
34+ private readonly ParameterTypeFromDataProviderResolver $ parameterTypeFromDataProviderResolver ,
4435 private readonly StaticTypeMapper $ staticTypeMapper ,
4536 ) {
4637 }
@@ -136,111 +127,6 @@ public function refactor(Node $node): ?Node
136127 return null ;
137128 }
138129
139- private function inferParam (int $ parameterPosition , ClassMethod $ dataProviderClassMethod ): Type
140- {
141- $ returns = $ this ->betterNodeFinder ->findReturnsScoped ($ dataProviderClassMethod );
142- if ($ returns !== []) {
143- return $ this ->resolveReturnStaticArrayTypeByParameterPosition ($ returns , $ parameterPosition );
144- }
145-
146- /** @var Yield_[] $yields */
147- $ yields = $ this ->betterNodeFinder ->findInstancesOfInFunctionLikeScoped ($ dataProviderClassMethod , Yield_::class);
148- return $ this ->resolveYieldStaticArrayTypeByParameterPosition ($ yields , $ parameterPosition );
149- }
150-
151- /**
152- * @param Return_[] $returns
153- */
154- private function resolveReturnStaticArrayTypeByParameterPosition (array $ returns , int $ parameterPosition ): Type
155- {
156- $ firstReturnedExpr = $ returns [0 ]->expr ;
157-
158- if (! $ firstReturnedExpr instanceof Array_) {
159- return new MixedType ();
160- }
161-
162- $ paramOnPositionTypes = $ this ->resolveParamOnPositionTypes ($ firstReturnedExpr , $ parameterPosition );
163- if ($ paramOnPositionTypes === []) {
164- return new MixedType ();
165- }
166-
167- return $ this ->typeFactory ->createMixedPassedOrUnionType ($ paramOnPositionTypes );
168- }
169-
170- /**
171- * @param Yield_[] $yields
172- */
173- private function resolveYieldStaticArrayTypeByParameterPosition (array $ yields , int $ parameterPosition ): Type
174- {
175- $ paramOnPositionTypes = [];
176-
177- foreach ($ yields as $ yield ) {
178- if (! $ yield ->value instanceof Array_) {
179- continue ;
180- }
181-
182- $ type = $ this ->getTypeFromClassMethodYield ($ yield ->value );
183-
184- if (! $ type instanceof ConstantArrayType) {
185- return $ type ;
186- }
187-
188- foreach ($ type ->getValueTypes () as $ position => $ valueType ) {
189- if ($ position !== $ parameterPosition ) {
190- continue ;
191- }
192-
193- $ paramOnPositionTypes [] = $ valueType ;
194- }
195- }
196-
197- if ($ paramOnPositionTypes === []) {
198- return new MixedType ();
199- }
200-
201- return $ this ->typeFactory ->createMixedPassedOrUnionType ($ paramOnPositionTypes );
202- }
203-
204- private function getTypeFromClassMethodYield (Array_ $ classMethodYieldArray ): MixedType | ConstantArrayType
205- {
206- $ arrayType = $ this ->nodeTypeResolver ->getType ($ classMethodYieldArray );
207-
208- // impossible to resolve
209- if (! $ arrayType instanceof ConstantArrayType) {
210- return new MixedType ();
211- }
212-
213- return $ arrayType ;
214- }
215-
216- /**
217- * @return Type[]
218- */
219- private function resolveParamOnPositionTypes (Array_ $ array , int $ parameterPosition ): array
220- {
221- $ paramOnPositionTypes = [];
222-
223- foreach ($ array ->items as $ singleDataProvidedSet ) {
224- if (! $ singleDataProvidedSet instanceof ArrayItem || ! $ singleDataProvidedSet ->value instanceof Array_) {
225- return [];
226- }
227-
228- foreach ($ singleDataProvidedSet ->value ->items as $ position => $ singleDataProvidedSetItem ) {
229- if ($ position !== $ parameterPosition ) {
230- continue ;
231- }
232-
233- if (! $ singleDataProvidedSetItem instanceof ArrayItem) {
234- continue ;
235- }
236-
237- $ paramOnPositionTypes [] = $ this ->nodeTypeResolver ->getType ($ singleDataProvidedSetItem ->value );
238- }
239- }
240-
241- return $ paramOnPositionTypes ;
242- }
243-
244130 private function refactorClassMethod (ClassMethod $ classMethod , DataProviderNodes $ dataProviderNodes ): bool
245131 {
246132 $ hasChanged = false ;
@@ -254,12 +140,11 @@ private function refactorClassMethod(ClassMethod $classMethod, DataProviderNodes
254140 continue ;
255141 }
256142
257- $ paramTypes = [];
258- foreach ( $ dataProviderNodes -> getClassMethods () as $ dataProviderClassMethod ) {
259- $ paramTypes [] = $ this -> inferParam ( $ parameterPosition , $ dataProviderClassMethod );
260- }
143+ $ paramTypeDeclaration = $ this -> parameterTypeFromDataProviderResolver -> resolve (
144+ $ parameterPosition ,
145+ $ dataProviderNodes -> getClassMethods ()
146+ );
261147
262- $ paramTypeDeclaration = TypeCombinator::union (...$ paramTypes );
263148 if ($ paramTypeDeclaration instanceof MixedType) {
264149 continue ;
265150 }
0 commit comments