Skip to content

Commit

Permalink
Resolve type incompatibilities
Browse files Browse the repository at this point in the history
I don't know whether PHP Parser changed or we always had an interesting
situation, but phpstan pointed out that the TypeFactory contained a type
incompatibility. I have resolved that and made the stringifying code
recursive because an intersection type may contain another intersection
type, etc, etc.
  • Loading branch information
mvriel committed Dec 7, 2022
1 parent 5478413 commit 41cb981
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 9 deletions.
Expand Up @@ -22,6 +22,8 @@
/**
* This class acts like a combination of a ClassConst and Const_
* to be able to create constant descriptors using a normal strategy.
*
* @implements Iterator<int, ClassConstantIterator>
*/
final class ClassConstantIterator implements Iterator
{
Expand Down
Expand Up @@ -19,6 +19,9 @@
use PhpParser\Node\Expr;
use PhpParser\Node\Stmt\Const_;

/**
* @implements Iterator<int, GlobalConstantIterator>
*/
final class GlobalConstantIterator implements Iterator
{
private Const_ $constant;
Expand Down
2 changes: 2 additions & 0 deletions src/phpDocumentor/Reflection/Php/Factory/PropertyIterator.php
Expand Up @@ -25,6 +25,8 @@
/**
* This class acts like a combination of a PropertyNode and PropertyProperty to
* be able to create property descriptors using a normal strategy.
*
* @implements Iterator<int, PropertyIterator>
*/
final class PropertyIterator implements Iterator
{
Expand Down
45 changes: 37 additions & 8 deletions src/phpDocumentor/Reflection/Php/Factory/Type.php
Expand Up @@ -23,9 +23,12 @@
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\UnionType;
use PhpParser\NodeAbstract;

use function array_map;
use function get_class;
use function implode;
use function is_string;
use function sprintf;

final class Type
Expand All @@ -39,23 +42,49 @@ public function fromPhpParser($type, ?Context $context = null): ?TypeElement
return null;
}

$typeResolver = new TypeResolver();
return (new TypeResolver())
->resolve($this->convertPhpParserTypeToString($type), $context);
}

/**
* @param NodeAbstract|string $type
*/
private function convertPhpParserTypeToString($type): string
{
if (is_string($type)) {
return $type;
}

if ($type instanceof Identifier) {
return $type->toString();
}

if ($type instanceof Name) {
return $type->toString();
}

if ($type instanceof NullableType) {
return $typeResolver->resolve('?' . $type->type, $context);
return '?' . $this->convertPhpParserTypeToString($type->type);
}

if ($type instanceof UnionType) {
return $typeResolver->resolve(implode('|', $type->types), $context);
$typesAsStrings = array_map(
fn ($typeObject): string => $this->convertPhpParserTypeToString($typeObject),
$type->types
);

return implode('|', $typesAsStrings);
}

if ($type instanceof IntersectionType) {
return $typeResolver->resolve(implode('&', $type->types), $context);
}
$typesAsStrings = array_map(
fn ($typeObject): string => $this->convertPhpParserTypeToString($typeObject),
$type->types
);

if ($type instanceof ComplexType) {
throw new InvalidArgumentException(sprintf('Unsupported complex type %s', get_class($type)));
return implode('&', $typesAsStrings);
}

return $typeResolver->resolve($type->toString(), $context);
throw new InvalidArgumentException(sprintf('Unsupported complex type %s', get_class($type)));
}
}
Expand Up @@ -78,7 +78,7 @@ public function testReturnsNullableTypeWhenPassedAPhpParserNullable(): void
public function testReturnsUnion(): void
{
$factory = new Type();
$given = new UnionType(['integer', 'string']);
$given = new UnionType([new Identifier('integer'), new Identifier('string')]);
$expected = new Compound([new Integer(), new String_()]);

$result = $factory->fromPhpParser($given);
Expand Down

0 comments on commit 41cb981

Please sign in to comment.