diff --git a/src/TypeResolver.php b/src/TypeResolver.php index 6c46079..9e2ba20 100644 --- a/src/TypeResolver.php +++ b/src/TypeResolver.php @@ -434,16 +434,7 @@ private function createFromGeneric(GenericTypeNode $type, Context $context): Typ return new IntegerRange((string) $type->genericTypes[0], (string) $type->genericTypes[1]); case 'iterable': - return new Iterable_( - ...array_reverse( - array_map( - function (TypeNode $genericType) use ($context): Type { - return $this->createType($genericType, $context); - }, - $type->genericTypes - ) - ) - ); + return new Iterable_(...array_reverse($this->createTypesByTypeNodes($type->genericTypes, $context))); case 'key-of': return new KeyOf($this->createType($type->genericTypes[0], $context)); @@ -452,18 +443,17 @@ function (TypeNode $genericType) use ($context): Type { return new ValueOf($this->createType($type->genericTypes[0], $context)); case 'int-mask': - return new IntMask( - ...array_map( - function (TypeNode $genericType) use ($context): Type { - return $this->createType($genericType, $context); - }, - $type->genericTypes - ) - ); + return new IntMask(...$this->createTypesByTypeNodes($type->genericTypes, $context)); case 'int-mask-of': return new IntMaskOf($this->createType($type->genericTypes[0], $context)); + case 'static': + return new Static_(...$this->createTypesByTypeNodes($type->genericTypes, $context)); + + case 'self': + return new Self_(...$this->createTypesByTypeNodes($type->genericTypes, $context)); + default: $collectionType = $this->createType($type->type, $context); if ($collectionType instanceof Object_ === false) { @@ -472,14 +462,7 @@ function (TypeNode $genericType) use ($context): Type { return new Collection( $collectionType->getFqsen(), - ...array_reverse( - array_map( - function (TypeNode $genericType) use ($context): Type { - return $this->createType($genericType, $context); - }, - $type->genericTypes - ) - ) + ...array_reverse($this->createTypesByTypeNodes($type->genericTypes, $context)) ); } } @@ -645,14 +628,7 @@ private function resolveTypedObject(string $type, ?Context $context = null): Obj /** @param TypeNode[] $typeNodes */ private function createArray(array $typeNodes, Context $context): Array_ { - $types = array_reverse( - array_map( - function (TypeNode $node) use ($context): Type { - return $this->createType($node, $context); - }, - $typeNodes - ) - ); + $types = array_reverse($this->createTypesByTypeNodes($typeNodes, $context)); if (isset($types[1]) === false) { return new Array_(...$types); @@ -727,4 +703,19 @@ private function tryParseRemainingCompoundTypes(TokenIterator $tokenIterator, Co return $type; } + + /** + * @param TypeNode[] $nodes + * + * @return Type[] + */ + private function createTypesByTypeNodes(array $nodes, Context $context): array + { + return array_map( + function (TypeNode $node) use ($context): Type { + return $this->createType($node, $context); + }, + $nodes + ); + } } diff --git a/src/Types/Self_.php b/src/Types/Self_.php index 5096126..b3fc783 100644 --- a/src/Types/Self_.php +++ b/src/Types/Self_.php @@ -15,6 +15,8 @@ use phpDocumentor\Reflection\Type; +use function implode; + /** * Value Object representing the 'self' type. * @@ -24,11 +26,31 @@ */ final class Self_ implements Type { + /** @var Type[] */ + private $genericTypes; + + public function __construct(Type ...$genericTypes) + { + $this->genericTypes = $genericTypes; + } + + /** + * @return Type[] + */ + public function getGenericTypes(): array + { + return $this->genericTypes; + } + /** * Returns a rendered output of the Type as it would be used in a DocBlock. */ public function __toString(): string { + if ($this->genericTypes) { + return 'self<' . implode(', ', $this->genericTypes) . '>'; + } + return 'self'; } } diff --git a/src/Types/Static_.php b/src/Types/Static_.php index 6fe365f..eb14ecb 100644 --- a/src/Types/Static_.php +++ b/src/Types/Static_.php @@ -15,6 +15,8 @@ use phpDocumentor\Reflection\Type; +use function implode; + /** * Value Object representing the 'static' type. * @@ -29,11 +31,31 @@ */ final class Static_ implements Type { + /** @var Type[] */ + private $genericTypes; + + public function __construct(Type ...$genericTypes) + { + $this->genericTypes = $genericTypes; + } + + /** + * @return Type[] + */ + public function getGenericTypes(): array + { + return $this->genericTypes; + } + /** * Returns a rendered output of the Type as it would be used in a DocBlock. */ public function __toString(): string { + if ($this->genericTypes) { + return 'static<' . implode(', ', $this->genericTypes) . '>'; + } + return 'static'; } } diff --git a/tests/unit/TypeResolverTest.php b/tests/unit/TypeResolverTest.php index 6aca0a2..272535e 100644 --- a/tests/unit/TypeResolverTest.php +++ b/tests/unit/TypeResolverTest.php @@ -980,6 +980,10 @@ public function typeProvider(): array new Integer() ), ], + [ + 'static', + new Static_(), + ], [ 'self', new Self_(), @@ -1109,6 +1113,26 @@ public function genericsProvider(): array 'int-mask-of', new IntMaskOf(new ConstExpression(new Object_(new Fqsen('\\phpDocumentor\\Foo')), 'INT_*')), ], + [ + 'iterable', + new Iterable_(new String_(), new Integer()), + ], + [ + 'static', + new Static_( + new Object_(new Fqsen('\\phpDocumentor\\FirstClass')), + new Object_(new Fqsen('\\phpDocumentor\\SecondClass')), + new Object_(new Fqsen('\\phpDocumentor\\ThirdClass')), + ), + ], + [ + 'self', + new Self_( + new Object_(new Fqsen('\\phpDocumentor\\FirstClass')), + new Object_(new Fqsen('\\phpDocumentor\\SecondClass')), + new Object_(new Fqsen('\\phpDocumentor\\ThirdClass')), + ), + ], ]; } diff --git a/tests/unit/Types/SelfTest.php b/tests/unit/Types/SelfTest.php new file mode 100644 index 0000000..b51b10f --- /dev/null +++ b/tests/unit/Types/SelfTest.php @@ -0,0 +1,60 @@ +assertSame($genericTypes, $type->getGenericTypes()); + } + + /** + * @dataProvider provideToStringData + * @covers ::__toString + */ + public function testToString(string $expectedResult, Self_ $type): void + { + $this->assertSame($expectedResult, (string) $type); + } + + /** + * @return array + */ + public static function provideToStringData(): array + { + return [ + 'basic' => [ + 'self', + new Self_(), + ], + 'with generic' => [ + 'self<\\phpDocumentor\\FirstClass, \\phpDocumentor\\SecondClass, \\phpDocumentor\\ThirdClass>', + new Self_( + new Object_(new Fqsen('\\phpDocumentor\\FirstClass')), + new Object_(new Fqsen('\\phpDocumentor\\SecondClass')), + new Object_(new Fqsen('\\phpDocumentor\\ThirdClass')), + ), + ], + ]; + } +} diff --git a/tests/unit/Types/StaticTest.php b/tests/unit/Types/StaticTest.php new file mode 100644 index 0000000..f41c1c0 --- /dev/null +++ b/tests/unit/Types/StaticTest.php @@ -0,0 +1,60 @@ +assertSame($genericTypes, $type->getGenericTypes()); + } + + /** + * @dataProvider provideToStringData + * @covers ::__toString + */ + public function testToString(string $expectedResult, Static_ $type): void + { + $this->assertSame($expectedResult, (string) $type); + } + + /** + * @return array + */ + public static function provideToStringData(): array + { + return [ + 'basic' => [ + 'static', + new Static_(), + ], + 'with generic' => [ + 'static<\\phpDocumentor\\FirstClass, \\phpDocumentor\\SecondClass, \\phpDocumentor\\ThirdClass>', + new Static_( + new Object_(new Fqsen('\\phpDocumentor\\FirstClass')), + new Object_(new Fqsen('\\phpDocumentor\\SecondClass')), + new Object_(new Fqsen('\\phpDocumentor\\ThirdClass')), + ), + ], + ]; + } +}