mirror of
https://github.com/barryvdh/ReflectionDocBlock.git
synced 2026-08-18 01:57:13 +00:00
Add support for constant types.
phpstan supports contant definitions and expressions to link to constants.
This commit is contained in:
@@ -4,10 +4,15 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
|
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
|
||||||
|
|
||||||
|
use phpDocumentor\Reflection\FqsenResolver;
|
||||||
use phpDocumentor\Reflection\PseudoTypes\ArrayShape;
|
use phpDocumentor\Reflection\PseudoTypes\ArrayShape;
|
||||||
use phpDocumentor\Reflection\PseudoTypes\ArrayShapeItem;
|
use phpDocumentor\Reflection\PseudoTypes\ArrayShapeItem;
|
||||||
|
use phpDocumentor\Reflection\PseudoTypes\ConstExpression;
|
||||||
|
use phpDocumentor\Reflection\PseudoTypes\FloatValue;
|
||||||
use phpDocumentor\Reflection\PseudoTypes\IntegerRange;
|
use phpDocumentor\Reflection\PseudoTypes\IntegerRange;
|
||||||
|
use phpDocumentor\Reflection\PseudoTypes\IntegerValue;
|
||||||
use phpDocumentor\Reflection\PseudoTypes\List_;
|
use phpDocumentor\Reflection\PseudoTypes\List_;
|
||||||
|
use phpDocumentor\Reflection\PseudoTypes\StringValue;
|
||||||
use phpDocumentor\Reflection\Type;
|
use phpDocumentor\Reflection\Type;
|
||||||
use phpDocumentor\Reflection\TypeResolver;
|
use phpDocumentor\Reflection\TypeResolver;
|
||||||
use phpDocumentor\Reflection\Types\Array_;
|
use phpDocumentor\Reflection\Types\Array_;
|
||||||
@@ -20,6 +25,10 @@ use phpDocumentor\Reflection\Types\InterfaceString;
|
|||||||
use phpDocumentor\Reflection\Types\Intersection;
|
use phpDocumentor\Reflection\Types\Intersection;
|
||||||
use phpDocumentor\Reflection\Types\Nullable;
|
use phpDocumentor\Reflection\Types\Nullable;
|
||||||
use phpDocumentor\Reflection\Types\This;
|
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\ArrayShapeItemNode;
|
||||||
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
|
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
|
||||||
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
|
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
|
||||||
@@ -48,10 +57,12 @@ use function strtolower;
|
|||||||
final class TypeFactory
|
final class TypeFactory
|
||||||
{
|
{
|
||||||
private TypeResolver $resolver;
|
private TypeResolver $resolver;
|
||||||
|
private FqsenResolver $fqsenResolver;
|
||||||
|
|
||||||
public function __construct(TypeResolver $resolver)
|
public function __construct(TypeResolver $resolver, FqsenResolver $fqsenResolver)
|
||||||
{
|
{
|
||||||
$this->resolver = $resolver;
|
$this->resolver = $resolver;
|
||||||
|
$this->fqsenResolver = $fqsenResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createType(?TypeNode $type, ?Context $context): ?Type
|
public function createType(?TypeNode $type, ?Context $context): ?Type
|
||||||
@@ -82,7 +93,7 @@ final class TypeFactory
|
|||||||
return $this->createFromCallable($type, $context);
|
return $this->createFromCallable($type, $context);
|
||||||
|
|
||||||
case ConstTypeNode::class:
|
case ConstTypeNode::class:
|
||||||
return null;
|
return $this->createFromConst($type, $context);
|
||||||
|
|
||||||
case GenericTypeNode::class:
|
case GenericTypeNode::class:
|
||||||
return $this->createFromGeneric($type, $context);
|
return $this->createFromGeneric($type, $context);
|
||||||
@@ -144,12 +155,12 @@ final class TypeFactory
|
|||||||
|
|
||||||
case 'class-string':
|
case 'class-string':
|
||||||
return new ClassString(
|
return new ClassString(
|
||||||
$this->createType($type->genericTypes[0], $context)->getFqsen()
|
$this->fqsenResolver->resolve((string) $type->genericTypes[0], $context)
|
||||||
);
|
);
|
||||||
|
|
||||||
case 'interface-string':
|
case 'interface-string':
|
||||||
return new InterfaceString(
|
return new InterfaceString(
|
||||||
$this->createType($type->genericTypes[0], $context)->getFqsen()
|
$this->fqsenResolver->resolve((string) $type->genericTypes[0], $context)
|
||||||
);
|
);
|
||||||
|
|
||||||
case 'list':
|
case 'list':
|
||||||
@@ -180,4 +191,24 @@ final class TypeFactory
|
|||||||
{
|
{
|
||||||
return new Callable_();
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ final class DocBlockFactory implements DocBlockFactoryInterface
|
|||||||
$tagFactory = new StandardTagFactory($fqsenResolver);
|
$tagFactory = new StandardTagFactory($fqsenResolver);
|
||||||
$descriptionFactory = new DescriptionFactory($tagFactory);
|
$descriptionFactory = new DescriptionFactory($tagFactory);
|
||||||
$typeResolver = new TypeResolver($fqsenResolver);
|
$typeResolver = new TypeResolver($fqsenResolver);
|
||||||
$typeFactory = new TypeFactory($typeResolver);
|
$typeFactory = new TypeFactory($typeResolver, $fqsenResolver);
|
||||||
|
|
||||||
$phpstanTagFactory = new AbstractPHPStanFactory(
|
$phpstanTagFactory = new AbstractPHPStanFactory(
|
||||||
new ParamFactory($typeFactory, $descriptionFactory),
|
new ParamFactory($typeFactory, $descriptionFactory),
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,7 +39,7 @@ abstract class TagFactoryTestCase extends TestCase
|
|||||||
|
|
||||||
public function giveTypeFactory(): TypeFactory
|
public function giveTypeFactory(): TypeFactory
|
||||||
{
|
{
|
||||||
return new TypeFactory(new TypeResolver(new FqsenResolver()));
|
return new TypeFactory(new TypeResolver(new FqsenResolver()), new FqsenResolver());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function givenDescriptionFactory(): DescriptionFactory
|
public function givenDescriptionFactory(): DescriptionFactory
|
||||||
|
|||||||
@@ -15,8 +15,13 @@ namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
|
|||||||
|
|
||||||
use phpDocumentor\Reflection\Fqsen;
|
use phpDocumentor\Reflection\Fqsen;
|
||||||
use phpDocumentor\Reflection\FqsenResolver;
|
use phpDocumentor\Reflection\FqsenResolver;
|
||||||
|
use phpDocumentor\Reflection\PseudoTypes\ConstExpression;
|
||||||
|
use phpDocumentor\Reflection\PseudoTypes\FloatValue;
|
||||||
use phpDocumentor\Reflection\PseudoTypes\IntegerRange;
|
use phpDocumentor\Reflection\PseudoTypes\IntegerRange;
|
||||||
|
use phpDocumentor\Reflection\PseudoTypes\IntegerValue;
|
||||||
use phpDocumentor\Reflection\PseudoTypes\List_;
|
use phpDocumentor\Reflection\PseudoTypes\List_;
|
||||||
|
use phpDocumentor\Reflection\PseudoTypes\StringValue;
|
||||||
|
use phpDocumentor\Reflection\PseudoTypes\True_;
|
||||||
use phpDocumentor\Reflection\Type;
|
use phpDocumentor\Reflection\Type;
|
||||||
use phpDocumentor\Reflection\TypeResolver;
|
use phpDocumentor\Reflection\TypeResolver;
|
||||||
use phpDocumentor\Reflection\Types\Array_;
|
use phpDocumentor\Reflection\Types\Array_;
|
||||||
@@ -50,6 +55,8 @@ final class TypeFactoryTest extends TestCase
|
|||||||
* @dataProvider typeProvider
|
* @dataProvider typeProvider
|
||||||
* @dataProvider genericsProvider
|
* @dataProvider genericsProvider
|
||||||
* @dataProvider callableProvider
|
* @dataProvider callableProvider
|
||||||
|
* @dataProvider constExpressions
|
||||||
|
* @testdox create type from $type
|
||||||
*/
|
*/
|
||||||
public function testTypeBuilding(string $type, Type $expected): void
|
public function testTypeBuilding(string $type, Type $expected): void
|
||||||
{
|
{
|
||||||
@@ -58,8 +65,9 @@ final class TypeFactoryTest extends TestCase
|
|||||||
$constParser = new ConstExprParser();
|
$constParser = new ConstExprParser();
|
||||||
$parser = new TypeParser($constParser);
|
$parser = new TypeParser($constParser);
|
||||||
$ast = $parser->parse(new TokenIterator($tokens));
|
$ast = $parser->parse(new TokenIterator($tokens));
|
||||||
|
$fqsenResolver = new FqsenResolver();
|
||||||
|
|
||||||
$factory = new TypeFactory(new TypeResolver(new FqsenResolver()));
|
$factory = new TypeFactory(new TypeResolver($fqsenResolver), $fqsenResolver);
|
||||||
$actual = $factory->createType($ast, new Context('phpDocumentor'));
|
$actual = $factory->createType($ast, new Context('phpDocumentor'));
|
||||||
|
|
||||||
self::assertEquals($expected, $actual);
|
self::assertEquals($expected, $actual);
|
||||||
@@ -219,72 +227,29 @@ final class TypeFactoryTest extends TestCase
|
|||||||
public function constExpressions(): array
|
public function constExpressions(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
['Foo::FOO_CONSTANT'],
|
|
||||||
[
|
[
|
||||||
'123',
|
'123',
|
||||||
//new ConstTypeNode(new ConstExprIntegerNode('123')),
|
new IntegerValue(123),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'true',
|
||||||
|
new True_(),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'123.2',
|
'123.2',
|
||||||
//new ConstTypeNode(new ConstExprFloatNode('123.2')),
|
new FloatValue(123.2),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'"bar"',
|
'"bar"',
|
||||||
//new ConstTypeNode(new ConstExprStringNode('bar')),
|
new StringValue('bar'),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'Foo::FOO_CONSTANT',
|
||||||
|
new ConstExpression(new Fqsen('\\phpDocumentor\\Foo'), 'FOO_CONSTANT'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'Foo::FOO_*',
|
'Foo::FOO_*',
|
||||||
//new ConstTypeNode(new ConstFetchNode('Foo', 'FOO_*')),
|
new ConstExpression(new Fqsen('\\phpDocumentor\\Foo'), 'FOO_*'),
|
||||||
],
|
|
||||||
[
|
|
||||||
'Foo::FOO_*BAR',
|
|
||||||
//new ConstTypeNode(new ConstFetchNode('Foo', 'FOO_*BAR')),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Foo::*FOO*',
|
|
||||||
//new ConstTypeNode(new ConstFetchNode('Foo', '*FOO*')),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Foo::A*B*C',
|
|
||||||
//new ConstTypeNode(new ConstFetchNode('Foo', 'A*B*C')),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'self::*BAR',
|
|
||||||
//new ConstTypeNode(new ConstFetchNode('self', '*BAR')),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Foo::*',
|
|
||||||
//new ConstTypeNode(new ConstFetchNode('Foo', '*')),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Foo::**',
|
|
||||||
//new ConstTypeNode(new ConstFetchNode('Foo', '*')), // fails later in PhpDocParser
|
|
||||||
//Lexer::TOKEN_WILDCARD,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Foo::*a',
|
|
||||||
//new ConstTypeNode(new ConstFetchNode('Foo', '*a')),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'( "foo" | Foo::FOO_* )',
|
|
||||||
// new UnionTypeNode([
|
|
||||||
// new ConstTypeNode(new ConstExprStringNode('foo')),
|
|
||||||
// new ConstTypeNode(new ConstFetchNode('Foo', 'FOO_*')),
|
|
||||||
// ]),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'DateTimeImmutable::*|DateTime::*',
|
|
||||||
// new UnionTypeNode([
|
|
||||||
// new ConstTypeNode(new ConstFetchNode('DateTimeImmutable', '*')),
|
|
||||||
// new ConstTypeNode(new ConstFetchNode('DateTime', '*')),
|
|
||||||
// ]),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'ParameterTier::*|null',
|
|
||||||
// new UnionTypeNode([
|
|
||||||
// new ConstTypeNode(new ConstFetchNode('ParameterTier', '*')),
|
|
||||||
// new IdentifierTypeNode('null'),
|
|
||||||
// ]),
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user