Skip to content

Commit 708cb0a

Browse files
authored
Merge pull request #218 from phpDocumentor/feature/216_enums
Add support for php 8.1 enums
2 parents c4ef8b9 + 6ceff49 commit 708cb0a

File tree

18 files changed

+1079
-1
lines changed

18 files changed

+1079
-1
lines changed

phpstan.neon

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ parameters:
1313
# all these $fqsen errors indicate the need for a decorator class around PhpParser\Node to hold the public $fqsen that Reflection is giving it)
1414
#
1515
# src/phpDocumentor/Reflection/NodeVisitor/ElementNameResolver.php
16-
- '#Access to an undefined property PhpParser\\Node\\Stmt\\Class_\|PhpParser\\Node\\Stmt\\Interface_\|PhpParser\\Node\\Stmt\\Trait_::\$fqsen#'
16+
- '#Access to an undefined property PhpParser\\Node\\Stmt\\Class_\|PhpParser\\Node\\Stmt\\Enum_\|PhpParser\\Node\\Stmt\\Interface_\|PhpParser\\Node\\Stmt\\Trait_::\$fqsen#'
1717
- '#Access to an undefined property PhpParser\\Node\\Stmt\\Namespace_::\$fqsen\.#'
18+
- '#Access to an undefined property PhpParser\\Node\\Stmt\\Enum_::\$fqsen\.#'
19+
- '#Access to an undefined property PhpParser\\Node\\Stmt\\EnumCase::\$fqsen\.#'
1820
- '#Access to an undefined property PhpParser\\Node\\Stmt\\Interface_::\$fqsen\.#'
1921
- '#Access to an undefined property PhpParser\\Node\\Stmt\\Function_::\$fqsen\.#'
2022
- '#Access to an undefined property PhpParser\\Node\\Stmt\\ClassMethod::\$fqsen\.#'

src/phpDocumentor/Reflection/NodeVisitor/ElementNameResolver.php

+9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
use PhpParser\Node\Stmt\Class_;
2020
use PhpParser\Node\Stmt\ClassConst;
2121
use PhpParser\Node\Stmt\ClassMethod;
22+
use PhpParser\Node\Stmt\Enum_;
23+
use PhpParser\Node\Stmt\EnumCase;
2224
use PhpParser\Node\Stmt\Function_;
2325
use PhpParser\Node\Stmt\Interface_;
2426
use PhpParser\Node\Stmt\Namespace_;
@@ -58,6 +60,8 @@ public function leaveNode(Node $node)
5860
switch (get_class($node)) {
5961
case Namespace_::class:
6062
case Class_::class:
63+
case Enum_::class:
64+
case EnumCase::class:
6165
case ClassMethod::class:
6266
case Trait_::class:
6367
case PropertyProperty::class:
@@ -98,6 +102,7 @@ public function enterNode(Node $node): ?int
98102
case Class_::class:
99103
case Trait_::class:
100104
case Interface_::class:
105+
case Enum_::class:
101106
if (empty($node->name)) {
102107
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
103108
}
@@ -128,6 +133,10 @@ public function enterNode(Node $node): ?int
128133
$this->parts->push('::$' . $node->name);
129134
$node->fqsen = new Fqsen($this->buildName());
130135
break;
136+
case EnumCase::class:
137+
$this->parts->push('::' . $node->name);
138+
$node->fqsen = new Fqsen($this->buildName());
139+
break;
131140
}
132141

133142
return null;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Reflection\Php;
6+
7+
use phpDocumentor\Reflection\DocBlock;
8+
use phpDocumentor\Reflection\Element;
9+
use phpDocumentor\Reflection\Fqsen;
10+
use phpDocumentor\Reflection\Location;
11+
12+
final class EnumCase implements Element
13+
{
14+
/** @var Fqsen */
15+
private $fqsen;
16+
17+
/** @var DocBlock|null */
18+
private $docBlock;
19+
/** @var Location|null */
20+
private $location;
21+
22+
/** @var string|null */
23+
private $value;
24+
25+
public function __construct(Fqsen $fqsen, ?DocBlock $docBlock, ?Location $location = null, ?string $value = null)
26+
{
27+
$this->fqsen = $fqsen;
28+
$this->docBlock = $docBlock;
29+
$this->location = $location;
30+
$this->value = $value;
31+
}
32+
33+
public function getFqsen(): Fqsen
34+
{
35+
return $this->fqsen;
36+
}
37+
38+
public function getName(): string
39+
{
40+
return $this->fqsen->getName();
41+
}
42+
43+
public function getDocBlock(): ?DocBlock
44+
{
45+
return $this->docBlock;
46+
}
47+
48+
public function getLocation(): ?Location
49+
{
50+
return $this->location;
51+
}
52+
53+
public function getValue(): ?string
54+
{
55+
return $this->value;
56+
}
57+
}
+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link http://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\Reflection\Php;
15+
16+
use phpDocumentor\Reflection\DocBlock;
17+
use phpDocumentor\Reflection\Element;
18+
use phpDocumentor\Reflection\Fqsen;
19+
use phpDocumentor\Reflection\Location;
20+
use phpDocumentor\Reflection\Type;
21+
22+
final class Enum_ implements Element
23+
{
24+
/** @var Fqsen Full Qualified Structural Element Name */
25+
private $fqsen;
26+
27+
/** @var DocBlock|null */
28+
private $docBlock;
29+
30+
/** @var Location|null */
31+
private $location;
32+
33+
/** @var EnumCase[] */
34+
private $cases = [];
35+
36+
/** @var array<string, Fqsen> */
37+
private $implements = [];
38+
39+
/** @var array<string, Method> */
40+
private $methods = [];
41+
42+
/** @var array<string, Fqsen> */
43+
private $usedTraits = [];
44+
45+
/** @var Type|null */
46+
private $backedType;
47+
48+
public function __construct(
49+
Fqsen $fqsen,
50+
?Type $backedType,
51+
?DocBlock $docBlock = null,
52+
?Location $location = null
53+
) {
54+
if ($location === null) {
55+
$location = new Location(-1);
56+
}
57+
58+
$this->fqsen = $fqsen;
59+
$this->docBlock = $docBlock;
60+
$this->location = $location;
61+
$this->backedType = $backedType;
62+
}
63+
64+
public function getFqsen(): Fqsen
65+
{
66+
return $this->fqsen;
67+
}
68+
69+
public function getName(): string
70+
{
71+
return $this->fqsen->getName();
72+
}
73+
74+
public function getDocBlock(): ?DocBlock
75+
{
76+
return $this->docBlock;
77+
}
78+
79+
public function getLocation(): ?Location
80+
{
81+
return $this->location;
82+
}
83+
84+
public function addCase(EnumCase $case): void
85+
{
86+
$this->cases[(string) $case->getFqsen()] = $case;
87+
}
88+
89+
/** @return EnumCase[] */
90+
public function getCases(): array
91+
{
92+
return $this->cases;
93+
}
94+
95+
/**
96+
* Returns the interfaces this enum is implementing.
97+
*
98+
* @return Fqsen[]
99+
*/
100+
public function getInterfaces(): array
101+
{
102+
return $this->implements;
103+
}
104+
105+
/**
106+
* Add an interface Fqsen this enum is implementing.
107+
*/
108+
public function addInterface(Fqsen $interface): void
109+
{
110+
$this->implements[(string) $interface] = $interface;
111+
}
112+
113+
/**
114+
* Returns the methods of this enum.
115+
*
116+
* @return Method[]
117+
*/
118+
public function getMethods(): array
119+
{
120+
return $this->methods;
121+
}
122+
123+
/**
124+
* Add a method to this enum.
125+
*/
126+
public function addMethod(Method $method): void
127+
{
128+
$this->methods[(string) $method->getFqsen()] = $method;
129+
}
130+
131+
/**
132+
* Returns the traits used by this enum.
133+
*
134+
* @return Fqsen[]
135+
*/
136+
public function getUsedTraits(): array
137+
{
138+
return $this->usedTraits;
139+
}
140+
141+
/**
142+
* Add trait fqsen used by this enum.
143+
*/
144+
public function addUsedTrait(Fqsen $fqsen): void
145+
{
146+
$this->usedTraits[(string) $fqsen] = $fqsen;
147+
}
148+
149+
public function getBackedType(): ?Type
150+
{
151+
return $this->backedType;
152+
}
153+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Reflection\Php\Factory;
6+
7+
use phpDocumentor\Reflection\DocBlockFactoryInterface;
8+
use phpDocumentor\Reflection\Location;
9+
use phpDocumentor\Reflection\Php\Enum_ as EnumElement;
10+
use phpDocumentor\Reflection\Php\EnumCase as EnumCaseElement;
11+
use phpDocumentor\Reflection\Php\StrategyContainer;
12+
use PhpParser\Node\Stmt\EnumCase as EnumCaseNode;
13+
use PhpParser\PrettyPrinter\Standard as PrettyPrinter;
14+
15+
use function assert;
16+
17+
final class EnumCase extends AbstractFactory
18+
{
19+
/** @var PrettyPrinter */
20+
private $prettyPrinter;
21+
22+
public function __construct(DocBlockFactoryInterface $docBlockFactory, PrettyPrinter $prettyPrinter)
23+
{
24+
parent::__construct($docBlockFactory);
25+
$this->prettyPrinter = $prettyPrinter;
26+
}
27+
28+
public function matches(ContextStack $context, object $object): bool
29+
{
30+
return $object instanceof EnumCaseNode;
31+
}
32+
33+
/**
34+
* @param EnumCaseNode $object
35+
*/
36+
protected function doCreate(ContextStack $context, object $object, StrategyContainer $strategies): void
37+
{
38+
$docBlock = $this->createDocBlock($object->getDocComment(), $context->getTypeContext());
39+
$enum = $context->peek();
40+
assert($enum instanceof EnumElement);
41+
$enum->addCase(new EnumCaseElement(
42+
$object->fqsen,
43+
$docBlock,
44+
new Location($object->getLine()),
45+
$object->expr !== null ? $this->prettyPrinter->prettyPrintExpr($object->expr) : null
46+
));
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link http://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\Reflection\Php\Factory;
15+
16+
use phpDocumentor\Reflection\Fqsen;
17+
use phpDocumentor\Reflection\Location;
18+
use phpDocumentor\Reflection\Php\File as FileElement;
19+
use phpDocumentor\Reflection\Php\StrategyContainer;
20+
use PhpParser\Node\Stmt\Enum_ as EnumNode;
21+
22+
use function assert;
23+
24+
final class Enum_ extends AbstractFactory
25+
{
26+
public function matches(ContextStack $context, object $object): bool
27+
{
28+
return $object instanceof EnumNode;
29+
}
30+
31+
/** @param EnumNode $object */
32+
protected function doCreate(ContextStack $context, object $object, StrategyContainer $strategies): void
33+
{
34+
$docBlock = $this->createDocBlock($object->getDocComment(), $context->getTypeContext());
35+
36+
$enum = new \phpDocumentor\Reflection\Php\Enum_(
37+
$object->fqsen,
38+
(new Type())->fromPhpParser($object->scalarType),
39+
$docBlock,
40+
new Location($object->getLine())
41+
);
42+
43+
if (isset($object->implements)) {
44+
foreach ($object->implements as $interfaceClassName) {
45+
$enum->addInterface(
46+
new Fqsen('\\' . $interfaceClassName->toString())
47+
);
48+
}
49+
}
50+
51+
$file = $context->peek();
52+
assert($file instanceof FileElement);
53+
$file->addEnum($enum);
54+
55+
if (!isset($object->stmts)) {
56+
return;
57+
}
58+
59+
foreach ($object->stmts as $stmt) {
60+
$thisContext = $context->push($enum);
61+
$strategy = $strategies->findMatching($thisContext, $stmt);
62+
$strategy->create($thisContext, $stmt, $strategies);
63+
}
64+
}
65+
}

0 commit comments

Comments
 (0)