Skip to content

Commit 18e223a

Browse files
Simplify
1 parent 4473157 commit 18e223a

1 file changed

Lines changed: 68 additions & 94 deletions

File tree

src/Type/Php/ReflectionClassGetConstantsDynamicReturnTypeExtension.php

Lines changed: 68 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@
1414
use PHPStan\Type\Constant\ConstantBooleanType;
1515
use PHPStan\Type\Constant\ConstantStringType;
1616
use PHPStan\Type\DynamicMethodReturnTypeExtension;
17-
use PHPStan\Type\ObjectWithoutClassType;
1817
use PHPStan\Type\Type;
1918
use PHPStan\Type\TypeCombinator;
2019
use ReflectionClass;
2120
use function count;
22-
use function is_int;
2321

2422
#[AutowiredService]
2523
final class ReflectionClassGetConstantsDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
@@ -41,16 +39,12 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method
4139
$calledOnType = $scope->getType($methodCall->var);
4240
$reflectionType = $calledOnType->getTemplateType(ReflectionClass::class, 'T');
4341

44-
if ((new ObjectWithoutClassType())->isSuperTypeOf($reflectionType)->no()) {
45-
return null;
46-
}
47-
4842
$classReflections = $reflectionType->getObjectClassReflections();
4943
if (count($classReflections) === 0) {
5044
return null;
5145
}
5246

53-
if ($this->isCovariantWithNonFinalClass($calledOnType, $classReflections)) {
47+
if (!$this->isInvariantOrFinalClass($calledOnType, $classReflections)) {
5448
return null;
5549
}
5650

@@ -65,17 +59,38 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method
6559
return $this->resolveGetConstants($scope, $classReflections, $filterType);
6660
}
6761

68-
/** @param non-empty-string $name */
69-
private function getConstantType(Scope $scope, ClassReflection $classReflection, string $name): Type
62+
/**
63+
* @param non-empty-list<ClassReflection> $classReflections
64+
*/
65+
private function isInvariantOrFinalClass(Type $calledOnType, array $classReflections): bool
7066
{
71-
return $scope->getType(new ClassConstFetch(
72-
new FullyQualified($classReflection->getName()),
73-
new Identifier($name),
74-
));
67+
$hasNonFinalClass = false;
68+
foreach ($classReflections as $classReflection) {
69+
if (!$classReflection->isFinal() && !$classReflection->isEnum()) {
70+
$hasNonFinalClass = true;
71+
break;
72+
}
73+
}
74+
75+
if (!$hasNonFinalClass) {
76+
return true;
77+
}
78+
79+
foreach ($calledOnType->getObjectClassReflections() as $reflectionClassReflection) {
80+
if ($reflectionClassReflection->getName() !== 'ReflectionClass') {
81+
return false;
82+
}
83+
$variance = $reflectionClassReflection->getCallSiteVarianceMap()->getVariance('T');
84+
if ($variance !== null && $variance->covariant()) {
85+
return false;
86+
}
87+
}
88+
89+
return true;
7590
}
7691

7792
/**
78-
* @param list<ClassReflection> $classReflections
93+
* @param non-empty-list<ClassReflection> $classReflections
7994
*/
8095
private function resolveGetConstant(MethodCall $methodCall, Scope $scope, array $classReflections): ?Type
8196
{
@@ -126,70 +141,14 @@ private function resolveGetConstant(MethodCall $methodCall, Scope $scope, array
126141
}
127142

128143
/**
129-
* @param list<ClassReflection> $classReflections
144+
* @param non-empty-string $name
130145
*/
131-
private function resolveGetConstants(Scope $scope, array $classReflections, ?Type $filterType): ?Type
132-
{
133-
if ($filterType === null) {
134-
return $this->buildConstantsArray($scope, $classReflections, null, false);
135-
}
136-
137-
$filterScalars = $filterType->getConstantScalarValues();
138-
$intFilters = [];
139-
foreach ($filterScalars as $scalar) {
140-
if (!is_int($scalar)) {
141-
$intFilters = null;
142-
break;
143-
}
144-
$intFilters[] = $scalar;
145-
}
146-
147-
if ($intFilters !== null && count($intFilters) === 1) {
148-
return $this->buildConstantsArray($scope, $classReflections, $intFilters[0], false);
149-
}
150-
151-
if ($intFilters !== null && count($intFilters) > 1) {
152-
$types = [];
153-
foreach ($intFilters as $filter) {
154-
$result = $this->buildConstantsArray($scope, $classReflections, $filter, false);
155-
if ($result !== null) {
156-
$types[] = $result;
157-
}
158-
}
159-
160-
if (count($types) === 0) {
161-
return null;
162-
}
163-
164-
return TypeCombinator::union(...$types);
165-
}
166-
167-
return $this->buildConstantsArray($scope, $classReflections, null, true);
168-
}
169-
170-
/**
171-
* @param list<ClassReflection> $classReflections
172-
*/
173-
private function buildConstantsArray(Scope $scope, array $classReflections, ?int $filter, bool $optional): ?Type
146+
private function getConstantType(Scope $scope, ClassReflection $classReflection, string $name): Type
174147
{
175-
$types = [];
176-
foreach ($classReflections as $classReflection) {
177-
$builder = ConstantArrayTypeBuilder::createEmpty();
178-
foreach ($this->getConstantNames($classReflection, $filter) as $name) {
179-
$builder->setOffsetValueType(
180-
new ConstantStringType($name),
181-
$this->getConstantType($scope, $classReflection, $name),
182-
$optional,
183-
);
184-
}
185-
$types[] = $builder->getArray();
186-
}
187-
188-
if (count($types) === 0) {
189-
return null;
190-
}
191-
192-
return TypeCombinator::union(...$types);
148+
return $scope->getType(new ClassConstFetch(
149+
new FullyQualified($classReflection->getName()),
150+
new Identifier($name),
151+
));
193152
}
194153

195154
/**
@@ -214,32 +173,47 @@ private function getConstantNames(ClassReflection $classReflection, ?int $filter
214173
return $names;
215174
}
216175

217-
/** @param list<ClassReflection> $classReflections */
218-
private function isCovariantWithNonFinalClass(Type $calledOnType, array $classReflections): bool
176+
/**
177+
* @param non-empty-list<ClassReflection> $classReflections
178+
*/
179+
private function resolveGetConstants(Scope $scope, array $classReflections, ?Type $filterType): ?Type
219180
{
220-
$hasNonFinalClass = false;
221-
foreach ($classReflections as $classReflection) {
222-
if (!$classReflection->isFinal() && !$classReflection->isEnum()) {
223-
$hasNonFinalClass = true;
224-
break;
225-
}
181+
if ($filterType === null) {
182+
return $this->buildConstantsArray($scope, $classReflections, null, false);
226183
}
227184

228-
if (!$hasNonFinalClass) {
229-
return false;
185+
$filterScalars = $filterType->getConstantScalarValues();
186+
if (count($filterScalars) === 0) {
187+
return $this->buildConstantsArray($scope, $classReflections, null, true);
230188
}
231189

232-
foreach ($calledOnType->getObjectClassReflections() as $reflectionClassReflection) {
233-
if ($reflectionClassReflection->getName() !== 'ReflectionClass') {
234-
continue;
235-
}
236-
$variance = $reflectionClassReflection->getCallSiteVarianceMap()->getVariance('T');
237-
if ($variance !== null && $variance->covariant()) {
238-
return true;
190+
$types = [];
191+
foreach ($filterScalars as $filter) {
192+
$types[] = $this->buildConstantsArray($scope, $classReflections, (int) $filter, false);
193+
}
194+
195+
return TypeCombinator::union(...$types);
196+
}
197+
198+
/**
199+
* @param non-empty-list<ClassReflection> $classReflections
200+
*/
201+
private function buildConstantsArray(Scope $scope, array $classReflections, ?int $filter, bool $optional): Type
202+
{
203+
$types = [];
204+
foreach ($classReflections as $classReflection) {
205+
$builder = ConstantArrayTypeBuilder::createEmpty();
206+
foreach ($this->getConstantNames($classReflection, $filter) as $name) {
207+
$builder->setOffsetValueType(
208+
new ConstantStringType($name),
209+
$this->getConstantType($scope, $classReflection, $name),
210+
$optional,
211+
);
239212
}
213+
$types[] = $builder->getArray();
240214
}
241215

242-
return false;
216+
return TypeCombinator::union(...$types);
243217
}
244218

245219
}

0 commit comments

Comments
 (0)