Skip to content

Commit c88052e

Browse files
phpstan-botclaude
andcommitted
Return union of GenericObjectType when multiple ReflectionAttribute subclasses match
When resolveReflectionAttributeClassNames finds multiple classes that extend ReflectionAttribute, create a union of GenericObjectType for each instead of falling back to the base ReflectionAttribute class. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6a2f58a commit c88052e

File tree

1 file changed

+15
-6
lines changed

1 file changed

+15
-6
lines changed

src/Type/Php/ReflectionGetAttributesMethodReturnTypeExtension.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use PHPStan\Type\IntersectionType;
1414
use PHPStan\Type\ObjectType;
1515
use PHPStan\Type\Type;
16+
use PHPStan\Type\TypeCombinator;
1617
use ReflectionAttribute;
1718
use function count;
1819

@@ -44,12 +45,20 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method
4445
$argType = $scope->getType($methodCall->getArgs()[0]->value);
4546
$classType = $argType->getClassStringObjectType();
4647

47-
$reflectionAttributeClassName = $this->resolveReflectionAttributeClassName($methodReflection);
48+
$reflectionAttributeClassNames = $this->resolveReflectionAttributeClassNames($methodReflection);
4849

49-
return new IntersectionType([new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new GenericObjectType($reflectionAttributeClassName, [$classType])), new AccessoryArrayListType()]);
50+
$valueTypes = [];
51+
foreach ($reflectionAttributeClassNames as $className) {
52+
$valueTypes[] = new GenericObjectType($className, [$classType]);
53+
}
54+
55+
return new IntersectionType([new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), TypeCombinator::union(...$valueTypes)), new AccessoryArrayListType()]);
5056
}
5157

52-
private function resolveReflectionAttributeClassName(MethodReflection $methodReflection): string
58+
/**
59+
* @return non-empty-list<string>
60+
*/
61+
private function resolveReflectionAttributeClassNames(MethodReflection $methodReflection): array
5362
{
5463
$returnType = $methodReflection->getVariants()[0]->getReturnType();
5564
$nativeReflectionAttributeType = new ObjectType(ReflectionAttribute::class);
@@ -61,11 +70,11 @@ private function resolveReflectionAttributeClassName(MethodReflection $methodRef
6170
}
6271
}
6372

64-
if (count($matchedClassNames) === 1) {
65-
return $matchedClassNames[0];
73+
if (count($matchedClassNames) === 0) {
74+
return [ReflectionAttribute::class];
6675
}
6776

68-
return ReflectionAttribute::class;
77+
return $matchedClassNames;
6978
}
7079

7180
}

0 commit comments

Comments
 (0)