66
77use PhpParser \Comment ;
88use PhpParser \Node ;
9+ use PhpParser \Node \Arg ;
10+ use PhpParser \Node \Attribute ;
11+ use PhpParser \Node \AttributeGroup ;
912use PhpParser \Node \ComplexType ;
1013use PhpParser \Node \Expr ;
1114use PhpParser \Node \Expr \Variable ;
1215use PhpParser \Node \Identifier ;
1316use PhpParser \Node \Name ;
17+ use PhpParser \Node \Name \FullyQualified ;
1418use PhpParser \Node \Param ;
1519use PhpParser \Node \Stmt \Class_ ;
1620use PhpParser \Node \Stmt \ClassMethod ;
21+ use PHPStan \BetterReflection \Reflection \Adapter \ReflectionParameter ;
1722use PHPStan \Reflection \ClassReflection ;
23+ use PHPStan \Reflection \ExtendedParameterReflection ;
1824use PHPStan \Reflection \MethodReflection ;
25+ use PHPStan \Reflection \ParametersAcceptorSelector ;
1926use Rector \NodeTypeResolver \Node \AttributeKey ;
20- use Rector \PhpParser \AstResolver ;
2127use Rector \PhpParser \Node \BetterNodeFinder ;
2228use Rector \PhpParser \Printer \BetterStandardPrinter ;
2329use Rector \PHPStan \ScopeFetcher ;
30+ use Rector \PHPStanStaticTypeMapper \Enum \TypeKind ;
2431use Rector \Rector \AbstractRector ;
32+ use Rector \StaticTypeMapper \StaticTypeMapper ;
2533use Rector \ValueObject \MethodName ;
2634use Rector \ValueObject \PhpVersionFeature ;
2735use Rector \VendorLocker \ParentClassMethodTypeOverrideGuard ;
@@ -36,7 +44,7 @@ final class AddParamBasedOnParentClassMethodRector extends AbstractRector implem
3644{
3745 public function __construct (
3846 private readonly ParentClassMethodTypeOverrideGuard $ parentClassMethodTypeOverrideGuard ,
39- private readonly AstResolver $ astResolver ,
47+ private readonly StaticTypeMapper $ staticTypeMapper ,
4048 private readonly BetterStandardPrinter $ betterStandardPrinter ,
4149 private readonly BetterNodeFinder $ betterNodeFinder ,
4250 ) {
@@ -130,13 +138,18 @@ public function refactor(Node $node): ?Node
130138 continue ;
131139 }
132140
133- $ parentClassMethod = $ this ->astResolver ->resolveClassMethodFromMethodReflection ($ parentMethodReflection );
134- if (! $ parentClassMethod instanceof ClassMethod) {
141+ $ parentClassReflection = $ parentMethodReflection ->getDeclaringClass ();
142+ $ nativeClassReflection = $ parentClassReflection ->getNativeReflection ();
143+ if (! $ nativeClassReflection ->hasMethod ($ parentMethodReflection ->getName ())) {
135144 continue ;
136145 }
137146
138147 $ currentClassMethodParams = $ classMethod ->getParams ();
139- $ parentClassMethodParams = $ parentClassMethod ->getParams ();
148+ $ parentClassMethodParams = $ nativeClassReflection ->getMethod ($ parentMethodReflection ->getName ())
149+ ->getParameters ();
150+ $ parentParameterReflections = ParametersAcceptorSelector ::combineAcceptors (
151+ $ parentMethodReflection ->getVariants ()
152+ )->getParameters ();
140153
141154 $ countCurrentClassMethodParams = count ($ currentClassMethodParams );
142155 $ countParentClassMethodParams = count ($ parentClassMethodParams );
@@ -148,9 +161,9 @@ public function refactor(Node $node): ?Node
148161 if ($ countCurrentClassMethodParams < $ countParentClassMethodParams ) {
149162 $ hasClassMethodChanged = $ this ->processReplaceClassMethodParams (
150163 $ classMethod ,
151- $ parentClassMethod ,
152164 $ currentClassMethodParams ,
153- $ parentClassMethodParams
165+ $ parentClassMethodParams ,
166+ $ parentParameterReflections
154167 );
155168
156169 if ($ hasClassMethodChanged ) {
@@ -178,7 +191,7 @@ public function refactor(Node $node): ?Node
178191
179192 /**
180193 * @param Param[] $currentClassMethodParams
181- * @param Param [] $parentClassMethodParams
194+ * @param ReflectionParameter [] $parentClassMethodParams
182195 */
183196 private function processAddNullDefaultParam (
184197 array $ currentClassMethodParams ,
@@ -208,69 +221,70 @@ private function processAddNullDefaultParam(
208221
209222 /**
210223 * @param array<int, Param> $currentClassMethodParams
211- * @param array<int, Param> $parentClassMethodParams
224+ * @param array<int, ReflectionParameter> $parentClassMethodParams
225+ * @param array<int, ExtendedParameterReflection> $parentParameterReflections
212226 */
213227 private function processReplaceClassMethodParams (
214- ClassMethod $ node ,
215- ClassMethod $ parentClassMethod ,
228+ ClassMethod $ classMethod ,
216229 array $ currentClassMethodParams ,
217- array $ parentClassMethodParams
230+ array $ parentClassMethodParams ,
231+ array $ parentParameterReflections
218232 ): bool {
219- $ originalParams = $ node ->params ;
233+ $ originalParams = $ classMethod ->params ;
220234
221235 $ hasChanged = false ;
222236
223237 foreach ($ parentClassMethodParams as $ key => $ parentClassMethodParam ) {
224238 if (isset ($ currentClassMethodParams [$ key ])) {
225239 $ currentParamName = $ this ->getName ($ currentClassMethodParams [$ key ]);
226- $ collectParamNamesNextKey = $ this ->collectParamNamesNextKey ($ parentClassMethod , $ key );
240+ $ collectParamNamesNextKey = $ this ->collectParamNamesNextKey ($ parentClassMethodParams , $ key );
227241
228242 if (in_array ($ currentParamName , $ collectParamNamesNextKey , true )) {
229- $ node ->params = $ originalParams ;
243+ $ classMethod ->params = $ originalParams ;
230244 return false ;
231245 }
232246
233247 continue ;
234248 }
235249
236250 $ isUsedInStmts = (bool ) $ this ->betterNodeFinder ->findFirstInFunctionLikeScoped (
237- $ node ,
251+ $ classMethod ,
238252 function (Node $ subNode ) use ($ parentClassMethodParam ): bool {
239253 if (! $ subNode instanceof Variable) {
240254 return false ;
241255 }
242256
243- return $ this ->nodeComparator -> areNodesEqual ($ subNode , $ parentClassMethodParam ->var );
257+ return $ this ->isName ($ subNode , $ parentClassMethodParam ->getName () );
244258 }
245259 );
246260
247261 if ($ isUsedInStmts ) {
248- $ node ->params = $ originalParams ;
262+ $ classMethod ->params = $ originalParams ;
249263 return false ;
250264 }
251265
252- $ paramDefault = $ parentClassMethodParam ->default ;
253-
254- if ($ paramDefault instanceof Expr) {
255- $ paramDefault = $ this ->nodeFactory ->createReprintedNode ($ paramDefault );
266+ $ paramDefault = null ;
267+ if ($ parentClassMethodParam ->isDefaultValueAvailable ()) {
268+ $ paramDefault = $ this ->nodeFactory ->createReprintedNode (
269+ $ parentClassMethodParam ->getDefaultValueExpression ()
270+ );
256271 }
257272
258- $ paramName = $ this ->getName ($ parentClassMethodParam );
259- $ paramType = $ this ->resolveParamType ($ parentClassMethodParam );
273+ $ paramName = $ parentClassMethodParam ->getName ();
274+ $ paramType = $ this ->resolveParamType ($ parentParameterReflections [ $ key ] ?? null );
260275
261- $ node ->params [$ key ] = new Param (
276+ $ classMethod ->params [$ key ] = new Param (
262277 new Variable ($ paramName ),
263278 $ paramDefault ,
264279 $ paramType ,
265- $ parentClassMethodParam ->byRef ,
266- $ parentClassMethodParam ->variadic ,
267- [],
268- $ parentClassMethodParam ->flags
280+ $ parentClassMethodParam ->isPassedByReference (),
281+ $ parentClassMethodParam ->isVariadic ()
269282 );
270283
271- if ($ parentClassMethodParam ->attrGroups !== []) {
272- $ attrGroupsAsComment = $ this ->betterStandardPrinter ->print ($ parentClassMethodParam ->attrGroups );
273- $ node ->params [$ key ]->setAttribute (AttributeKey::COMMENTS , [new Comment ($ attrGroupsAsComment )]);
284+ $ attributeGroups = $ this ->createAttributeGroups ($ parentClassMethodParam );
285+ if ($ attributeGroups !== []) {
286+ $ attrGroupsAsComment = $ this ->betterStandardPrinter ->print ($ attributeGroups );
287+ $ classMethod ->params [$ key ]->setAttribute (AttributeKey::COMMENTS , [new Comment ($ attrGroupsAsComment )]);
274288 }
275289
276290 $ hasChanged = true ;
@@ -279,28 +293,60 @@ function (Node $subNode) use ($parentClassMethodParam): bool {
279293 return $ hasChanged ;
280294 }
281295
282- private function resolveParamType (Param $ param ): null |Identifier |Name |ComplexType
283- {
284- if (! $ param ->type instanceof Node) {
296+ private function resolveParamType (
297+ ?ExtendedParameterReflection $ extendedParameterReflection
298+ ): null |Identifier |Name |ComplexType {
299+ if (! $ extendedParameterReflection instanceof ExtendedParameterReflection) {
285300 return null ;
286301 }
287302
288- return $ this ->nodeFactory ->createReprintedNode ($ param ->type );
303+ return $ this ->staticTypeMapper ->mapPHPStanTypeToPhpParserNode (
304+ $ extendedParameterReflection ->getNativeType (),
305+ TypeKind::PARAM
306+ );
289307 }
290308
291309 /**
310+ * @param ReflectionParameter[] $parentClassMethodParams
292311 * @return string[]
293312 */
294- private function collectParamNamesNextKey (ClassMethod $ classMethod , int $ key ): array
313+ private function collectParamNamesNextKey (array $ parentClassMethodParams , int $ key ): array
295314 {
296315 $ paramNames = [];
297316
298- foreach ($ classMethod -> params as $ paramKey => $ param ) {
317+ foreach ($ parentClassMethodParams as $ paramKey => $ param ) {
299318 if ($ paramKey > $ key ) {
300- $ paramNames [] = $ this ->getName ($ param );
319+ $ paramNames [] = $ param ->getName ();
301320 }
302321 }
303322
304323 return $ paramNames ;
305324 }
325+
326+ /**
327+ * @return AttributeGroup[]
328+ */
329+ private function createAttributeGroups (ReflectionParameter $ reflectionParameter ): array
330+ {
331+ $ attributeGroups = [];
332+
333+ foreach ($ reflectionParameter ->getAttributes () as $ reflectionAttribute ) {
334+ $ args = [];
335+ foreach ($ reflectionAttribute ->getArgumentsExpressions () as $ name => $ argumentExpression ) {
336+ $ args [] = new Arg (
337+ $ this ->nodeFactory ->createReprintedNode ($ argumentExpression ),
338+ false ,
339+ false ,
340+ [],
341+ is_string ($ name ) ? new Identifier ($ name ) : null
342+ );
343+ }
344+
345+ $ attributeGroups [] = new AttributeGroup ([
346+ new Attribute (new FullyQualified ($ reflectionAttribute ->getName ()), $ args ),
347+ ]);
348+ }
349+
350+ return $ attributeGroups ;
351+ }
306352}
0 commit comments