Skip to content

Commit 2526e5c

Browse files
committed
Support enum cases
1 parent be1de74 commit 2526e5c

File tree

8 files changed

+127
-17
lines changed

8 files changed

+127
-17
lines changed

src/Reflection/ClassReflection.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public function __construct(
162162
private PhpDocInheritanceResolver $phpDocInheritanceResolver,
163163
private PhpVersion $phpVersion,
164164
private SignatureMapProvider $signatureMapProvider,
165-
private DeprecationProvider $deprecationResolver,
165+
private DeprecationProvider $deprecationProvider,
166166
private AttributeReflectionFactory $attributeReflectionFactory,
167167
private array $propertiesClassReflectionExtensions,
168168
private array $methodsClassReflectionExtensions,
@@ -795,7 +795,8 @@ public function getEnumCases(): array
795795
$valueType = $this->initializerExprTypeResolver->getType($case->getValueExpression(), $initializerExprContext);
796796
}
797797
$caseName = $case->getName();
798-
$cases[$caseName] = new EnumCaseReflection($this, $case, $valueType, $this->attributeReflectionFactory->fromNativeReflection($case->getAttributes(), InitializerExprContext::fromClass($this->getName(), $this->getFileName())));
798+
$attributes = $this->attributeReflectionFactory->fromNativeReflection($case->getAttributes(), InitializerExprContext::fromClass($this->getName(), $this->getFileName()));
799+
$cases[$caseName] = new EnumCaseReflection($this, $case, $valueType, $attributes, $this->deprecationProvider);
799800
}
800801

801802
return $this->enumCases = $cases;
@@ -821,7 +822,9 @@ public function getEnumCase(string $name): EnumCaseReflection
821822
$valueType = $this->initializerExprTypeResolver->getType($case->getValueExpression(), InitializerExprContext::fromClassReflection($this));
822823
}
823824

824-
return new EnumCaseReflection($this, $case, $valueType, $this->attributeReflectionFactory->fromNativeReflection($case->getAttributes(), InitializerExprContext::fromClass($this->getName(), $this->getFileName())));
825+
$attributes = $this->attributeReflectionFactory->fromNativeReflection($case->getAttributes(), InitializerExprContext::fromClass($this->getName(), $this->getFileName()));
826+
827+
return new EnumCaseReflection($this, $case, $valueType, $attributes, $this->deprecationProvider);
825828
}
826829

827830
public function isClass(): bool
@@ -1081,7 +1084,7 @@ public function getConstant(string $name): ClassConstantReflection
10811084
throw new MissingConstantFromReflectionException($this->getName(), $name);
10821085
}
10831086

1084-
$deprecation = $this->deprecationResolver->getClassConstantDeprecation($reflectionConstant);
1087+
$deprecation = $this->deprecationProvider->getClassConstantDeprecation($reflectionConstant);
10851088
$deprecatedDescription = $deprecation === null ? null : $deprecation->getDescription();
10861089
$isDeprecated = $deprecation !== null;
10871090

@@ -1239,7 +1242,7 @@ public function isDeprecated(): bool
12391242
*/
12401243
private function resolveDeprecation(): void
12411244
{
1242-
$deprecation = $this->deprecationResolver->isClassDeprecated($this->reflection);
1245+
$deprecation = $this->deprecationProvider->isClassDeprecated($this->reflection);
12431246
if ($deprecation !== null) {
12441247
$this->isDeprecated = true;
12451248
$this->deprecatedDescription = $deprecation->getDescription();
@@ -1587,7 +1590,7 @@ public function withTypes(array $types): self
15871590
$this->phpDocInheritanceResolver,
15881591
$this->phpVersion,
15891592
$this->signatureMapProvider,
1590-
$this->deprecationResolver,
1593+
$this->deprecationProvider,
15911594
$this->attributeReflectionFactory,
15921595
$this->propertiesClassReflectionExtensions,
15931596
$this->methodsClassReflectionExtensions,
@@ -1619,7 +1622,7 @@ public function withVariances(array $variances): self
16191622
$this->phpDocInheritanceResolver,
16201623
$this->phpVersion,
16211624
$this->signatureMapProvider,
1622-
$this->deprecationResolver,
1625+
$this->deprecationProvider,
16231626
$this->attributeReflectionFactory,
16241627
$this->propertiesClassReflectionExtensions,
16251628
$this->methodsClassReflectionExtensions,
@@ -1661,7 +1664,7 @@ public function asFinal(): self
16611664
$this->phpDocInheritanceResolver,
16621665
$this->phpVersion,
16631666
$this->signatureMapProvider,
1664-
$this->deprecationResolver,
1667+
$this->deprecationProvider,
16651668
$this->attributeReflectionFactory,
16661669
$this->propertiesClassReflectionExtensions,
16671670
$this->methodsClassReflectionExtensions,

src/Reflection/Deprecation/DeprecationProvider.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionClass;
66
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionClassConstant;
77
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnum;
8+
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnumBackedCase;
9+
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnumUnitCase;
810
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionFunction;
911
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionMethod;
1012
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionProperty;
@@ -32,6 +34,9 @@ final class DeprecationProvider
3234
/** @var array<ConstantDeprecationExtension> $constantDeprecationExtensions */
3335
private array $constantDeprecationExtensions;
3436

37+
/** @var array<EnumCaseDeprecationExtension> $enumCaseDeprecationExtensions */
38+
private array $enumCaseDeprecationExtensions;
39+
3540
public function __construct(
3641
Container $container,
3742
)
@@ -42,6 +47,7 @@ public function __construct(
4247
$this->classDeprecationExtensions = $container->getServicesByTag('phpstan.classDeprecationExtension');
4348
$this->functionDeprecationExtensions = $container->getServicesByTag('phpstan.functionDeprecationExtension');
4449
$this->constantDeprecationExtensions = $container->getServicesByTag('phpstan.constantDeprecationExtension');
50+
$this->enumCaseDeprecationExtensions = $container->getServicesByTag('phpstan.enumCaseDeprecationExtension');
4551
}
4652

4753
public function getPropertyDeprecation(ReflectionProperty $reflectionProperty): ?Deprecation
@@ -116,4 +122,16 @@ public function getConstantDeprecation(ReflectionConstant $constantReflection):
116122
return null;
117123
}
118124

125+
public function getEnumCaseDeprecation(ReflectionEnumUnitCase|ReflectionEnumBackedCase $enumCaseReflection): ?Deprecation
126+
{
127+
foreach ($this->enumCaseDeprecationExtensions as $extension) {
128+
$deprecation = $extension->getEnumCaseDeprecation($enumCaseReflection);
129+
if ($deprecation !== null) {
130+
return $deprecation;
131+
}
132+
}
133+
134+
return null;
135+
}
136+
119137
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Reflection\Deprecation;
4+
5+
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnumBackedCase;
6+
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnumUnitCase;
7+
8+
/**
9+
* This interface allows you to provide custom deprecation information
10+
*
11+
* To register it in the configuration file use the following tag:
12+
*
13+
* ```
14+
* services:
15+
* -
16+
* class: App\PHPStan\MyProvider
17+
* tags:
18+
* - phpstan.enumCaseDeprecationExtension
19+
* ```
20+
*
21+
* @api
22+
*/
23+
interface EnumCaseDeprecationExtension
24+
{
25+
26+
public function getEnumCaseDeprecation(ReflectionEnumUnitCase|ReflectionEnumBackedCase $reflection): ?Deprecation;
27+
28+
}

src/Reflection/EnumCaseReflection.php

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnumBackedCase;
66
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnumUnitCase;
77
use PHPStan\Internal\DeprecatedAttributeHelper;
8+
use PHPStan\Reflection\Deprecation\DeprecationProvider;
89
use PHPStan\TrinaryLogic;
910
use PHPStan\Type\Type;
1011

@@ -14,6 +15,10 @@
1415
final class EnumCaseReflection
1516
{
1617

18+
private bool $isDeprecated;
19+
20+
private ?string $deprecatedDescription;
21+
1722
/**
1823
* @param list<AttributeReflection> $attributes
1924
*/
@@ -22,8 +27,22 @@ public function __construct(
2227
private ReflectionEnumUnitCase|ReflectionEnumBackedCase $reflection,
2328
private ?Type $backingValueType,
2429
private array $attributes,
30+
DeprecationProvider $deprecationProvider,
2531
)
2632
{
33+
$deprecation = $deprecationProvider->getEnumCaseDeprecation($reflection);
34+
if ($deprecation !== null) {
35+
$this->isDeprecated = true;
36+
$this->deprecatedDescription = $deprecation->getDescription();
37+
38+
} elseif ($reflection->isDeprecated()) {
39+
$attributes = $this->reflection->getBetterReflection()->getAttributes();
40+
$this->isDeprecated = true;
41+
$this->deprecatedDescription = DeprecatedAttributeHelper::getDeprecatedDescription($attributes);
42+
} else {
43+
$this->isDeprecated = false;
44+
$this->deprecatedDescription = null;
45+
}
2746
}
2847

2948
public function getDeclaringEnum(): ClassReflection
@@ -43,17 +62,12 @@ public function getBackingValueType(): ?Type
4362

4463
public function isDeprecated(): TrinaryLogic
4564
{
46-
return TrinaryLogic::createFromBoolean($this->reflection->isDeprecated());
65+
return TrinaryLogic::createFromBoolean($this->isDeprecated);
4766
}
4867

4968
public function getDeprecatedDescription(): ?string
5069
{
51-
if ($this->reflection->isDeprecated()) {
52-
$attributes = $this->reflection->getBetterReflection()->getAttributes();
53-
return DeprecatedAttributeHelper::getDeprecatedDescription($attributes);
54-
}
55-
56-
return null;
70+
return $this->deprecatedDescription;
5771
}
5872

5973
/**

tests/PHPStan/Reflection/Deprecation/DeprecationProviderTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use CustomDeprecations\DoubleDeprecatedClass;
88
use CustomDeprecations\DoubleDeprecatedClassOnlyAttributeMessage;
99
use CustomDeprecations\DoubleDeprecatedClassOnlyPhpDocMessage;
10+
use CustomDeprecations\MyDeprecatedEnum;
1011
use CustomDeprecations\NotDeprecatedClass;
1112
use CustomDeprecations\PhpDocDeprecatedClass;
1213
use CustomDeprecations\PhpDocDeprecatedClassWithMessage;
@@ -58,6 +59,24 @@ public function testCustomDeprecations(): void
5859
$scopeForDoubleDeprecatedClassOnlyNativeMessage = $scopeFactory->create(ScopeContext::create('dummy.php')->enterClass($doubleDeprecatedClassOnlyPhpDocMessage));
5960
$scopeForDoubleDeprecatedClassOnlyCustomMessage = $scopeFactory->create(ScopeContext::create('dummy.php')->enterClass($doubleDeprecatedClassOnlyAttributeMessage));
6061

62+
// enum cases
63+
$myEnum = $reflectionProvider->getClass(MyDeprecatedEnum::class);
64+
65+
self::assertTrue($myEnum->isDeprecated());
66+
self::assertNull($myEnum->getDeprecatedDescription());
67+
68+
self::assertTrue($myEnum->getEnumCase('CustomDeprecated')->isDeprecated()->yes());
69+
self::assertSame('custom', $myEnum->getEnumCase('CustomDeprecated')->getDeprecatedDescription());
70+
71+
self::assertTrue($myEnum->getEnumCase('NativeDeprecated')->isDeprecated()->yes());
72+
self::assertSame('native', $myEnum->getEnumCase('NativeDeprecated')->getDeprecatedDescription());
73+
74+
self::assertTrue($myEnum->getEnumCase('PhpDocDeprecated')->isDeprecated()->yes());
75+
self::assertNull($myEnum->getEnumCase('PhpDocDeprecated')->getDeprecatedDescription()); // this should not be null
76+
77+
self::assertFalse($myEnum->getEnumCase('NotDeprecated')->isDeprecated()->yes());
78+
self::assertNull($myEnum->getEnumCase('NotDeprecated')->getDeprecatedDescription());
79+
6180
// class
6281
self::assertFalse($notDeprecatedClass->isDeprecated());
6382
self::assertNull($notDeprecatedClass->getDeprecatedDescription());

tests/PHPStan/Reflection/Deprecation/data/CustomDeprecationExtension.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionClass;
99
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionClassConstant;
1010
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnum;
11+
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnumBackedCase;
12+
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnumUnitCase;
1113
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionFunction;
1214
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionMethod;
1315
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionProperty;
@@ -16,6 +18,7 @@
1618
use PHPStan\Reflection\Deprecation\ClassDeprecationExtension;
1719
use PHPStan\Reflection\Deprecation\ConstantDeprecationExtension;
1820
use PHPStan\Reflection\Deprecation\Deprecation;
21+
use PHPStan\Reflection\Deprecation\EnumCaseDeprecationExtension;
1922
use PHPStan\Reflection\Deprecation\FunctionDeprecationExtension;
2023
use PHPStan\Reflection\Deprecation\MethodDeprecationExtension;
2124
use PHPStan\Reflection\Deprecation\PropertyDeprecationExtension;
@@ -26,7 +29,8 @@ class CustomDeprecationExtension implements
2629
ClassConstantDeprecationExtension,
2730
MethodDeprecationExtension,
2831
PropertyDeprecationExtension,
29-
FunctionDeprecationExtension
32+
FunctionDeprecationExtension,
33+
EnumCaseDeprecationExtension
3034
{
3135

3236
public function getClassDeprecation(ReflectionClass|ReflectionEnum $reflection): ?Deprecation
@@ -59,6 +63,11 @@ public function getClassConstantDeprecation(ReflectionClassConstant $reflection)
5963
return $this->buildDeprecation($reflection);
6064
}
6165

66+
public function getEnumCaseDeprecation(ReflectionEnumBackedCase|ReflectionEnumUnitCase $reflection): ?Deprecation
67+
{
68+
return $this->buildDeprecation($reflection);
69+
}
70+
6271
private function buildDeprecation($reflection): ?Deprecation
6372
{
6473
foreach ($reflection->getAttributes(CustomDeprecated::class) as $attribute) {
@@ -70,5 +79,4 @@ private function buildDeprecation($reflection): ?Deprecation
7079

7180
return null;
7281
}
73-
7482
}

tests/PHPStan/Reflection/Deprecation/data/deprecation-provider.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ services:
88
- phpstan.classDeprecationExtension
99
- phpstan.functionDeprecationExtension
1010
- phpstan.constantDeprecationExtension
11+
- phpstan.enumCaseDeprecationExtension

tests/PHPStan/Reflection/Deprecation/data/deprecations.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,22 @@ function doubleDeprecatedFunctionOnlyAttributeMessage() {}
161161
/** @deprecated phpdoc */
162162
#[CustomDeprecated()]
163163
function doubleDeprecatedFunctionOnlyPhpDocMessage() {}
164+
165+
166+
#[CustomDeprecated]
167+
enum MyDeprecatedEnum: string
168+
{
169+
#[CustomDeprecated('custom')]
170+
case CustomDeprecated = '1';
171+
172+
/**
173+
* @deprecated phpdoc
174+
*/
175+
case PhpDocDeprecated = '2';
176+
177+
#[\Deprecated('native')]
178+
case NativeDeprecated = '3';
179+
180+
case NotDeprecated = '4';
181+
182+
}

0 commit comments

Comments
 (0)