Remove type logic from this package

This commit is contained in:
Jaapio
2022-11-11 12:30:14 +01:00
parent d6e90a3238
commit 6a92bc3ce9
28 changed files with 108 additions and 844 deletions
+2 -2
View File
@@ -14,8 +14,8 @@
}
],
"require": {
"php": "^7.4 || ^8.0",
"phpdocumentor/type-resolver": "^1.3",
"php": "^7.2 || ^8.0",
"phpdocumentor/type-resolver": "1.x-dev@dev",
"webmozart/assert": "^1.9.1",
"phpdocumentor/reflection-common": "^2.2",
"ext-filter": "*",
Generated
+28 -18
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "99af646bb3e1fa0d77d855f0f5995c9f",
"content-hash": "829061026cc6b2284953cbe816406760",
"packages": [
{
"name": "phpdocumentor/reflection-common",
@@ -61,26 +61,34 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.6.1",
"version": "1.x-dev",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "77a32518733312af16a44300404e945338981de3"
"reference": "662b17f56786e34354684f6c141c1909b1ee3ac0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3",
"reference": "77a32518733312af16a44300404e945338981de3",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/662b17f56786e34354684f6c141c1909b1ee3ac0",
"reference": "662b17f56786e34354684f6c141c1909b1ee3ac0",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"phpdocumentor/reflection-common": "^2.0"
"php": "^7.4 || ^8.0",
"phpdocumentor/reflection-common": "^2.0",
"phpstan/phpdoc-parser": "^1.13"
},
"require-dev": {
"ext-tokenizer": "*",
"psalm/phar": "^4.8"
"phpbench/phpbench": "^1.2",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-phpunit": "^1.1",
"phpunit/phpunit": "^9.5",
"rector/rector": "^0.13.9",
"vimeo/psalm": "^4.25"
},
"default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
@@ -105,22 +113,22 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.x"
},
"time": "2022-03-15T21:29:03+00:00"
"time": "2022-11-11T10:44:03+00:00"
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.7.0",
"version": "1.13.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "367a8d9d5f7da2a0136422d27ce8840583926955"
"reference": "33aefcdab42900e36366d0feab6206e2dd68f947"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/367a8d9d5f7da2a0136422d27ce8840583926955",
"reference": "367a8d9d5f7da2a0136422d27ce8840583926955",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/33aefcdab42900e36366d0feab6206e2dd68f947",
"reference": "33aefcdab42900e36366d0feab6206e2dd68f947",
"shasum": ""
},
"require": {
@@ -150,9 +158,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.7.0"
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.13.0"
},
"time": "2022-08-09T12:23:23+00:00"
"time": "2022-10-21T09:57:39+00:00"
},
{
"name": "webmozart/assert",
@@ -4049,11 +4057,13 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {
"phpdocumentor/type-resolver": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": "^7.4 || ^8.0",
"php": "^7.2 || ^8.0",
"ext-filter": "*"
},
"platform-dev": [],
@@ -50,6 +50,10 @@ class AbstractPHPStanFactory implements Factory
$tokens = $this->lexer->tokenize($tagLine);
$ast = $this->parser->parseTag(new TokenIterator($tokens));
if ($context === null) {
$context = new TypeContext('');
}
foreach ($this->factories as $factory) {
if ($factory->supports($ast, $context)) {
return $factory->create($ast, $context);
+9 -8
View File
@@ -9,6 +9,7 @@ use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Method;
use phpDocumentor\Reflection\DocBlock\Tags\MethodParameter;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\Types\Mixed_;
use phpDocumentor\Reflection\Types\Void_;
@@ -25,16 +26,16 @@ use function trim;
*/
final class MethodFactory implements PHPStanFactory
{
private TypeFactory $typeFactory;
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeFactory $typeFactory, DescriptionFactory $descriptionFactory)
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->typeFactory = $typeFactory;
$this->descriptionFactory = $descriptionFactory;
$this->typeResolver = $typeResolver;
}
public function create(PhpDocTagNode $node, ?Context $context): Tag
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, MethodTagValueNode::class);
@@ -50,7 +51,7 @@ final class MethodFactory implements PHPStanFactory
function (MethodTagValueParameterNode $param) use ($context) {
return new MethodParameter(
trim($param->parameterName, '$'),
$this->typeFactory->createType($param->type, $context) ?? new Mixed_(),
$this->typeResolver->createType($param->type, $context) ?? new Mixed_(),
$param->isReference,
$param->isVariadic,
(string) $param->defaultValue
@@ -61,13 +62,13 @@ final class MethodFactory implements PHPStanFactory
);
}
public function supports(PhpDocTagNode $node, ?Context $context): bool
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof MethodTagValueNode;
}
private function createReturnType(MethodTagValueNode $tagValue, ?Context $context): Type
private function createReturnType(MethodTagValueNode $tagValue, Context $context): Type
{
return $this->typeFactory->createType($tagValue->returnType, $context) ?? new Void_();
return $this->typeResolver->createType($tagValue->returnType, $context) ?? new Void_();
}
}
+2 -2
View File
@@ -10,7 +10,7 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
interface PHPStanFactory
{
public function create(PhpDocTagNode $node, ?Context $context): Tag;
public function create(PhpDocTagNode $node, Context $context): Tag;
public function supports(PhpDocTagNode $node, ?Context $context): bool;
public function supports(PhpDocTagNode $node, Context $context): bool;
}
+7 -6
View File
@@ -7,6 +7,7 @@ namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Param;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
@@ -19,30 +20,30 @@ use function trim;
*/
final class ParamFactory implements PHPStanFactory
{
private TypeFactory $typeFactory;
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeFactory $typeFactory, DescriptionFactory $descriptionFactory)
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->typeFactory = $typeFactory;
$this->descriptionFactory = $descriptionFactory;
$this->typeResolver = $typeResolver;
}
public function create(PhpDocTagNode $node, ?Context $context): Tag
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, ParamTagValueNode::class);
return new Param(
trim($tagValue->parameterName, '$'),
$this->typeFactory->createType($tagValue->type, $context),
$this->typeResolver->createType($tagValue->type, $context),
$tagValue->isVariadic,
$this->descriptionFactory->create($tagValue->description, $context),
$tagValue->isReference
);
}
public function supports(PhpDocTagNode $node, ?Context $context): bool
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof ParamTagValueNode;
}
@@ -7,6 +7,7 @@ namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Property;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
@@ -19,28 +20,28 @@ use function trim;
*/
final class PropertyFactory implements PHPStanFactory
{
private TypeFactory $typeFactory;
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeFactory $typeFactory, DescriptionFactory $descriptionFactory)
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->typeFactory = $typeFactory;
$this->descriptionFactory = $descriptionFactory;
$this->typeResolver = $typeResolver;
}
public function create(PhpDocTagNode $node, ?Context $context): Tag
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, PropertyTagValueNode::class);
return new Property(
trim($tagValue->propertyName, '$'),
$this->typeFactory->createType($tagValue->type, $context),
$this->typeResolver->createType($tagValue->type, $context),
$this->descriptionFactory->create($tagValue->description, $context)
);
}
public function supports(PhpDocTagNode $node, ?Context $context): bool
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof PropertyTagValueNode && $node->name === '@property';
}
@@ -7,6 +7,7 @@ namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\PropertyRead;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
@@ -19,28 +20,28 @@ use function trim;
*/
final class PropertyReadFactory implements PHPStanFactory
{
private TypeFactory $typeFactory;
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeFactory $typeFactory, DescriptionFactory $descriptionFactory)
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->typeFactory = $typeFactory;
$this->typeResolver = $typeResolver;
$this->descriptionFactory = $descriptionFactory;
}
public function create(PhpDocTagNode $node, ?Context $context): Tag
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, PropertyTagValueNode::class);
return new PropertyRead(
trim($tagValue->propertyName, '$'),
$this->typeFactory->createType($tagValue->type, $context),
$this->typeResolver->createType($tagValue->type, $context),
$this->descriptionFactory->create($tagValue->description, $context)
);
}
public function supports(PhpDocTagNode $node, ?Context $context): bool
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof PropertyTagValueNode && $node->name === '@property-read';
}
@@ -7,6 +7,7 @@ namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\PropertyWrite;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
@@ -19,28 +20,28 @@ use function trim;
*/
final class PropertyWriteFactory implements PHPStanFactory
{
private TypeFactory $typeFactory;
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeFactory $typeFactory, DescriptionFactory $descriptionFactory)
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->typeFactory = $typeFactory;
$this->descriptionFactory = $descriptionFactory;
$this->typeResolver = $typeResolver;
}
public function create(PhpDocTagNode $node, ?Context $context): Tag
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, PropertyTagValueNode::class);
return new PropertyWrite(
trim($tagValue->propertyName, '$'),
$this->typeFactory->createType($tagValue->type, $context),
$this->typeResolver->createType($tagValue->type, $context),
$this->descriptionFactory->create($tagValue->description, $context)
);
}
public function supports(PhpDocTagNode $node, ?Context $context): bool
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof PropertyTagValueNode && $node->name === '@property-write';
}
+7 -6
View File
@@ -7,6 +7,7 @@ namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Return_;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
@@ -17,27 +18,27 @@ use Webmozart\Assert\Assert;
*/
final class ReturnFactory implements PHPStanFactory
{
private TypeFactory $typeFactory;
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeFactory $typeFactory, DescriptionFactory $descriptionFactory)
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->typeFactory = $typeFactory;
$this->descriptionFactory = $descriptionFactory;
$this->typeResolver = $typeResolver;
}
public function create(PhpDocTagNode $node, ?Context $context): Tag
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, ReturnTagValueNode::class);
return new Return_(
$this->typeFactory->createType($tagValue->type, $context),
$this->typeResolver->createType($tagValue->type, $context),
$this->descriptionFactory->create($tagValue->description, $context)
);
}
public function supports(PhpDocTagNode $node, ?Context $context): bool
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof ReturnTagValueNode;
}
-230
View File
@@ -1,230 +0,0 @@
<?php
declare(strict_types=1);
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_;
use phpDocumentor\Reflection\Types\Callable_;
use phpDocumentor\Reflection\Types\CallableParameter;
use phpDocumentor\Reflection\Types\ClassString;
use phpDocumentor\Reflection\Types\Collection;
use phpDocumentor\Reflection\Types\Compound;
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\Types\InterfaceString;
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;
use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeForParameterNode;
use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeNode;
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode;
use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode;
use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode;
use function array_filter;
use function array_map;
use function array_reverse;
use function get_class;
use function strtolower;
/**
* @internal This class is not part of the BC promise of this library.
*/
final class TypeFactory
{
private TypeResolver $resolver;
private FqsenResolver $fqsenResolver;
public function __construct(TypeResolver $resolver, FqsenResolver $fqsenResolver)
{
$this->resolver = $resolver;
$this->fqsenResolver = $fqsenResolver;
}
public function createType(?TypeNode $type, ?Context $context): ?Type
{
if ($type === null) {
return null;
}
switch (get_class($type)) {
case ArrayTypeNode::class:
return new Array_(
$this->createType($type->type, $context)
);
case ArrayShapeNode::class:
return new ArrayShape(
...array_map(
fn (ArrayShapeItemNode $item) => new ArrayShapeItem(
(string) $item->keyName,
$this->createType($item->valueType, $context),
$item->optional
),
$type->items
)
);
case CallableTypeNode::class:
return $this->createFromCallable($type, $context);
case ConstTypeNode::class:
return $this->createFromConst($type, $context);
case GenericTypeNode::class:
return $this->createFromGeneric($type, $context);
case IdentifierTypeNode::class:
return $this->resolver->resolve($type->name, $context);
case IntersectionTypeNode::class:
return new Intersection(
array_filter(
array_map(
fn (TypeNode $nestedType) => $this->createType($nestedType, $context),
$type->types
)
)
);
case NullableTypeNode::class:
$nestedType = $this->createType($type->type, $context);
if ($nestedType === null) {
return null;
}
return new Nullable($nestedType);
case UnionTypeNode::class:
return new Compound(
array_filter(
array_map(
fn (TypeNode $nestedType) => $this->createType($nestedType, $context),
$type->types
)
)
);
case ThisTypeNode::class:
return new This();
case ConditionalTypeNode::class:
case ConditionalTypeForParameterNode::class:
case OffsetAccessTypeNode::class:
default:
return null;
}
}
private function createFromGeneric(GenericTypeNode $type, ?Context $context): Type
{
switch (strtolower($type->type->name)) {
case 'array':
return new Array_(
...array_reverse(
array_map(
fn (TypeNode $genericType) => $this->createType($genericType, $context),
$type->genericTypes
)
)
);
case 'class-string':
return new ClassString(
$this->fqsenResolver->resolve((string) $type->genericTypes[0], $context)
);
case 'interface-string':
return new InterfaceString(
$this->fqsenResolver->resolve((string) $type->genericTypes[0], $context)
);
case 'list':
return new List_(
$this->createType($type->genericTypes[0], $context)
);
case 'int':
return new IntegerRange(
(string) $type->genericTypes[0],
(string) ($type->genericTypes[1] ?? ''),
);
default:
return new Collection(
$this->createType($type->type, $context)->getFqsen(),
...array_reverse(
array_map(
fn (TypeNode $genericType) => $this->createType($genericType, $context),
$type->genericTypes
)
)
);
}
}
private function createFromCallable(CallableTypeNode $type, ?Context $context): Callable_
{
return new Callable_(
array_map(
function (CallableTypeParameterNode $param) use ($context) {
return new CallableParameter(
$param->parameterName !== '' ? trim($param->parameterName, '$') : null,
$this->createType($param->type, $context),
$param->isReference,
$param->isVariadic,
$param->isOptional
);
},
$type->parameters
),
$this->createType($type->returnType, $context),
);
}
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
);
}
}
}
+7 -6
View File
@@ -7,6 +7,7 @@ namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
@@ -19,28 +20,28 @@ use function trim;
*/
final class VarFactory implements PHPStanFactory
{
private TypeFactory $typeFactory;
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeFactory $typeFactory, DescriptionFactory $descriptionFactory)
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->typeFactory = $typeFactory;
$this->descriptionFactory = $descriptionFactory;
$this->typeResolver = $typeResolver;
}
public function create(PhpDocTagNode $node, ?Context $context): Tag
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, VarTagValueNode::class);
return new Var_(
trim($tagValue->variableName, '$'),
$this->typeFactory->createType($tagValue->type, $context),
$this->typeResolver->createType($tagValue->type, $context),
$this->descriptionFactory->create($tagValue->description, $context)
);
}
public function supports(PhpDocTagNode $node, ?Context $context): bool
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof VarTagValueNode;
}
+6 -7
View File
@@ -70,15 +70,14 @@ final class DocBlockFactory implements DocBlockFactoryInterface
$tagFactory = new StandardTagFactory($fqsenResolver);
$descriptionFactory = new DescriptionFactory($tagFactory);
$typeResolver = new TypeResolver($fqsenResolver);
$typeFactory = new TypeFactory($typeResolver, $fqsenResolver);
$phpstanTagFactory = new AbstractPHPStanFactory(
new ParamFactory($typeFactory, $descriptionFactory),
new VarFactory($typeFactory, $descriptionFactory),
new ReturnFactory($typeFactory, $descriptionFactory),
new PropertyFactory($typeFactory, $descriptionFactory),
new PropertyReadFactory($typeFactory, $descriptionFactory),
new PropertyWriteFactory($typeFactory, $descriptionFactory),
new ParamFactory($typeResolver, $descriptionFactory),
new VarFactory($typeResolver, $descriptionFactory),
new ReturnFactory($typeResolver, $descriptionFactory),
new PropertyFactory($typeResolver, $descriptionFactory),
new PropertyReadFactory($typeResolver, $descriptionFactory),
new PropertyWriteFactory($typeResolver, $descriptionFactory),
);
$tagFactory->addService($descriptionFactory);
-34
View File
@@ -1,34 +0,0 @@
<?php
declare(strict_types=1);
namespace phpDocumentor\Reflection\PseudoTypes;
use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Array_;
use phpDocumentor\Reflection\Types\ArrayKey;
use phpDocumentor\Reflection\Types\Mixed_;
use function implode;
class ArrayShape implements PseudoType
{
/** @var ArrayShapeItem[] */
private array $items;
public function __construct(ArrayShapeItem ...$items)
{
$this->items = $items;
}
public function underlyingType(): Type
{
return new Array_(new Mixed_(), new ArrayKey());
}
public function __toString(): string
{
return 'array{' . implode(', ', $this->items) . '}';
}
}
-53
View File
@@ -1,53 +0,0 @@
<?php
declare(strict_types=1);
namespace phpDocumentor\Reflection\PseudoTypes;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Mixed_;
use function sprintf;
final class ArrayShapeItem
{
private ?string $key;
private Type $value;
private bool $optional;
public function __construct(?string $key, ?Type $value, bool $optional)
{
$this->key = $key;
$this->value = $value ?? new Mixed_();
$this->optional = $optional;
}
public function getKey(): ?string
{
return $this->key;
}
public function getValue(): Type
{
return $this->value;
}
public function isOptional(): bool
{
return $this->optional;
}
public function __toString(): string
{
if ($this->key !== null) {
return sprintf(
'%s%s: %s',
$this->key,
$this->optional ? '?' : '',
$this->value
);
}
return (string) $this->value;
}
}
-44
View File
@@ -1,44 +0,0 @@
<?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
View File
@@ -1,34 +0,0 @@
<?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
View File
@@ -1,34 +0,0 @@
<?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
View File
@@ -1,36 +0,0 @@
<?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);
}
}
@@ -33,7 +33,7 @@ final class MethodFactoryTest extends TagFactoryTestCase
public function testIsCreated(string $tagLine, Method $tag): void
{
$ast = $this->parseTag($tagLine);
$factory = new MethodFactory($this->giveTypeFactory(), $this->givenDescriptionFactory());
$factory = new MethodFactory($this->giveTypeResolver(), $this->givenDescriptionFactory());
$context = new Context('global');
self::assertTrue($factory->supports($ast, $context));
@@ -76,7 +76,7 @@ final class MethodFactoryTest extends TagFactoryTestCase
new Method(
'myMethod',
[],
new Void_(),
new Mixed_(),
false,
new Description(''),
false,
@@ -88,7 +88,7 @@ final class MethodFactoryTest extends TagFactoryTestCase
new Method(
'myMethod',
[],
new Void_(),
new Mixed_(),
false,
new Description(''),
false,
@@ -100,7 +100,7 @@ final class MethodFactoryTest extends TagFactoryTestCase
new Method(
'myMethod',
[],
new Void_(),
new Mixed_(),
false,
new Description(''),
false,
@@ -112,7 +112,7 @@ final class MethodFactoryTest extends TagFactoryTestCase
new Method(
'myMethod',
[],
new Void_(),
new Mixed_(),
false,
new Description(''),
false,
@@ -124,7 +124,7 @@ final class MethodFactoryTest extends TagFactoryTestCase
new Method(
'myMethod',
[],
new Void_(),
new Mixed_(),
false,
new Description(''),
false,
@@ -136,7 +136,7 @@ final class MethodFactoryTest extends TagFactoryTestCase
new Method(
'myMethod',
[],
new Void_(),
new Mixed_(),
false,
new Description(''),
false,
@@ -28,7 +28,7 @@ final class ParamFactoryTest extends TagFactoryTestCase
public function testParamIsCreated(): void
{
$ast = $this->parseTag('@param string $var');
$factory = new ParamFactory($this->giveTypeFactory(), $this->givenDescriptionFactory());
$factory = new ParamFactory($this->giveTypeResolver(), $this->givenDescriptionFactory());
$context = new Context('global');
self::assertTrue($factory->supports($ast, $context));
@@ -28,7 +28,7 @@ final class PropertyFactoryTest extends TagFactoryTestCase
public function testParamIsCreated(): void
{
$ast = $this->parseTag('@property string $var');
$factory = new PropertyFactory($this->giveTypeFactory(), $this->givenDescriptionFactory());
$factory = new PropertyFactory($this->giveTypeResolver(), $this->givenDescriptionFactory());
$context = new Context('global');
self::assertTrue($factory->supports($ast, $context));
@@ -28,7 +28,7 @@ final class PropertyReadFactoryTest extends TagFactoryTestCase
public function testParamIsCreated(): void
{
$ast = $this->parseTag('@property-read string $var');
$factory = new PropertyReadFactory($this->giveTypeFactory(), $this->givenDescriptionFactory());
$factory = new PropertyReadFactory($this->giveTypeResolver(), $this->givenDescriptionFactory());
$context = new Context('global');
self::assertTrue($factory->supports($ast, $context));
@@ -28,7 +28,7 @@ final class PropertyWriteFactoryTest extends TagFactoryTestCase
public function testParamIsCreated(): void
{
$ast = $this->parseTag('@property-write string $var');
$factory = new PropertyWriteFactory($this->giveTypeFactory(), $this->givenDescriptionFactory());
$factory = new PropertyWriteFactory($this->giveTypeResolver(), $this->givenDescriptionFactory());
$context = new Context('global');
self::assertTrue($factory->supports($ast, $context));
@@ -28,7 +28,7 @@ final class ReturnFactoryTest extends TagFactoryTestCase
public function testParamIsCreated(): void
{
$ast = $this->parseTag('@return string');
$factory = new ReturnFactory($this->giveTypeFactory(), $this->givenDescriptionFactory());
$factory = new ReturnFactory($this->giveTypeResolver(), $this->givenDescriptionFactory());
$context = new Context('global');
self::assertTrue($factory->supports($ast, $context));
@@ -37,9 +37,9 @@ abstract class TagFactoryTestCase extends TestCase
return (new PhpDocParser(new TypeParser($constParser), $constParser))->parseTag(new TokenIterator($tokens));
}
public function giveTypeFactory(): TypeFactory
public function giveTypeResolver(): TypeResolver
{
return new TypeFactory(new TypeResolver(new FqsenResolver()), new FqsenResolver());
return new TypeResolver(new FqsenResolver());
}
public function givenDescriptionFactory(): DescriptionFactory
@@ -1,291 +0,0 @@
<?php
declare(strict_types=1);
/**
* 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
*/
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\FqsenResolver;
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\PseudoTypes\True_;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Array_;
use phpDocumentor\Reflection\Types\ArrayKey;
use phpDocumentor\Reflection\Types\Callable_;
use phpDocumentor\Reflection\Types\CallableParameter;
use phpDocumentor\Reflection\Types\ClassString;
use phpDocumentor\Reflection\Types\Collection;
use phpDocumentor\Reflection\Types\Compound;
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\Types\Float_;
use phpDocumentor\Reflection\Types\Integer;
use phpDocumentor\Reflection\Types\InterfaceString;
use phpDocumentor\Reflection\Types\Intersection;
use phpDocumentor\Reflection\Types\Nullable;
use phpDocumentor\Reflection\Types\Object_;
use phpDocumentor\Reflection\Types\Self_;
use phpDocumentor\Reflection\Types\String_;
use phpDocumentor\Reflection\Types\This;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\PhpDocParser\Parser\TypeParser;
use PHPUnit\Framework\TestCase;
final class TypeFactoryTest extends TestCase
{
/**
* @covers \phpDocumentor\Reflection\DocBlock\Tags\Factory\TypeFactory::createType
* @covers \phpDocumentor\Reflection\DocBlock\Tags\Factory\TypeFactory::createFromGeneric
* @covers \phpDocumentor\Reflection\DocBlock\Tags\Factory\TypeFactory::createFromCallable
* @dataProvider typeProvider
* @dataProvider genericsProvider
* @dataProvider callableProvider
* @dataProvider constExpressions
* @testdox create type from $type
*/
public function testTypeBuilding(string $type, Type $expected): void
{
$lexer = new Lexer();
$tokens = $lexer->tokenize($type);
$constParser = new ConstExprParser();
$parser = new TypeParser($constParser);
$ast = $parser->parse(new TokenIterator($tokens));
$fqsenResolver = new FqsenResolver();
$factory = new TypeFactory(new TypeResolver($fqsenResolver), $fqsenResolver);
$actual = $factory->createType($ast, new Context('phpDocumentor'));
self::assertEquals($expected, $actual);
}
/**
* @return array<array{0: string, 1: Type}>
*/
public function typeProvider(): array
{
return [
[
'string',
new String_(),
],
[
'( string )',
new String_(),
],
[
'\\Foo\Bar\\Baz',
new Object_(new Fqsen('\\Foo\Bar\\Baz')),
],
[
'string|int',
new Compound(
[
new String_(),
new Integer(),
]
),
],
[
'string&int',
new Intersection(
[
new String_(),
new Integer(),
]
),
],
[
'string & (int | float)',
new Intersection(
[
new String_(),
new Compound(
[
new Integer(),
new Float_(),
]
),
]
),
],
[
'string[]',
new Array_(
new String_()
),
],
[
'$this',
new This(),
],
[
'?int',
new Nullable(
new Integer()
),
],
[
'self',
new Self_(),
],
];
}
/**
* @return array<array{0: string, 1: Type}>
*/
public function genericsProvider(): array
{
return [
[
'array<int, Foo\\Bar>',
new Array_(
new Object_(new Fqsen('\\phpDocumentor\\Foo\\Bar')),
new Integer()
),
],
[
'Collection<array-key, int>[]',
new Array_(
new Collection(
new Fqsen('\\phpDocumentor\\Collection'),
new Integer(),
new ArrayKey()
)
),
],
[
'class-string',
new ClassString(null),
],
[
'class-string<Foo>',
new ClassString(new Fqsen('\\phpDocumentor\\Foo')),
],
[
'interface-string<Foo>',
new InterfaceString(new Fqsen('\\phpDocumentor\\Foo')),
],
[
'List<Foo>',
new List_(new Object_(new Fqsen('\\phpDocumentor\\Foo'))),
],
[
'int<1, 100>',
new IntegerRange('1', '100'),
],
];
}
/**
* @return array<array{0: string, 1: Type}>
*/
public function callableProvider(): array
{
return [
[
'callable',
new Callable_(),
],
[
'callable()',
new Callable_(),
],
[
'callable(): Foo',
new Callable_([], new Object_(new Fqsen('\\phpDocumentor\\Foo'))),
],
[
'callable(): (Foo&Bar)',
new Callable_(
[],
new Intersection(
[
new Object_(new Fqsen('\\phpDocumentor\\Foo')),
new Object_(new Fqsen('\\phpDocumentor\\Bar'))
]
)
),
],
[
'callable(A&...$a=, B&...=, C): Foo',
new Callable_(
[
new CallableParameter(
'a',
new Object_(new Fqsen('\\phpDocumentor\\A')),
true,
true,
true
),
new CallableParameter(
null,
new Object_(new Fqsen('\\phpDocumentor\\B')),
true,
true,
true
),
new CallableParameter(
null,
new Object_(new Fqsen('\\phpDocumentor\\C')),
false,
false,
false
),
],
new Object_(new Fqsen('\\phpDocumentor\\Foo')
)
),
],
];
}
/**
* @return array<array{0: string, 1: Type}>
*/
public function constExpressions(): array
{
return [
[
'123',
new IntegerValue(123),
],
[
'true',
new True_(),
],
[
'123.2',
new FloatValue(123.2),
],
[
'"bar"',
new StringValue('bar'),
],
[
'Foo::FOO_CONSTANT',
new ConstExpression(new Fqsen('\\phpDocumentor\\Foo'), 'FOO_CONSTANT'),
],
[
'Foo::FOO_*',
new ConstExpression(new Fqsen('\\phpDocumentor\\Foo'), 'FOO_*'),
],
];
}
}
@@ -28,7 +28,7 @@ final class VarFactoryTest extends TagFactoryTestCase
public function testParamIsCreated(): void
{
$ast = $this->parseTag('@var string $var');
$factory = new VarFactory($this->giveTypeFactory(), $this->givenDescriptionFactory());
$factory = new VarFactory($this->giveTypeResolver(), $this->givenDescriptionFactory());
$context = new Context('global');
self::assertTrue($factory->supports($ast, $context));