@@ -114,8 +114,8 @@ private function registerMethodCall(
114
114
115
115
if ($ methodCall instanceof New_) {
116
116
if ($ methodCall ->class instanceof Expr) {
117
- $ callerType = $ scope ->getType ($ methodCall-> class );
118
- $ possibleDescendantCall = true ;
117
+ $ callerType = $ scope ->getType ($ methodCall );
118
+ $ possibleDescendantCall = null ;
119
119
120
120
} elseif ($ methodCall ->class instanceof Name) {
121
121
$ callerType = $ scope ->resolveTypeByName ($ methodCall ->class );
@@ -126,15 +126,15 @@ private function registerMethodCall(
126
126
}
127
127
} else {
128
128
$ callerType = $ scope ->getType ($ methodCall ->var );
129
- $ possibleDescendantCall = true ;
129
+ $ possibleDescendantCall = null ;
130
130
}
131
131
132
132
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 ) {
134
134
$ this ->registerUsage (
135
135
new ClassMethodUsage (
136
136
$ this ->usageOriginDetector ->detectOrigin ($ scope ),
137
- new ClassMethodRef ( $ className , $ methodName , $ possibleDescendantCall ) ,
137
+ $ methodRef ,
138
138
),
139
139
$ methodCall ,
140
140
$ scope ,
@@ -152,19 +152,19 @@ private function registerStaticCall(
152
152
153
153
if ($ staticCall ->class instanceof Expr) {
154
154
$ callerType = $ scope ->getType ($ staticCall ->class );
155
- $ possibleDescendantCall = true ;
155
+ $ possibleDescendantCall = null ;
156
156
157
157
} else {
158
158
$ callerType = $ scope ->resolveTypeByName ($ staticCall ->class );
159
159
$ possibleDescendantCall = $ staticCall ->class ->toString () === 'static ' ;
160
160
}
161
161
162
162
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 ) {
164
164
$ this ->registerUsage (
165
165
new ClassMethodUsage (
166
166
$ this ->usageOriginDetector ->detectOrigin ($ scope ),
167
- new ClassMethodRef ( $ className , $ methodName , $ possibleDescendantCall ) ,
167
+ $ methodRef ,
168
168
),
169
169
$ staticCall ,
170
170
$ scope ,
@@ -186,14 +186,11 @@ private function registerArrayCallable(
186
186
$ caller = $ typeAndName ->getType ();
187
187
$ methodName = $ typeAndName ->getMethod ();
188
188
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 ) {
193
190
$ this ->registerUsage (
194
191
new ClassMethodUsage (
195
192
$ this ->usageOriginDetector ->detectOrigin ($ scope ),
196
- new ClassMethodRef ( $ className , $ methodName , $ possibleDescendantCall ) ,
193
+ $ methodRef ,
197
194
),
198
195
$ array ,
199
196
$ scope ,
@@ -221,11 +218,11 @@ private function registerClone(Clone_ $node, Scope $scope): void
221
218
$ methodName = '__clone ' ;
222
219
$ callerType = $ scope ->getType ($ node ->expr );
223
220
224
- foreach ($ this ->getDeclaringTypesWithMethod ($ scope , $ callerType , $ methodName , TrinaryLogic::createNo ()) as $ className ) {
221
+ foreach ($ this ->getDeclaringTypesWithMethod ($ methodName , $ callerType , TrinaryLogic::createNo ()) as $ methodRef ) {
225
222
$ this ->registerUsage (
226
223
new ClassMethodUsage (
227
224
$ this ->usageOriginDetector ->detectOrigin ($ scope ),
228
- new ClassMethodRef ( $ className , $ methodName , true ) ,
225
+ $ methodRef ,
229
226
),
230
227
$ node ,
231
228
$ scope ,
@@ -257,13 +254,13 @@ private function getMethodName(CallLike $call, Scope $scope): array
257
254
}
258
255
259
256
/**
260
- * @return list<class-string<object>|null >
257
+ * @return list<ClassMethodRef >
261
258
*/
262
259
private function getDeclaringTypesWithMethod (
263
- Scope $ scope ,
264
- Type $ type ,
265
260
string $ methodName ,
266
- TrinaryLogic $ isStaticCall
261
+ Type $ type ,
262
+ TrinaryLogic $ isStaticCall ,
263
+ ?bool $ isPossibleDescendant = null
267
264
): array
268
265
{
269
266
$ typeNoNull = TypeCombinator::removeNull ($ type ); // remove null to support nullsafe calls
@@ -273,15 +270,16 @@ private function getDeclaringTypesWithMethod(
273
270
$ result = [];
274
271
275
272
foreach ($ classReflections as $ classReflection ) {
276
- $ result [] = $ classReflection ->getName ();
273
+ $ possibleDescendant = $ isPossibleDescendant ?? !$ classReflection ->isFinal ();
274
+ $ result [] = new ClassMethodRef ($ classReflection ->getName (), $ methodName , $ possibleDescendant );
277
275
}
278
276
279
277
if ($ this ->trackMixedAccess ) {
280
278
$ canBeObjectCall = !$ typeNoNull ->isObject ()->no () && !$ isStaticCall ->yes ();
281
279
$ canBeClassStringCall = !$ typeNoNull ->isClassString ()->no () && !$ isStaticCall ->no ();
282
280
283
281
if ($ result === [] && ($ canBeObjectCall || $ canBeClassStringCall )) {
284
- $ result [] = null ; // call over unknown type
282
+ $ result [] = new ClassMethodRef ( null , $ methodName , true ) ; // call over unknown type
285
283
}
286
284
}
287
285
0 commit comments