55
66use PhpParser \Comment ;
77use PhpParser \Node ;
8+ use PhpParser \Node \Arg ;
9+ use PhpParser \Node \Attribute ;
10+ use PhpParser \Node \AttributeGroup ;
811use PhpParser \Node \ComplexType ;
912use PhpParser \Node \Expr ;
1013use PhpParser \Node \Expr \Variable ;
1114use PhpParser \Node \Identifier ;
1215use PhpParser \Node \Name ;
16+ use PhpParser \Node \Name \FullyQualified ;
1317use PhpParser \Node \Param ;
1418use PhpParser \Node \Stmt \Class_ ;
1519use PhpParser \Node \Stmt \ClassMethod ;
20+ use PHPStan \BetterReflection \Reflection \Adapter \ReflectionParameter ;
1621use PHPStan \Reflection \ClassReflection ;
22+ use PHPStan \Reflection \ExtendedParameterReflection ;
1723use PHPStan \Reflection \MethodReflection ;
24+ use PHPStan \Reflection \ParametersAcceptorSelector ;
1825use Rector \NodeTypeResolver \Node \AttributeKey ;
19- use Rector \PhpParser \AstResolver ;
2026use Rector \PhpParser \Node \BetterNodeFinder ;
2127use Rector \PhpParser \Printer \BetterStandardPrinter ;
2228use Rector \PHPStan \ScopeFetcher ;
29+ use Rector \PHPStanStaticTypeMapper \Enum \TypeKind ;
2330use Rector \Rector \AbstractRector ;
31+ use Rector \StaticTypeMapper \StaticTypeMapper ;
2432use Rector \ValueObject \MethodName ;
2533use Rector \ValueObject \PhpVersionFeature ;
2634use Rector \VendorLocker \ParentClassMethodTypeOverrideGuard ;
@@ -39,7 +47,7 @@ final class AddParamBasedOnParentClassMethodRector extends AbstractRector implem
3947 /**
4048 * @readonly
4149 */
42- private AstResolver $ astResolver ;
50+ private StaticTypeMapper $ staticTypeMapper ;
4351 /**
4452 * @readonly
4553 */
@@ -48,10 +56,10 @@ final class AddParamBasedOnParentClassMethodRector extends AbstractRector implem
4856 * @readonly
4957 */
5058 private BetterNodeFinder $ betterNodeFinder ;
51- public function __construct (ParentClassMethodTypeOverrideGuard $ parentClassMethodTypeOverrideGuard , AstResolver $ astResolver , BetterStandardPrinter $ betterStandardPrinter , BetterNodeFinder $ betterNodeFinder )
59+ public function __construct (ParentClassMethodTypeOverrideGuard $ parentClassMethodTypeOverrideGuard , StaticTypeMapper $ staticTypeMapper , BetterStandardPrinter $ betterStandardPrinter , BetterNodeFinder $ betterNodeFinder )
5260 {
5361 $ this ->parentClassMethodTypeOverrideGuard = $ parentClassMethodTypeOverrideGuard ;
54- $ this ->astResolver = $ astResolver ;
62+ $ this ->staticTypeMapper = $ staticTypeMapper ;
5563 $ this ->betterStandardPrinter = $ betterStandardPrinter ;
5664 $ this ->betterNodeFinder = $ betterNodeFinder ;
5765 }
@@ -128,19 +136,21 @@ public function refactor(Node $node): ?Node
128136 if ($ isPDO && $ parentMethodReflection ->getName () === 'query ' ) {
129137 continue ;
130138 }
131- $ parentClassMethod = $ this ->astResolver ->resolveClassMethodFromMethodReflection ($ parentMethodReflection );
132- if (!$ parentClassMethod instanceof ClassMethod) {
139+ $ parentClassReflection = $ parentMethodReflection ->getDeclaringClass ();
140+ $ nativeClassReflection = $ parentClassReflection ->getNativeReflection ();
141+ if (!$ nativeClassReflection ->hasMethod ($ parentMethodReflection ->getName ())) {
133142 continue ;
134143 }
135144 $ currentClassMethodParams = $ classMethod ->getParams ();
136- $ parentClassMethodParams = $ parentClassMethod ->getParams ();
145+ $ parentClassMethodParams = $ nativeClassReflection ->getMethod ($ parentMethodReflection ->getName ())->getParameters ();
146+ $ parentParameterReflections = ParametersAcceptorSelector::combineAcceptors ($ parentMethodReflection ->getVariants ())->getParameters ();
137147 $ countCurrentClassMethodParams = count ($ currentClassMethodParams );
138148 $ countParentClassMethodParams = count ($ parentClassMethodParams );
139149 if ($ countCurrentClassMethodParams === $ countParentClassMethodParams ) {
140150 continue ;
141151 }
142152 if ($ countCurrentClassMethodParams < $ countParentClassMethodParams ) {
143- $ hasClassMethodChanged = $ this ->processReplaceClassMethodParams ($ classMethod , $ parentClassMethod , $ currentClassMethodParams , $ parentClassMethodParams );
153+ $ hasClassMethodChanged = $ this ->processReplaceClassMethodParams ($ classMethod , $ currentClassMethodParams , $ parentClassMethodParams , $ parentParameterReflections );
144154 if ($ hasClassMethodChanged ) {
145155 $ hasChanged = \true;
146156 }
@@ -158,7 +168,7 @@ public function refactor(Node $node): ?Node
158168 }
159169 /**
160170 * @param Param[] $currentClassMethodParams
161- * @param Param [] $parentClassMethodParams
171+ * @param ReflectionParameter [] $parentClassMethodParams
162172 */
163173 private function processAddNullDefaultParam (array $ currentClassMethodParams , array $ parentClassMethodParams ): bool
164174 {
@@ -180,42 +190,44 @@ private function processAddNullDefaultParam(array $currentClassMethodParams, arr
180190 }
181191 /**
182192 * @param array<int, Param> $currentClassMethodParams
183- * @param array<int, Param> $parentClassMethodParams
193+ * @param array<int, ReflectionParameter> $parentClassMethodParams
194+ * @param array<int, ExtendedParameterReflection> $parentParameterReflections
184195 */
185- private function processReplaceClassMethodParams (ClassMethod $ node , ClassMethod $ parentClassMethod , array $ currentClassMethodParams , array $ parentClassMethodParams ): bool
196+ private function processReplaceClassMethodParams (ClassMethod $ classMethod , array $ currentClassMethodParams , array $ parentClassMethodParams , array $ parentParameterReflections ): bool
186197 {
187- $ originalParams = $ node ->params ;
198+ $ originalParams = $ classMethod ->params ;
188199 $ hasChanged = \false;
189200 foreach ($ parentClassMethodParams as $ key => $ parentClassMethodParam ) {
190201 if (isset ($ currentClassMethodParams [$ key ])) {
191202 $ currentParamName = $ this ->getName ($ currentClassMethodParams [$ key ]);
192- $ collectParamNamesNextKey = $ this ->collectParamNamesNextKey ($ parentClassMethod , $ key );
203+ $ collectParamNamesNextKey = $ this ->collectParamNamesNextKey ($ parentClassMethodParams , $ key );
193204 if (in_array ($ currentParamName , $ collectParamNamesNextKey , \true)) {
194- $ node ->params = $ originalParams ;
205+ $ classMethod ->params = $ originalParams ;
195206 return \false;
196207 }
197208 continue ;
198209 }
199- $ isUsedInStmts = (bool ) $ this ->betterNodeFinder ->findFirstInFunctionLikeScoped ($ node , function (Node $ subNode ) use ($ parentClassMethodParam ): bool {
210+ $ isUsedInStmts = (bool ) $ this ->betterNodeFinder ->findFirstInFunctionLikeScoped ($ classMethod , function (Node $ subNode ) use ($ parentClassMethodParam ): bool {
200211 if (!$ subNode instanceof Variable) {
201212 return \false;
202213 }
203- return $ this ->nodeComparator -> areNodesEqual ($ subNode , $ parentClassMethodParam ->var );
214+ return $ this ->isName ($ subNode , $ parentClassMethodParam ->getName () );
204215 });
205216 if ($ isUsedInStmts ) {
206- $ node ->params = $ originalParams ;
217+ $ classMethod ->params = $ originalParams ;
207218 return \false;
208219 }
209- $ paramDefault = $ parentClassMethodParam -> default ;
210- if ($ paramDefault instanceof Expr ) {
211- $ paramDefault = $ this ->nodeFactory ->createReprintedNode ($ paramDefault );
220+ $ paramDefault = null ;
221+ if ($ parentClassMethodParam -> isDefaultValueAvailable () ) {
222+ $ paramDefault = $ this ->nodeFactory ->createReprintedNode ($ parentClassMethodParam -> getDefaultValueExpression () );
212223 }
213- $ paramName = $ this ->getName ($ parentClassMethodParam );
214- $ paramType = $ this ->resolveParamType ($ parentClassMethodParam );
215- $ node ->params [$ key ] = new Param (new Variable ($ paramName ), $ paramDefault , $ paramType , $ parentClassMethodParam ->byRef , $ parentClassMethodParam ->variadic , [], $ parentClassMethodParam ->flags );
216- if ($ parentClassMethodParam ->attrGroups !== []) {
217- $ attrGroupsAsComment = $ this ->betterStandardPrinter ->print ($ parentClassMethodParam ->attrGroups );
218- $ node ->params [$ key ]->setAttribute (AttributeKey::COMMENTS , [new Comment ($ attrGroupsAsComment )]);
224+ $ paramName = $ parentClassMethodParam ->getName ();
225+ $ paramType = $ this ->resolveParamType ($ parentParameterReflections [$ key ] ?? null );
226+ $ classMethod ->params [$ key ] = new Param (new Variable ($ paramName ), $ paramDefault , $ paramType , $ parentClassMethodParam ->isPassedByReference (), $ parentClassMethodParam ->isVariadic ());
227+ $ attributeGroups = $ this ->createAttributeGroups ($ parentClassMethodParam );
228+ if ($ attributeGroups !== []) {
229+ $ attrGroupsAsComment = $ this ->betterStandardPrinter ->print ($ attributeGroups );
230+ $ classMethod ->params [$ key ]->setAttribute (AttributeKey::COMMENTS , [new Comment ($ attrGroupsAsComment )]);
219231 }
220232 $ hasChanged = \true;
221233 }
@@ -224,24 +236,40 @@ private function processReplaceClassMethodParams(ClassMethod $node, ClassMethod
224236 /**
225237 * @return null|\PhpParser\Node\Identifier|\PhpParser\Node\Name|\PhpParser\Node\ComplexType
226238 */
227- private function resolveParamType (Param $ param )
239+ private function resolveParamType (? ExtendedParameterReflection $ extendedParameterReflection )
228240 {
229- if (!$ param -> type instanceof Node ) {
241+ if (!$ extendedParameterReflection instanceof ExtendedParameterReflection ) {
230242 return null ;
231243 }
232- return $ this ->nodeFactory -> createReprintedNode ( $ param -> type );
244+ return $ this ->staticTypeMapper -> mapPHPStanTypeToPhpParserNode ( $ extendedParameterReflection -> getNativeType (), TypeKind:: PARAM );
233245 }
234246 /**
247+ * @param ReflectionParameter[] $parentClassMethodParams
235248 * @return string[]
236249 */
237- private function collectParamNamesNextKey (ClassMethod $ classMethod , int $ key ): array
250+ private function collectParamNamesNextKey (array $ parentClassMethodParams , int $ key ): array
238251 {
239252 $ paramNames = [];
240- foreach ($ classMethod -> params as $ paramKey => $ param ) {
253+ foreach ($ parentClassMethodParams as $ paramKey => $ param ) {
241254 if ($ paramKey > $ key ) {
242- $ paramNames [] = $ this ->getName ($ param );
255+ $ paramNames [] = $ param ->getName ();
243256 }
244257 }
245258 return $ paramNames ;
246259 }
260+ /**
261+ * @return AttributeGroup[]
262+ */
263+ private function createAttributeGroups (ReflectionParameter $ reflectionParameter ): array
264+ {
265+ $ attributeGroups = [];
266+ foreach (method_exists ($ reflectionParameter , 'getAttributes ' ) ? $ reflectionParameter ->getAttributes () : [] as $ reflectionAttribute ) {
267+ $ args = [];
268+ foreach ($ reflectionAttribute ->getArgumentsExpressions () as $ name => $ argumentExpression ) {
269+ $ args [] = new Arg ($ this ->nodeFactory ->createReprintedNode ($ argumentExpression ), \false, \false, [], is_string ($ name ) ? new Identifier ($ name ) : null );
270+ }
271+ $ attributeGroups [] = new AttributeGroup ([new Attribute (new FullyQualified ($ reflectionAttribute ->getName ()), $ args )]);
272+ }
273+ return $ attributeGroups ;
274+ }
247275}
0 commit comments