8000 [TypeInfo] Add type alias support · symfony/symfony@d0d85af · GitHub
[go: up one dir, main page]

Skip to content

Commit d0d85af

Browse files
committed
[TypeInfo] Add type alias support
1 parent ab6c611 commit d0d85af

18 files changed

+302
-18
lines changed

src/Symfony/Component/TypeInfo/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGELOG
88
* Add `TypeFactoryTrait::fromValue()` method
99
* Deprecate constructing a `CollectionType` instance as a list that is not an array
1010
* Deprecate the third `$asList` argument of `TypeFactoryTrait::iterable()`, use `TypeFactoryTrait::list()` instead
11+
* Add type alias support in `TypeContext` and `StringTypeResolver`
1112

1213
7.2
1314
---

src/Symfony/Component/TypeInfo/Tests/Fixtures/AbstractDummy.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
<?php
22

3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
312
namespace Symfony\Component\TypeInfo\Tests\Fixtures;
413

514
abstract class AbstractDummy

src/Symfony/Component/TypeInfo/Tests/Fixtures/Dummy.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
<?php
22

3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
312
namespace Symfony\Component\TypeInfo\Tests\Fixtures;
413

514
final class Dummy extends AbstractDummy

src/Symfony/Component/TypeInfo/Tests/Fixtures/DummyBackedEnum.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
<?php
22

3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
312
namespace Symfony\Component\TypeInfo\Tests\Fixtures;
413

514
enum DummyBackedEnum: string

src/Symfony/Component/TypeInfo/Tests/Fixtures/DummyCollection.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
<?php
22

3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
312
namespace Symfony\Component\TypeInfo\Tests\Fixtures;
413

514
final class DummyCollection implements \IteratorAggregate

src/Symfony/Component/TypeInfo/Tests/Fixtures/DummyEnum.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
<?php
22

3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
312
namespace Symfony\Component\TypeInfo\Tests\Fixtures;
413

514
enum DummyEnum

src/Symfony/Component/TypeInfo/Tests/Fixtures/DummyExtendingStdClass.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
<?php
22

3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
312
namespace Symfony\Component\TypeInfo\Tests\Fixtures;
413

514
final class DummyExtendingStdClass extends \stdClass

src/Symfony/Component/TypeInfo/Tests/Fixtures/DummyWithPhpDoc.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
11
<?php
22

3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
312
namespace Symfony\Component\TypeInfo\Tests\Fixtures;
413

14+
/**
15+
* @phpstan-type CustomInt = int
16+
* @psalm-type PsalmCustomInt = int
17+
*/
518
final class DummyWithPhpDoc
619
{
720
/**
821
* @var array<Dummy>
922
*/
1023
public mixed $arrayOfDummies = [];
1124

25+
/**
26+
* @var CustomInt
27+
*/
28+
public mixed $aliasedInt;
29+
1230
/**
1331
* @param bool $promoted
1432
*/

src/Symfony/Component/TypeInfo/Tests/Fixtures/DummyWithTemplates.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
<?php
22

3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
312
namespace Symfony\Component\TypeInfo\Tests\Fixtures;
413

514
/**
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\TypeInfo\Tests\Fixtures;
13+
14+
/**
15+
* @phpstan-type CustomString = string
16+
* @phpstan-import-type CustomInt from DummyWithPhpDoc
17+
* @phpstan-import-type CustomInt from DummyWithPhpDoc as AliasedCustomInt
18+
*
19+
* @psalm-type PsalmCustomString = string
20+
* @psalm-import-type PsalmCustomInt from DummyWithPhpDoc
21+
* @psalm-import-type PsalmCustomInt from DummyWithPhpDoc as PsalmAliasedCustomInt
22+
*/
23+
final class DummyWithTypeAliases
24+
{
25+
/**
26+
* @var CustomString
27+
*/
28+
public mixed $localAlias;
29+
30+
/**
31+
* @var CustomInt
32+
*/
33+
public mixed $externalAlias;
34+
35+
/**
36+
* @var AliasedCustomInt
37+
*/
38+
public mixed $aliasedExternalAlias;
39+
40+
/**
41+
* @var PsalmCustomString
42+
*/
43+
public mixed $psalmLocalAlias;
44+
45+
/**
46+
* @var PsalmCustomInt
47+
*/
48+
public mixed $psalmExternalAlias;
49+
50+
/**
51+
* @var PsalmAliasedCustomInt
52+
*/
53+
public mixed $psalmOtherAliasedExternalAlias;
54+
}
55+
56+
/**
57+
* @phpstan-import-type Invalid from DummyWithTypeAliases
58+
*/
59+
final class DummyWithInvalidTypeAliasImport
60+
{
61+
}

src/Symfony/Component/TypeInfo/Tests/Fixtures/DummyWithUses.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
<?php
22

3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
312
namespace Symfony\Component\TypeInfo\Tests\Fixtures;
413

514
use Symfony\Component\TypeInfo\Type;

src/Symfony/Component/TypeInfo/Tests/Fixtures/ReflectionExtractableDummy.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
<?php
22

3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
312
namespace Symfony\Component\TypeInfo\Tests\Fixtures;
413

514
final class ReflectionExtractableDummy extends AbstractDummy

src/Symfony/Component/TypeInfo/Tests/TypeContext/TypeContextFactoryTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
namespace Symfony\Component\TypeInfo\Tests\TypeContext;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\TypeInfo\Exception\LogicException;
1516
use Symfony\Component\TypeInfo\Tests\Fixtures\AbstractDummy;
1617
use Symfony\Component\TypeInfo\Tests\Fixtures\Dummy;
18+
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyWithInvalidTypeAliasImport;
1719
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyWithTemplates;
20+
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyWithTypeAliases;
1821
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyWithUses;
1922
use Symfony\Component\TypeInfo\Type;
2023
use Symfony\Component\TypeInfo\TypeContext\TypeContextFactory;
@@ -119,4 +122,49 @@ public function testDoNotCollectTemplatesWhenToStringTypeResolver()
119122

120123
$this->assertEquals([], $typeContextFactory->createFromClassName(DummyWithTemplates::class)->templates);
121124
}
125+
126+
public function testCollectTypeAliases()
127+
{
128+
$this->assertEquals([
129+
'CustomString' => Type::string(),
130+
'CustomInt' => Type::int(),
131+
'AliasedCustomInt' => Type::int(),
132+
'PsalmCustomString' => Type::string(),
133+
'PsalmCustomInt' => Type::int(),
134+
'PsalmAliasedCustomInt' => Type::int(),
135+
], $this->typeContextFactory->createFromClassName(DummyWithTypeAliases::class)->typeAliases);
136+
137+
$this->assertEquals([
138+
'CustomString' => Type::string(),
139+
'CustomInt' => Type::int(),
140+
'AliasedCustomInt' => Type::int(),
141+
'PsalmCustomString' => Type::string(),
142+
'PsalmCustomInt' => Type::int(),
143+
'PsalmAliasedCustomInt' => Type::int(),
144+
], $this->typeContextFactory->createFromReflection(new \ReflectionClass(DummyWithTypeAliases::class))->typeAliases);
145+
146+
$this->assertEquals([
147+
'CustomString' => Type::string(),
148+
'CustomInt' => Type::int(),
149+
'AliasedCustomInt' => Type::int(),
150+
'PsalmCustomString' => Type::string(),
151+
'PsalmCustomInt' => Type::int(),
152+
'PsalmAliasedCustomInt' => Type::int(),
153+
], $this->typeContextFactory->createFromReflection(new \ReflectionProperty(DummyWithTypeAliases::class, 'localAlias'))->typeAliases);
154+
}
155+
156+
public function testDoNotCollectTypeAliasesWhenToStringTypeResolver()
157+
{
158+
$typeContextFactory = new TypeContextFactory();
159+
160+
$this->assertEquals([], $typeContextFactory->createFromClassName(DummyWithTypeAliases::class)->typeAliases);
161+
}
162+
163+
public function testThrowWhenImportingInvalidAlias()
164+
{
165+
$this->expectException(LogicException::class);
166+
$this->expectExceptionMessage(\sprintf('Cannot find any "Invalid" type alias in "%s".', DummyWithTypeAliases::class));
167+
168+
$this->typeContextFactory->createFromClassName(DummyWithInvalidTypeAliasImport::class);
169+
}
122170
}

src/Symfony/Component/TypeInfo/Tests/TypeResolver/PhpDocAwareReflectionTypeResolverTest.php

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,28 @@
2222

2323
class PhpDocAwareReflectionTypeResolverTest extends TestCase
2424
{
25-
public function testReadPhpDoc()
25+
/**
26+
* @dataProvider readPhpDocDataProvider
27+
*/
28+
public function testReadPhpDoc(Type $expected, \Reflector $reflector)
29+
{
30+
$resolver = new PhpDocAwareReflectionTypeResolver(TypeResolver::create(), new StringTypeResolver(), new TypeContextFactory(new StringTypeResolver()));
31+
32+
$this->assertEquals($expected, $resolver->resolve($reflector));
33+
}
34+
35+
/**
36+
* @return iterable<array{0: Type, 1: \Reflector}>
37+
*/
38+
public static function readPhpDocDataProvider(): iterable
2639
{
27-
$resolver = new PhpDocAwareReflectionTypeResolver(TypeResolver::create(), new StringTypeResolver(), new TypeContextFactory());
2840
$reflection = new \ReflectionClass(DummyWithPhpDoc::class);
2941

30-
$this->assertEquals(Type::array(Type::object(Dummy::class)), $resolver->resolve($reflection->getProperty('arrayOfDummies')));
31-
$this->assertEquals(Type::bool(), $resolver->resolve($reflection->getProperty('promoted')));
32-
$this->assertEquals(Type::object(Dummy::class), $resolver->resolve($reflection->getMethod('getNextDummy')));
33-
$this->assertEquals(Type::object(Dummy::class), $resolver->resolve($reflection->getMethod('getNextDummy')->getParameters()[0]));
42+
yield [Type::array(Type::object(Dummy::class)), $reflection->getProperty('arrayOfDummies')];
43+
yield [Type::bool(), $reflection->getProperty('promoted')];
44+
yield [Type::object(Dummy::class), $reflection->getMethod('getNextDummy')];
45+
yield [Type::object(Dummy::class), $reflection->getMethod('getNextDummy')->getParameters()[0]];
46+
yield [Type::int(), $reflection->getProperty('aliasedInt')];
3447
}
3548

3649
public function testFallbackWhenNoPhpDoc()

src/Symfony/Component/TypeInfo/Tests/TypeResolver/StringTypeResolverTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyCollection;
2121
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyEnum;
2222
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyWithTemplates;
23+
use Symfony\Component\TypeInfo\Tests\Fixtures\DummyWithTypeAliases;
2324
use Symfony\Component\TypeInfo\Type;
2425
use Symfony\Component\TypeInfo\TypeContext\TypeContext;
2526
use Symfony\Component\TypeInfo\TypeContext\TypeContextFactory;
@@ -175,6 +176,10 @@ public static function resolveDataProvider(): iterable
175176
yield [Type::collection(Type::object(\IteratorAggregate::class), Type::string()), \IteratorAggregate::class.'<string>'];
176177
yield [Type::collection(Type::object(\IteratorAggregate::class), Type::bool(), Type::string()), \IteratorAggregate::class.'<string, bool>'];
177178
yield [Type::collection(Type::object(DummyCollection::class), Type::bool(), Type::string()), DummyCollection::class.'<string, bool>'];
179+
180+
// type aliases
181+
yield [Type::int(), 'CustomInt', $typeContextFactory->createFromClassName(DummyWithTypeAliases::class)];
182+
yield [Type::string(), 'CustomString', $typeContextFactory->createFromClassName(DummyWithTypeAliases::class)];
178183
}
179184

180185
public function testCannotResolveNonStringType()

src/Symfony/Component/TypeInfo/TypeContext/TypeContext.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@ final class TypeContext
3333
/**
3434
* @param array<string, string> $uses
3535
* @param array<string, Type> $templates
36+
* @param array<string, Type> $typeAliases
3637
*/
3738
public function __construct(
3839
public readonly string $calledClassName,
3940
public readonly string $declaringClassName,
4041
public readonly ?string $namespace = null,
4142
public readonly array $uses = [],
4243
public readonly array $templates = [],
44+
public readonly array $typeAliases = [],
4345
) {
4446
}
4547

0 commit comments

Comments
 (0)
0