Skip to content

Commit

Permalink
Add ClassReflection::typeArgumentsOf($class)
Browse files Browse the repository at this point in the history
  • Loading branch information
vudaltsov committed Aug 12, 2024
1 parent 820867b commit a6223d2
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Reflection/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Add `ConstantReflection` and `TyphoonReflector::reflectConstant()`.
- Add `ClassReflection::typeArgumentsOf($class)`.

## [0.4.2] 2024-08-05

Expand Down
26 changes: 26 additions & 0 deletions src/Reflection/ClassReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Typhoon\Reflection\Internal\Misc\NonSerializable;
use Typhoon\Reflection\Internal\NativeAdapter\ClassAdapter;
use Typhoon\Type\Type;
use Typhoon\Type\types;
use Typhoon\Type\Visitor\TemplateTypeResolver;
use Typhoon\TypedMap\TypedMap;

Expand Down Expand Up @@ -199,6 +200,31 @@ public function isInstanceOf(string|NamedClassId|AnonymousClassId $class): bool
|| \array_key_exists($class->name, $this->data[Data::Interfaces]);
}

/**
* @param non-empty-string|NamedClassId|AnonymousClassId $class
* @return list<Type>
*/
public function typeArgumentsOf(string|NamedClassId|AnonymousClassId $class): array
{
if (\is_string($class)) {
$class = Id::class($class);
}

if ($this->id->equals($class)) {
return $this
->templates()
->map(static fn(TemplateReflection $template): Type => types::template($template->id))
->toList();
}

if ($class instanceof AnonymousClassId) {
return [];

Check warning on line 221 in src/Reflection/ClassReflection.php

View check run for this annotation

Codecov / codecov/patch

src/Reflection/ClassReflection.php#L221

Added line #L221 was not covered by tests
}

/** @psalm-suppress PossiblyInvalidArrayOffset */
return $this->data[Data::Parents][$class->name] ?? $this->data[Data::Interfaces][$class->name] ?? [];
}

public function isClass(): bool
{
return $this->data[Data::ClassKind] === ClassKind::Class_;
Expand Down
42 changes: 42 additions & 0 deletions tests/Reflection/functional_tests/class/type_arguments_of.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Typhoon\Reflection;

use Typhoon\Reflection\Locator\Resource;
use Typhoon\Type\types;
use function PHPUnit\Framework\assertEquals;

return static function (TyphoonReflector $reflector): void {
$iterator = $reflector->reflectClass(\Iterator::class);
assertEquals(
[types::classTemplate(\Iterator::class, 'TKey'), types::classTemplate(\Iterator::class, 'TValue')],
$iterator->typeArgumentsOf(\Iterator::class),
);
assertEquals(
[types::classTemplate(\Iterator::class, 'TKey'), types::classTemplate(\Iterator::class, 'TValue')],
$iterator->typeArgumentsOf(\Traversable::class),
);

$a = $reflector
->withResource(Resource::fromCode(
<<<'PHP'
<?php
/**
* @implements Iterator<string>
*/
abstract class A implements Iterator {}
PHP,
))
->reflectClass('A');
assertEquals(
[types::mixed, types::string],
$a->typeArgumentsOf(\Iterator::class),
);
assertEquals(
[types::mixed, types::string],
$a->typeArgumentsOf(\Traversable::class),
);
};

0 comments on commit a6223d2

Please sign in to comment.