Skip to content

Commit 0bc75d9

Browse files
authored
Fix TypeUtils::getDirectClassNames for nested type (#1380)
1 parent 1232186 commit 0bc75d9

File tree

5 files changed

+94
-4
lines changed

5 files changed

+94
-4
lines changed

src/Type/TypeUtils.php

+2-4
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,9 @@ public static function getDirectClassNames(Type $type): array
145145
if ($type instanceof UnionType || $type instanceof IntersectionType) {
146146
$classNames = [];
147147
foreach ($type->getTypes() as $innerType) {
148-
if (!$innerType instanceof TypeWithClassName) {
149-
continue;
148+
foreach (self::getDirectClassNames($innerType) as $n) {
149+
$classNames[] = $n;
150150
}
151-
152-
$classNames[] = $innerType->getClassName();
153151
}
154152

155153
return $classNames;

tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public function dataAsserts(): iterable
1818

1919
yield from $this->gatherAssertTypes(__DIR__ . '/data/dynamic-method-return-compound-types.php');
2020
yield from $this->gatherAssertTypes(__DIR__ . '/data/dynamic-method-return-getsingle-conditional.php');
21+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7344.php');
2122
}
2223

2324
/**

tests/PHPStan/Analyser/data/TestDynamicReturnTypeExtensions.php

+31
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,26 @@
22

33
namespace PHPStan\Tests;
44

5+
use PhpParser\Node\Expr\ClassConstFetch;
56
use PhpParser\Node\Expr\MethodCall;
67
use PhpParser\Node\Expr\StaticCall;
78
use PHPStan\Analyser\Scope;
9+
use PHPStan\Reflection\Dummy\ChangedTypeMethodReflection;
810
use PHPStan\Reflection\MethodReflection;
911
use PHPStan\Reflection\ParametersAcceptorSelector;
12+
use PHPStan\Reflection\ResolvedMethodReflection;
13+
use PHPStan\Reflection\Type\CalledOnTypeUnresolvedMethodPrototypeReflection;
14+
use PHPStan\Reflection\Type\UnionTypeMethodReflection;
1015
use PHPStan\Type\Constant\ConstantStringType;
1116
use PHPStan\Type\DynamicMethodReturnTypeExtension;
1217
use PHPStan\Type\DynamicStaticMethodReturnTypeExtension;
18+
use PHPStan\Type\IntegerType;
19+
use PHPStan\Type\IntersectionType;
20+
use PHPStan\Type\NeverType;
1321
use PHPStan\Type\ObjectType;
1422
use PHPStan\Type\ObjectWithoutClassType;
1523
use PHPStan\Type\Type;
24+
use PHPStan\Type\TypeCombinator;
1625

1726
class GetByPrimaryDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
1827
{
@@ -209,3 +218,25 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method
209218
}
210219

211220
}
221+
222+
class Bug7344DynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
223+
{
224+
public function getClass(): string
225+
{
226+
return \Bug7344\Model::class;
227+
}
228+
229+
public function isMethodSupported(MethodReflection $methodReflection): bool
230+
{
231+
return $methodReflection->getName() === 'getModel';
232+
}
233+
234+
public function getTypeFromMethodCall(
235+
MethodReflection $methodReflection,
236+
MethodCall $methodCall,
237+
Scope $scope
238+
): Type {
239+
return new IntegerType();
240+
}
241+
242+
}
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace Bug7344;
4+
5+
use Exception;
6+
use function PHPStan\Testing\assertType;
7+
8+
interface PhpdocTypeInterface
9+
{
10+
/**
11+
* Interface for phpdoc type for Phpstan only
12+
*
13+
* @return never
14+
*/
15+
public function neverImplement(): void;
16+
}
17+
18+
interface IsEntity extends PhpdocTypeInterface
19+
{
20+
}
21+
22+
class Model
23+
{
24+
25+
public function getModel(bool $allowOnModel = false): self
26+
{
27+
return $this;
28+
}
29+
}
30+
31+
class Person extends Model
32+
{
33+
}
34+
35+
class Female extends Person
36+
{
37+
}
38+
39+
class Male extends Person
40+
{
41+
}
42+
43+
class Foo
44+
{
45+
46+
/** @param Male|Female $maleOrFemale */
47+
public function doFoo($maleOrFemale): void
48+
{
49+
if (!$maleOrFemale instanceof IsEntity) {
50+
return;
51+
}
52+
53+
assertType('(Bug7344\Female&Bug7344\IsEntity)|(Bug7344\IsEntity&Bug7344\Male)', $maleOrFemale);
54+
assertType('int', $maleOrFemale->getModel());
55+
}
56+
}

tests/PHPStan/Analyser/dynamic-return-type.neon

+4
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,7 @@ services:
3131
class: PHPStan\Tests\ConditionalGetSingle
3232
tags:
3333
- phpstan.broker.dynamicMethodReturnTypeExtension
34+
-
35+
class: PHPStan\Tests\Bug7344DynamicReturnTypeExtension
36+
tags:
37+
- phpstan.broker.dynamicMethodReturnTypeExtension

0 commit comments

Comments
 (0)