Skip to content

Commit f253cd4

Browse files
committed
Add support for constant types.
phpstan supports contant definitions and expressions to link to constants.
1 parent 8d57d3d commit f253cd4

File tree

10 files changed

+241
-61
lines changed

10 files changed

+241
-61
lines changed

src/ConstExpression/Expression.php

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
/**
3+
* This file is part of phpDocumentor.
4+
*
5+
* For the full copyright and license information, please view the LICENSE
6+
* file that was distributed with this source code.
7+
*
8+
* @link http://phpdoc.org
9+
*/
10+
11+
declare(strict_types=1);
12+
13+
namespace phpDocumentor\Reflection\ConstExpression;
14+
15+
interface Expression
16+
{
17+
}

src/ConstExpression/Lookup.php

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Reflection\ConstExpression;
6+
7+
use phpDocumentor\Reflection\Fqsen;
8+
9+
final class Lookup implements Expression
10+
{
11+
private Fqsen $fqsen;
12+
private string $expression;
13+
14+
public function __construct(Fqsen $fqsen, string $expression)
15+
{
16+
$this->fqsen = $fqsen;
17+
$this->expression = $expression;
18+
}
19+
}

src/DocBlock/Tags/Factory/TypeFactory.php

+35-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44

55
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
66

7+
use phpDocumentor\Reflection\FqsenResolver;
78
use phpDocumentor\Reflection\PseudoTypes\ArrayShape;
89
use phpDocumentor\Reflection\PseudoTypes\ArrayShapeItem;
10+
use phpDocumentor\Reflection\PseudoTypes\ConstExpression;
11+
use phpDocumentor\Reflection\PseudoTypes\FloatValue;
912
use phpDocumentor\Reflection\PseudoTypes\IntegerRange;
13+
use phpDocumentor\Reflection\PseudoTypes\IntegerValue;
1014
use phpDocumentor\Reflection\PseudoTypes\List_;
15+
use phpDocumentor\Reflection\PseudoTypes\StringValue;
1116
use phpDocumentor\Reflection\Type;
1217
use phpDocumentor\Reflection\TypeResolver;
1318
use phpDocumentor\Reflection\Types\Array_;
@@ -20,6 +25,10 @@
2025
use phpDocumentor\Reflection\Types\Intersection;
2126
use phpDocumentor\Reflection\Types\Nullable;
2227
use phpDocumentor\Reflection\Types\This;
28+
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFloatNode;
29+
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
30+
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
31+
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
2332
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode;
2433
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
2534
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
@@ -48,10 +57,12 @@
4857
final class TypeFactory
4958
{
5059
private TypeResolver $resolver;
60+
private FqsenResolver $fqsenResolver;
5161

52-
public function __construct(TypeResolver $resolver)
62+
public function __construct(TypeResolver $resolver, FqsenResolver $fqsenResolver)
5363
{
5464
$this->resolver = $resolver;
65+
$this->fqsenResolver = $fqsenResolver;
5566
}
5667

5768
public function createType(?TypeNode $type, ?Context $context): ?Type
@@ -82,7 +93,7 @@ public function createType(?TypeNode $type, ?Context $context): ?Type
8293
return $this->createFromCallable($type, $context);
8394

8495
case ConstTypeNode::class:
85-
return null;
96+
return $this->createFromConst($type, $context);
8697

8798
case GenericTypeNode::class:
8899
return $this->createFromGeneric($type, $context);
@@ -144,12 +155,12 @@ private function createFromGeneric(GenericTypeNode $type, ?Context $context): Ty
144155

145156
case 'class-string':
146157
return new ClassString(
147-
$this->createType($type->genericTypes[0], $context)->getFqsen()
158+
$this->fqsenResolver->resolve((string) $type->genericTypes[0], $context)
148159
);
149160

150161
case 'interface-string':
151162
return new InterfaceString(
152-
$this->createType($type->genericTypes[0], $context)->getFqsen()
163+
$this->fqsenResolver->resolve((string) $type->genericTypes[0], $context)
153164
);
154165

155166
case 'list':
@@ -180,4 +191,24 @@ private function createFromCallable(CallableTypeNode $type, ?Context $context):
180191
{
181192
return new Callable_();
182193
}
194+
195+
private function createFromConst(ConstTypeNode $type, ?Context $context): ?Type
196+
{
197+
switch (get_class($type->constExpr)) {
198+
case ConstExprIntegerNode::class:
199+
return new IntegerValue((int) $type->constExpr->value);
200+
201+
case ConstExprFloatNode::class:
202+
return new FloatValue((float) $type->constExpr->value);
203+
204+
case ConstExprStringNode::class:
205+
return new StringValue($type->constExpr->value);
206+
207+
case ConstFetchNode::class:
208+
return new ConstExpression(
209+
$this->fqsenResolver->resolve($type->constExpr->className, $context),
210+
$type->constExpr->name
211+
);
212+
}
213+
}
183214
}

src/DocBlockFactory.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public static function createInstance(array $additionalTags = []): self
7070
$tagFactory = new StandardTagFactory($fqsenResolver);
7171
$descriptionFactory = new DescriptionFactory($tagFactory);
7272
$typeResolver = new TypeResolver($fqsenResolver);
73-
$typeFactory = new TypeFactory($typeResolver);
73+
$typeFactory = new TypeFactory($typeResolver, $fqsenResolver);
7474

7575
$phpstanTagFactory = new AbstractPHPStanFactory(
7676
new ParamFactory($typeFactory, $descriptionFactory),

src/PseudoTypes/ConstExpression.php

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Reflection\PseudoTypes;
6+
7+
use phpDocumentor\Reflection\Fqsen;
8+
use phpDocumentor\Reflection\PseudoType;
9+
use phpDocumentor\Reflection\Type;
10+
use phpDocumentor\Reflection\Types\Mixed_;
11+
12+
use function sprintf;
13+
14+
final class ConstExpression implements PseudoType
15+
{
16+
private Fqsen $owner;
17+
private string $expression;
18+
19+
public function __construct(Fqsen $owner, string $expression)
20+
{
21+
$this->owner = $owner;
22+
$this->expression = $expression;
23+
}
24+
25+
public function getOwner(): Fqsen
26+
{
27+
return $this->owner;
28+
}
29+
30+
public function getExpression(): string
31+
{
32+
return $this->expression;
33+
}
34+
35+
public function underlyingType(): Type
36+
{
37+
return new Mixed_();
38+
}
39+
40+
public function __toString(): string
41+
{
42+
return sprintf('%s::%s', $this->owner, $this->expression);
43+
}
44+
}

src/PseudoTypes/FloatValue.php

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Reflection\PseudoTypes;
6+
7+
use phpDocumentor\Reflection\PseudoType;
8+
use phpDocumentor\Reflection\Type;
9+
use phpDocumentor\Reflection\Types\Float_;
10+
11+
class FloatValue implements PseudoType
12+
{
13+
private float $value;
14+
15+
public function __construct(float $value)
16+
{
17+
$this->value = $value;
18+
}
19+
20+
public function getValue(): float
21+
{
22+
return $this->value;
23+
}
24+
25+
public function underlyingType(): Type
26+
{
27+
return new Float_();
28+
}
29+
30+
public function __toString(): string
31+
{
32+
return (string) $this->value;
33+
}
34+
}

src/PseudoTypes/IntegerValue.php

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Reflection\PseudoTypes;
6+
7+
use phpDocumentor\Reflection\PseudoType;
8+
use phpDocumentor\Reflection\Type;
9+
use phpDocumentor\Reflection\Types\Integer;
10+
11+
final class IntegerValue implements PseudoType
12+
{
13+
private int $value;
14+
15+
public function __construct(int $value)
16+
{
17+
$this->value = $value;
18+
}
19+
20+
public function getValue(): int
21+
{
22+
return $this->value;
23+
}
24+
25+
public function underlyingType(): Type
26+
{
27+
return new Integer();
28+
}
29+
30+
public function __toString(): string
31+
{
32+
return (string) $this->value;
33+
}
34+
}

src/PseudoTypes/StringValue.php

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Reflection\PseudoTypes;
6+
7+
use phpDocumentor\Reflection\PseudoType;
8+
use phpDocumentor\Reflection\Type;
9+
use phpDocumentor\Reflection\Types\Float_;
10+
11+
use function sprintf;
12+
13+
class StringValue implements PseudoType
14+
{
15+
private string $value;
16+
17+
public function __construct(string $value)
18+
{
19+
$this->value = $value;
20+
}
21+
22+
public function getValue(): string
23+
{
24+
return $this->value;
25+
}
26+
27+
public function underlyingType(): Type
28+
{
29+
return new Float_();
30+
}
31+
32+
public function __toString(): string
33+
{
34+
return sprintf('"%s"', $this->value);
35+
}
36+
}

tests/unit/DocBlock/Tags/Factory/TagFactoryTestCase.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function parseTag(string $tag): PhpDocTagNode
3939

4040
public function giveTypeFactory(): TypeFactory
4141
{
42-
return new TypeFactory(new TypeResolver(new FqsenResolver()));
42+
return new TypeFactory(new TypeResolver(new FqsenResolver()), new FqsenResolver());
4343
}
4444

4545
public function givenDescriptionFactory(): DescriptionFactory

0 commit comments

Comments
 (0)