Skip to content

Commit

Permalink
Add support for constant types.
Browse files Browse the repository at this point in the history
phpstan supports contant definitions and expressions to
link to constants.
  • Loading branch information
jaapio committed Nov 4, 2022
1 parent 8d57d3d commit f253cd4
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 61 deletions.
17 changes: 17 additions & 0 deletions src/ConstExpression/Expression.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link http://phpdoc.org
*/

declare(strict_types=1);

namespace phpDocumentor\Reflection\ConstExpression;

interface Expression
{
}
19 changes: 19 additions & 0 deletions src/ConstExpression/Lookup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\ConstExpression;

use phpDocumentor\Reflection\Fqsen;

final class Lookup implements Expression
{
private Fqsen $fqsen;
private string $expression;

public function __construct(Fqsen $fqsen, string $expression)
{
$this->fqsen = $fqsen;
$this->expression = $expression;
}
}
39 changes: 35 additions & 4 deletions src/DocBlock/Tags/Factory/TypeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@

namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;

use phpDocumentor\Reflection\FqsenResolver;
use phpDocumentor\Reflection\PseudoTypes\ArrayShape;
use phpDocumentor\Reflection\PseudoTypes\ArrayShapeItem;
use phpDocumentor\Reflection\PseudoTypes\ConstExpression;
use phpDocumentor\Reflection\PseudoTypes\FloatValue;
use phpDocumentor\Reflection\PseudoTypes\IntegerRange;
use phpDocumentor\Reflection\PseudoTypes\IntegerValue;
use phpDocumentor\Reflection\PseudoTypes\List_;
use phpDocumentor\Reflection\PseudoTypes\StringValue;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Array_;
Expand All @@ -20,6 +25,10 @@
use phpDocumentor\Reflection\Types\Intersection;
use phpDocumentor\Reflection\Types\Nullable;
use phpDocumentor\Reflection\Types\This;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFloatNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode;
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
Expand Down Expand Up @@ -48,10 +57,12 @@
final class TypeFactory
{
private TypeResolver $resolver;
private FqsenResolver $fqsenResolver;

public function __construct(TypeResolver $resolver)
public function __construct(TypeResolver $resolver, FqsenResolver $fqsenResolver)
{
$this->resolver = $resolver;
$this->fqsenResolver = $fqsenResolver;
}

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

case ConstTypeNode::class:
return null;
return $this->createFromConst($type, $context);

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

case 'class-string':
return new ClassString(
$this->createType($type->genericTypes[0], $context)->getFqsen()
$this->fqsenResolver->resolve((string) $type->genericTypes[0], $context)
);

case 'interface-string':
return new InterfaceString(
$this->createType($type->genericTypes[0], $context)->getFqsen()
$this->fqsenResolver->resolve((string) $type->genericTypes[0], $context)
);

case 'list':
Expand Down Expand Up @@ -180,4 +191,24 @@ private function createFromCallable(CallableTypeNode $type, ?Context $context):
{
return new Callable_();
}

private function createFromConst(ConstTypeNode $type, ?Context $context): ?Type
{
switch (get_class($type->constExpr)) {
case ConstExprIntegerNode::class:
return new IntegerValue((int) $type->constExpr->value);

case ConstExprFloatNode::class:
return new FloatValue((float) $type->constExpr->value);

case ConstExprStringNode::class:
return new StringValue($type->constExpr->value);

case ConstFetchNode::class:
return new ConstExpression(
$this->fqsenResolver->resolve($type->constExpr->className, $context),
$type->constExpr->name
);
}
}
}
2 changes: 1 addition & 1 deletion src/DocBlockFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public static function createInstance(array $additionalTags = []): self
$tagFactory = new StandardTagFactory($fqsenResolver);
$descriptionFactory = new DescriptionFactory($tagFactory);
$typeResolver = new TypeResolver($fqsenResolver);
$typeFactory = new TypeFactory($typeResolver);
$typeFactory = new TypeFactory($typeResolver, $fqsenResolver);

$phpstanTagFactory = new AbstractPHPStanFactory(
new ParamFactory($typeFactory, $descriptionFactory),
Expand Down
44 changes: 44 additions & 0 deletions src/PseudoTypes/ConstExpression.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Mixed_;

use function sprintf;

final class ConstExpression implements PseudoType
{
private Fqsen $owner;
private string $expression;

public function __construct(Fqsen $owner, string $expression)
{
$this->owner = $owner;
$this->expression = $expression;
}

public function getOwner(): Fqsen
{
return $this->owner;
}

public function getExpression(): string
{
return $this->expression;
}

public function underlyingType(): Type
{
return new Mixed_();
}

public function __toString(): string
{
return sprintf('%s::%s', $this->owner, $this->expression);
}
}
34 changes: 34 additions & 0 deletions src/PseudoTypes/FloatValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Float_;

class FloatValue implements PseudoType
{
private float $value;

public function __construct(float $value)
{
$this->value = $value;
}

public function getValue(): float
{
return $this->value;
}

public function underlyingType(): Type
{
return new Float_();
}

public function __toString(): string
{
return (string) $this->value;
}
}
34 changes: 34 additions & 0 deletions src/PseudoTypes/IntegerValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Integer;

final class IntegerValue implements PseudoType
{
private int $value;

public function __construct(int $value)
{
$this->value = $value;
}

public function getValue(): int
{
return $this->value;
}

public function underlyingType(): Type
{
return new Integer();
}

public function __toString(): string
{
return (string) $this->value;
}
}
36 changes: 36 additions & 0 deletions src/PseudoTypes/StringValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Float_;

use function sprintf;

class StringValue implements PseudoType
{
private string $value;

public function __construct(string $value)
{
$this->value = $value;
}

public function getValue(): string
{
return $this->value;
}

public function underlyingType(): Type
{
return new Float_();
}

public function __toString(): string
{
return sprintf('"%s"', $this->value);
}
}
2 changes: 1 addition & 1 deletion tests/unit/DocBlock/Tags/Factory/TagFactoryTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function parseTag(string $tag): PhpDocTagNode

public function giveTypeFactory(): TypeFactory
{
return new TypeFactory(new TypeResolver(new FqsenResolver()));
return new TypeFactory(new TypeResolver(new FqsenResolver()), new FqsenResolver());
}

public function givenDescriptionFactory(): DescriptionFactory
Expand Down
Loading

0 comments on commit f253cd4

Please sign in to comment.