44
55namespace Rector \CodingStyle \Rector \FunctionLike ;
66
7- use PhpParser \Comment \Doc ;
87use PhpParser \Node ;
98use PhpParser \Node \Arg ;
109use PhpParser \Node \Expr ;
1413use PhpParser \Node \Expr \Closure ;
1514use PhpParser \Node \Expr \FuncCall ;
1615use PhpParser \Node \Expr \MethodCall ;
17- use PhpParser \Node \Expr \New_ ;
1816use PhpParser \Node \Expr \StaticCall ;
1917use PhpParser \Node \Expr \Variable ;
2018use PhpParser \Node \FunctionLike ;
2422use PhpParser \Node \VariadicPlaceholder ;
2523use PhpParser \NodeVisitor ;
2624use PHPStan \Analyser \Scope ;
27- use PHPStan \PhpDocParser \Ast \PhpDoc \ParamTagValueNode ;
2825use PHPStan \Reflection \Annotations \AnnotationMethodReflection ;
29- use PHPStan \Reflection \ExtendedFunctionVariant ;
3026use PHPStan \Reflection \Native \NativeFunctionReflection ;
31- use PHPStan \Reflection \ParametersAcceptorSelector ;
32- use PHPStan \Reflection \ResolvedFunctionVariantWithOriginal ;
33- use PHPStan \Type \CallableType ;
34- use PHPStan \Type \ObjectType ;
35- use PHPStan \Type \UnionType ;
36- use Rector \BetterPhpDocParser \PhpDocInfo \PhpDocInfoFactory ;
37- use Rector \NodeTypeResolver \PHPStan \ParametersAcceptorSelectorVariantsWrapper ;
3827use Rector \PhpParser \AstResolver ;
39- use Rector \PhpParser \Node \BetterNodeFinder ;
4028use Rector \PHPStan \ScopeFetcher ;
4129use Rector \Rector \AbstractRector ;
4230use Rector \Reflection \ReflectionResolver ;
@@ -62,9 +50,7 @@ final class FunctionLikeToFirstClassCallableRector extends AbstractRector implem
6250
6351 public function __construct (
6452 private readonly AstResolver $ astResolver ,
65- private readonly ReflectionResolver $ reflectionResolver ,
66- private readonly BetterNodeFinder $ betterNodeFinder ,
67- private readonly PhpDocInfoFactory $ phpDocInfoFactory
53+ private readonly ReflectionResolver $ reflectionResolver
6854 ) {
6955 }
7056
@@ -89,19 +75,11 @@ function ($parameter) {
8975
9076 public function getNodeTypes (): array
9177 {
92- return [
93- Assign::class,
94- MethodCall::class,
95- FuncCall::class,
96- StaticCall::class,
97- New_::class,
98- ArrowFunction::class,
99- Closure::class,
100- ];
78+ return [Assign::class, CallLike::class, ArrowFunction::class, Closure::class];
10179 }
10280
10381 /**
104- * @param MethodCall|FuncCall|StaticCall|New_ |ArrowFunction|Closure $node
82+ * @param CallLike |ArrowFunction|Closure $node
10583 */
10684 public function refactor (Node $ node ): null |CallLike
10785 {
@@ -118,99 +96,14 @@ public function refactor(Node $node): null|CallLike
11896 return null ;
11997 }
12098
121- $ args = $ node ->getArgs ();
122- foreach ($ args as $ key => $ arg ) {
123- if ($ arg ->value instanceof Closure || $ arg ->value instanceof ArrowFunction) {
124- // verify caller signature
125- $ methodReflection = $ this ->reflectionResolver ->resolveFunctionLikeReflectionFromCall ($ node );
126-
127- if ($ methodReflection === null ) {
128- return null ;
129- }
130-
131- $ reflection = ParametersAcceptorSelectorVariantsWrapper::select (
132- $ methodReflection ,
133- $ node ,
134- ScopeFetcher::fetch ($ node )
135- );
136-
137- if ($ reflection instanceof ResolvedFunctionVariantWithOriginal) {
138- $ reflection = ParametersAcceptorSelector::combineAcceptors (
139- $ methodReflection ->getVariants ()
140- );
141-
142- if (! $ reflection instanceof ExtendedFunctionVariant) {
143- return null ;
144- }
145- }
146-
147- $ classMethodOrFunction = $ this ->astResolver ->resolveClassMethodOrFunctionFromCall ($ node );
148- if (! $ classMethodOrFunction instanceof FunctionLike) {
149- return null ;
150- }
99+ $ methodReflection = $ this ->reflectionResolver ->resolveFunctionLikeReflectionFromCall ($ node );
100+ if ($ methodReflection instanceof NativeFunctionReflection) {
101+ return null ;
102+ }
151103
152- foreach ($ reflection ->getParameters () as $ index => $ parameterReflection ) {
153- if ($ index !== $ key ) {
154- continue ;
155- }
156-
157- if ($ parameterReflection ->getType () instanceof CallableType
158- &&
159- count ($ parameterReflection ->getType ()->getParameters ()) !== 1
160- && ! $ methodReflection instanceof NativeFunctionReflection
161- && $ this ->hasDocCommentForCallable ($ classMethodOrFunction , $ index )
162- ) {
163- $ args [$ key ]->value ->setAttribute (self ::HAS_CALLBACK_SIGNATURE_MULTI_PARAMS , true );
164- return null ;
165- }
166-
167- $ parameterName = $ parameterReflection ->getName ();
168-
169- $ isInvokable = (bool ) $ this ->betterNodeFinder ->findFirstInFunctionLikeScoped (
170- $ classMethodOrFunction ,
171- fn (Node $ node ): bool => $ node instanceof FuncCall
172- && $ node ->name instanceof Variable
173- && $ this ->isName ($ node ->name , $ parameterName )
174- && count ($ node ->args ) > 1
175- );
176-
177- if ($ isInvokable ) {
178- $ args [$ key ]->value ->setAttribute (self ::HAS_CALLBACK_SIGNATURE_MULTI_PARAMS , true );
179- return null ;
180- }
181-
182- $ isClosureBindTo = (bool ) $ this ->betterNodeFinder ->findFirstInFunctionLikeScoped (
183- $ classMethodOrFunction ,
184- function (Node $ node ) use ($ parameterName ): bool {
185- if (! $ node instanceof MethodCall) {
186- return false ;
187- }
188-
189- if (! $ node ->name instanceof Identifier) {
190- return false ;
191- }
192-
193- if (! $ this ->isName ($ node ->name , 'bindTo ' )) {
194- return false ;
195- }
196-
197- if (! $ node ->var instanceof Variable) {
198- return false ;
199- }
200-
201- if (! $ this ->isObjectType ($ node ->var , new ObjectType ('Closure ' ))) {
202- return false ;
203- }
204-
205- return $ this ->isName ($ node ->var , $ parameterName );
206- }
207- );
208-
209- if ($ isClosureBindTo ) {
210- $ args [$ key ]->value ->setAttribute (self ::HAS_CALLBACK_SIGNATURE_MULTI_PARAMS , true );
211- return null ;
212- }
213- }
104+ foreach ($ node ->getArgs () as $ arg ) {
105+ if ($ arg ->value instanceof Closure || $ arg ->value instanceof ArrowFunction) {
106+ $ arg ->value ->setAttribute (self ::HAS_CALLBACK_SIGNATURE_MULTI_PARAMS , true );
214107 }
215108 }
216109
@@ -237,37 +130,6 @@ public function provideMinPhpVersion(): int
237130 return PhpVersionFeature::FIRST_CLASS_CALLABLE_SYNTAX ;
238131 }
239132
240- private function hasDocCommentForCallable (FunctionLike $ functionLike , int $ index ): bool
241- {
242- $ docComment = $ functionLike ->getDocComment ();
243- if (! $ docComment instanceof Doc) {
244- return false ;
245- }
246-
247- $ phpDocInfo = $ this ->phpDocInfoFactory ->createFromNodeOrEmpty ($ functionLike );
248- $ params = $ functionLike ->getParams ();
249-
250- $ paramName = null ;
251- foreach ($ params as $ key => $ param ) {
252- if ($ key === $ index ) {
253- $ paramName = (string ) $ this ->getName ($ param );
254- break ;
255- }
256- }
257-
258- if ($ paramName === null ) {
259- return false ;
260- }
261-
262- $ paramTagValueNode = $ phpDocInfo ->getParamTagValueByName ($ paramName );
263- if ($ paramTagValueNode instanceof ParamTagValueNode) {
264- $ type = $ phpDocInfo ->getParamType ($ paramName );
265- return ($ type instanceof CallableType && count ($ type ->getParameters ()) !== 1 ) || $ type instanceof UnionType;
266- }
267-
268- return false ;
269- }
270-
271133 private function shouldSkip (
272134 ArrowFunction |Closure $ node ,
273135 FuncCall |MethodCall |StaticCall $ callLike ,
0 commit comments