@@ -114,8 +114,8 @@ private function registerMethodCall(
114114
115115 if ($ methodCall instanceof New_) {
116116 if ($ methodCall ->class instanceof Expr) {
117- $ callerType = $ scope ->getType ($ methodCall-> class );
118- $ possibleDescendantCall = true ;
117+ $ callerType = $ scope ->getType ($ methodCall );
118+ $ possibleDescendantCall = null ;
119119
120120 } elseif ($ methodCall ->class instanceof Name) {
121121 $ callerType = $ scope ->resolveTypeByName ($ methodCall ->class );
@@ -126,15 +126,15 @@ private function registerMethodCall(
126126 }
127127 } else {
128128 $ callerType = $ scope ->getType ($ methodCall ->var );
129- $ possibleDescendantCall = true ;
129+ $ possibleDescendantCall = null ;
130130 }
131131
132132 foreach ($ methodNames as $ methodName ) {
133- foreach ($ this ->getDeclaringTypesWithMethod ($ scope , $ callerType , $ methodName , TrinaryLogic::createNo ()) as $ className ) {
133+ foreach ($ this ->getDeclaringTypesWithMethod ($ methodName , $ callerType , TrinaryLogic::createNo (), $ possibleDescendantCall ) as $ methodRef ) {
134134 $ this ->registerUsage (
135135 new ClassMethodUsage (
136136 $ this ->usageOriginDetector ->detectOrigin ($ scope ),
137- new ClassMethodRef ( $ className , $ methodName , $ possibleDescendantCall ) ,
137+ $ methodRef ,
138138 ),
139139 $ methodCall ,
140140 $ scope ,
@@ -152,19 +152,19 @@ private function registerStaticCall(
152152
153153 if ($ staticCall ->class instanceof Expr) {
154154 $ callerType = $ scope ->getType ($ staticCall ->class );
155- $ possibleDescendantCall = true ;
155+ $ possibleDescendantCall = null ;
156156
157157 } else {
158158 $ callerType = $ scope ->resolveTypeByName ($ staticCall ->class );
159159 $ possibleDescendantCall = $ staticCall ->class ->toString () === 'static ' ;
160160 }
161161
162162 foreach ($ methodNames as $ methodName ) {
163- foreach ($ this ->getDeclaringTypesWithMethod ($ scope , $ callerType , $ methodName , TrinaryLogic::createYes ()) as $ className ) {
163+ foreach ($ this ->getDeclaringTypesWithMethod ($ methodName , $ callerType , TrinaryLogic::createYes (), $ possibleDescendantCall ) as $ methodRef ) {
164164 $ this ->registerUsage (
165165 new ClassMethodUsage (
166166 $ this ->usageOriginDetector ->detectOrigin ($ scope ),
167- new ClassMethodRef ( $ className , $ methodName , $ possibleDescendantCall ) ,
167+ $ methodRef ,
168168 ),
169169 $ staticCall ,
170170 $ scope ,
@@ -186,14 +186,11 @@ private function registerArrayCallable(
186186 $ caller = $ typeAndName ->getType ();
187187 $ methodName = $ typeAndName ->getMethod ();
188188
189- // currently always true, see https://github.com/phpstan/phpstan-src/pull/3372
190- $ possibleDescendantCall = !$ caller ->isClassString ()->yes ();
191-
192- foreach ($ this ->getDeclaringTypesWithMethod ($ scope , $ caller , $ methodName , TrinaryLogic::createMaybe ()) as $ className ) {
189+ foreach ($ this ->getDeclaringTypesWithMethod ($ methodName , $ caller , TrinaryLogic::createMaybe ()) as $ methodRef ) {
193190 $ this ->registerUsage (
194191 new ClassMethodUsage (
195192 $ this ->usageOriginDetector ->detectOrigin ($ scope ),
196- new ClassMethodRef ( $ className , $ methodName , $ possibleDescendantCall ) ,
193+ $ methodRef ,
197194 ),
198195 $ array ,
199196 $ scope ,
@@ -221,11 +218,11 @@ private function registerClone(Clone_ $node, Scope $scope): void
221218 $ methodName = '__clone ' ;
222219 $ callerType = $ scope ->getType ($ node ->expr );
223220
224- foreach ($ this ->getDeclaringTypesWithMethod ($ scope , $ callerType , $ methodName , TrinaryLogic::createNo ()) as $ className ) {
221+ foreach ($ this ->getDeclaringTypesWithMethod ($ methodName , $ callerType , TrinaryLogic::createNo ()) as $ methodRef ) {
225222 $ this ->registerUsage (
226223 new ClassMethodUsage (
227224 $ this ->usageOriginDetector ->detectOrigin ($ scope ),
228- new ClassMethodRef ( $ className , $ methodName , true ) ,
225+ $ methodRef ,
229226 ),
230227 $ node ,
231228 $ scope ,
@@ -257,13 +254,13 @@ private function getMethodName(CallLike $call, Scope $scope): array
257254 }
258255
259256 /**
260- * @return list<class-string<object>|null >
257+ * @return list<ClassMethodRef >
261258 */
262259 private function getDeclaringTypesWithMethod (
263- Scope $ scope ,
264- Type $ type ,
265260 string $ methodName ,
266- TrinaryLogic $ isStaticCall
261+ Type $ type ,
262+ TrinaryLogic $ isStaticCall ,
263+ ?bool $ isPossibleDescendant = null
267264 ): array
268265 {
269266 $ typeNoNull = TypeCombinator::removeNull ($ type ); // remove null to support nullsafe calls
@@ -273,15 +270,16 @@ private function getDeclaringTypesWithMethod(
273270 $ result = [];
274271
275272 foreach ($ classReflections as $ classReflection ) {
276- $ result [] = $ classReflection ->getName ();
273+ $ possibleDescendant = $ isPossibleDescendant ?? !$ classReflection ->isFinal ();
274+ $ result [] = new ClassMethodRef ($ classReflection ->getName (), $ methodName , $ possibleDescendant );
277275 }
278276
279277 if ($ this ->trackMixedAccess ) {
280278 $ canBeObjectCall = !$ typeNoNull ->isObject ()->no () && !$ isStaticCall ->yes ();
281279 $ canBeClassStringCall = !$ typeNoNull ->isClassString ()->no () && !$ isStaticCall ->no ();
282280
283281 if ($ result === [] && ($ canBeObjectCall || $ canBeClassStringCall )) {
284- $ result [] = null ; // call over unknown type
282+ $ result [] = new ClassMethodRef ( null , $ methodName , true ) ; // call over unknown type
285283 }
286284 }
287285
0 commit comments