55use Doctrine \ORM \EntityRepository ;
66use Doctrine \ORM \QueryBuilder ;
77use PhpParser \Node \Expr ;
8+ use PhpParser \Node \Expr \CallLike ;
89use PhpParser \Node \Expr \MethodCall ;
10+ use PhpParser \Node \Expr \StaticCall ;
911use PhpParser \Node \Identifier ;
12+ use PhpParser \Node \Name ;
1013use PHPStan \Analyser \Scope ;
14+ use PHPStan \Reflection \MethodReflection ;
1115use PHPStan \Reflection \ParametersAcceptorSelector ;
1216use PHPStan \Type \ExpressionTypeResolverExtension ;
1317use PHPStan \Type \ObjectType ;
@@ -30,30 +34,15 @@ public function __construct(
3034
3135 public function getType (Expr $ expr , Scope $ scope ): ?Type
3236 {
33- if (!$ expr instanceof MethodCall) {
37+ if (!$ expr instanceof MethodCall && ! $ expr instanceof StaticCall ) {
3438 return null ;
3539 }
3640
3741 if ($ expr ->isFirstClassCallable ()) {
3842 return null ;
3943 }
4044
41- if (!$ expr ->name instanceof Identifier) {
42- return null ;
43- }
44-
45- $ callerType = $ scope ->getType ($ expr ->var );
46-
47- foreach ($ callerType ->getObjectClassReflections () as $ callerClassReflection ) {
48- if ($ callerClassReflection ->is (QueryBuilder::class)) {
49- return null ; // covered by QueryBuilderMethodDynamicReturnTypeExtension
50- }
51- if ($ callerClassReflection ->is (EntityRepository::class) && $ expr ->name ->name === 'createQueryBuilder ' ) {
52- return null ; // covered by EntityRepositoryCreateQueryBuilderDynamicReturnTypeExtension
53- }
54- }
55-
56- $ methodReflection = $ scope ->getMethodReflection ($ callerType , $ expr ->name ->name );
45+ $ methodReflection = $ this ->getMethodReflection ($ expr , $ scope );
5746
5847 if ($ methodReflection === null ) {
5948 return null ;
@@ -67,12 +56,44 @@ public function getType(Expr $expr, Scope $scope): ?Type
6756 return null ;
6857 }
6958
70- $ queryBuilderTypes = $ this ->otherMethodQueryBuilderParser ->findQueryBuilderTypesInCalledMethod ($ scope , $ expr );
59+ $ queryBuilderTypes = $ this ->otherMethodQueryBuilderParser ->findQueryBuilderTypesInCalledMethod ($ scope , $ methodReflection );
7160 if (count ($ queryBuilderTypes ) === 0 ) {
7261 return null ;
7362 }
7463
7564 return TypeCombinator::union (...$ queryBuilderTypes );
7665 }
7766
67+ /**
68+ * @param StaticCall|MethodCall $call
69+ */
70+ private function getMethodReflection (CallLike $ call , Scope $ scope ): ?MethodReflection
71+ {
72+ if (!$ call ->name instanceof Identifier) {
73+ return null ;
74+ }
75+
76+ if ($ call instanceof MethodCall) {
77+ $ callerType = $ scope ->getType ($ call ->var );
78+ } else {
79+ if (!$ call ->class instanceof Name) {
80+ return null ;
81+ }
82+ $ callerType = $ scope ->resolveTypeByName ($ call ->class );
83+ }
84+
85+ $ methodName = $ call ->name ->name ;
86+
87+ foreach ($ callerType ->getObjectClassReflections () as $ callerClassReflection ) {
88+ if ($ callerClassReflection ->is (QueryBuilder::class)) {
89+ return null ; // covered by QueryBuilderMethodDynamicReturnTypeExtension
90+ }
91+ if ($ callerClassReflection ->is (EntityRepository::class) && $ methodName === 'createQueryBuilder ' ) {
92+ return null ; // covered by EntityRepositoryCreateQueryBuilderDynamicReturnTypeExtension
93+ }
94+ }
95+
96+ return $ scope ->getMethodReflection ($ callerType , $ methodName );
97+ }
98+
7899}
0 commit comments