Skip to content

Commit b9aeed4

Browse files
committed
Local type aliases
2 parents 927d442 + 31ea9a2 commit b9aeed4

39 files changed

+1096
-117
lines changed

build.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@
221221
checkreturn="true"
222222
>
223223
<arg value="-d"/>
224-
<arg value="memory_limit=768M"/>
224+
<arg value="memory_limit=864M"/>
225225
<arg path="${phpunit.executable}"/>
226226
<arg value="-c"/>
227227
<arg value="tests/phpunit.xml"/>

build/baseline-7.4.neon

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,6 @@ parameters:
9393
count: 1
9494
path: ../src/Reflection/ReflectionProvider/SetterReflectionProviderProvider.php
9595
-
96-
message: "#^Class class@anonymous/src/Testing/TestCase\\.php\\:267 has an uninitialized property \\$reflectionProvider\\. Give it default value or assign it in the constructor\\.$#"
96+
message: "#^Class class@anonymous/src/Testing/TestCase\\.php\\:270 has an uninitialized property \\$reflectionProvider\\. Give it default value or assign it in the constructor\\.$#"
9797
count: 1
9898
path: ../src/Testing/TestCase.php

conf/config.level0.neon

+7
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,10 @@ services:
200200

201201
-
202202
class: PHPStan\Rules\Whitespace\FileWhitespaceRule
203+
204+
-
205+
class: PHPStan\Rules\Classes\LocalTypeAliasesRule
206+
arguments:
207+
globalTypeAliases: %typeAliases%
208+
tags:
209+
- phpstan.rules.rule

conf/config.neon

+5-8
Original file line numberDiff line numberDiff line change
@@ -366,13 +366,6 @@ services:
366366
-
367367
class: PHPStan\PhpDoc\ConstExprNodeResolver
368368

369-
-
370-
class: PHPStan\PhpDoc\TypeAlias\TypeAliasesTypeNodeResolverExtension
371-
arguments:
372-
aliases: %typeAliases%
373-
tags:
374-
- phpstan.phpDoc.typeNodeResolverExtension
375-
376369
-
377370
class: PHPStan\PhpDoc\TypeNodeResolver
378371

@@ -747,7 +740,6 @@ services:
747740
class: PHPStan\Rules\Generics\TemplateTypeCheck
748741
arguments:
749742
checkClassCaseSensitivity: %checkClassCaseSensitivity%
750-
typeAliases: %typeAliases%
751743

752744
-
753745
class: PHPStan\Rules\Generics\VarianceCheck
@@ -802,6 +794,11 @@ services:
802794
-
803795
class: PHPStan\Type\FileTypeMapper
804796

797+
-
798+
class: PHPStan\Type\TypeAliasResolver
799+
arguments:
800+
globalTypeAliases: %typeAliases%
801+
805802
-
806803
class: PHPStan\Type\Php\ArgumentBasedFunctionReturnTypeExtension
807804
tags:

src/Analyser/NameScope.php

+14-1
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,21 @@ class NameScope
2020

2121
private TemplateTypeMap $templateTypeMap;
2222

23+
private bool $bypassTypeAliases;
24+
2325
/**
2426
* @param string|null $namespace
2527
* @param array<string, string> $uses alias(string) => fullName(string)
2628
* @param string|null $className
2729
*/
28-
public function __construct(?string $namespace, array $uses, ?string $className = null, ?string $functionName = null, ?TemplateTypeMap $templateTypeMap = null)
30+
public function __construct(?string $namespace, array $uses, ?string $className = null, ?string $functionName = null, ?TemplateTypeMap $templateTypeMap = null, bool $bypassTypeAliases = false)
2931
{
3032
$this->namespace = $namespace;
3133
$this->uses = $uses;
3234
$this->className = $className;
3335
$this->functionName = $functionName;
3436
$this->templateTypeMap = $templateTypeMap ?? TemplateTypeMap::createEmpty();
37+
$this->bypassTypeAliases = $bypassTypeAliases;
3538
}
3639

3740
public function getNamespace(): ?string
@@ -137,6 +140,16 @@ public function unsetTemplateType(string $name): self
137140
);
138141
}
139142

143+
public function bypassTypeAliases(): self
144+
{
145+
return new self($this->namespace, $this->uses, $this->className, $this->functionName, $this->templateTypeMap, true);
146+
}
147+
148+
public function shouldBypassTypeAliases(): bool
149+
{
150+
return $this->bypassTypeAliases;
151+
}
152+
140153
/**
141154
* @param mixed[] $properties
142155
* @return self

src/PhpDoc/PhpDocNodeResolver.php

+39
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use PHPStan\PhpDoc\Tag\ReturnTag;
1515
use PHPStan\PhpDoc\Tag\TemplateTag;
1616
use PHPStan\PhpDoc\Tag\ThrowsTag;
17+
use PHPStan\PhpDoc\Tag\TypeAliasImportTag;
18+
use PHPStan\PhpDoc\Tag\TypeAliasTag;
1719
use PHPStan\PhpDoc\Tag\UsesTag;
1820
use PHPStan\PhpDoc\Tag\VarTag;
1921
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNullNode;
@@ -365,6 +367,43 @@ public function resolveMixinTags(PhpDocNode $phpDocNode, NameScope $nameScope):
365367
}, $phpDocNode->getMixinTagValues());
366368
}
367369

370+
/**
371+
* @return array<string, TypeAliasTag>
372+
*/
373+
public function resolveTypeAliasTags(PhpDocNode $phpDocNode, NameScope $nameScope): array
374+
{
375+
$resolved = [];
376+
377+
foreach (['@psalm-type', '@phpstan-type'] as $tagName) {
378+
foreach ($phpDocNode->getTypeAliasTagValues($tagName) as $typeAliasTagValue) {
379+
$alias = $typeAliasTagValue->alias;
380+
$typeNode = $typeAliasTagValue->type;
381+
$resolved[$alias] = new TypeAliasTag($alias, $typeNode, $nameScope);
382+
}
383+
}
384+
385+
return $resolved;
386+
}
387+
388+
/**
389+
* @return array<string, TypeAliasImportTag>
390+
*/
391+
public function resolveTypeAliasImportTags(PhpDocNode $phpDocNode, NameScope $nameScope): array
392+
{
393+
$resolved = [];
394+
395+
foreach (['@psalm-import-type', '@phpstan-import-type'] as $tagName) {
396+
foreach ($phpDocNode->getTypeAliasImportTagValues($tagName) as $typeAliasImportTagValue) {
397+
$importedAlias = $typeAliasImportTagValue->importedAlias;
398+
$importedFrom = $nameScope->resolveStringName($typeAliasImportTagValue->importedFrom->name);
399+
$importedAs = $typeAliasImportTagValue->importedAs;
400+
$resolved[$importedAs ?? $importedAlias] = new TypeAliasImportTag($importedAlias, $importedFrom, $importedAs);
401+
}
402+
}
403+
404+
return $resolved;
405+
}
406+
368407
public function resolveDeprecatedTag(PhpDocNode $phpDocNode, NameScope $nameScope): ?\PHPStan\PhpDoc\Tag\DeprecatedTag
369408
{
370409
foreach ($phpDocNode->getDeprecatedTagValues() as $deprecatedTagValue) {

src/PhpDoc/ResolvedPhpDocBlock.php

+45
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
use PHPStan\PhpDoc\Tag\ParamTag;
88
use PHPStan\PhpDoc\Tag\ReturnTag;
99
use PHPStan\PhpDoc\Tag\ThrowsTag;
10+
use PHPStan\PhpDoc\Tag\TypeAliasImportTag;
11+
use PHPStan\PhpDoc\Tag\TypeAliasTag;
1012
use PHPStan\PhpDoc\Tag\TypedTag;
1113
use PHPStan\PhpDoc\Tag\VarTag;
1214
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
@@ -64,6 +66,12 @@ class ResolvedPhpDocBlock
6466
/** @var array<MixinTag>|false */
6567
private $mixinTags = false;
6668

69+
/** @var array<TypeAliasTag>|false */
70+
private $typeAliasTags = false;
71+
72+
/** @var array<TypeAliasImportTag>|false */
73+
private $typeAliasImportTags = false;
74+
6775
/** @var \PHPStan\PhpDoc\Tag\DeprecatedTag|false|null */
6876
private $deprecatedTag = false;
6977

@@ -133,6 +141,8 @@ public static function createEmpty(): self
133141
$self->returnTag = null;
134142
$self->throwsTag = null;
135143
$self->mixinTags = [];
144+
$self->typeAliasTags = [];
145+
$self->typeAliasImportTags = [];
136146
$self->deprecatedTag = null;
137147
$self->isDeprecated = false;
138148
$self->isInternal = false;
@@ -176,6 +186,8 @@ public function merge(array $parents, array $parentPhpDocBlocks): self
176186
$result->returnTag = self::mergeReturnTags($this->getReturnTag(), $parents, $parentPhpDocBlocks);
177187
$result->throwsTag = self::mergeThrowsTags($this->getThrowsTag(), $parents);
178188
$result->mixinTags = $this->getMixinTags();
189+
$result->typeAliasTags = $this->getTypeAliasTags();
190+
$result->typeAliasImportTags = $this->getTypeAliasImportTags();
179191
$result->deprecatedTag = $this->getDeprecatedTag();
180192
$result->isDeprecated = $result->deprecatedTag !== null;
181193
$result->isInternal = $this->isInternal();
@@ -219,6 +231,9 @@ public function changeParameterNamesByMapping(array $parameterNameMapping): self
219231
$self->paramTags = $newParamTags;
220232
$self->returnTag = $this->returnTag;
221233
$self->throwsTag = $this->throwsTag;
234+
$self->mixinTags = $this->mixinTags;
235+
$self->typeAliasTags = $this->typeAliasTags;
236+
$self->typeAliasImportTags = $this->typeAliasImportTags;
222237
$self->deprecatedTag = $this->deprecatedTag;
223238
$self->isDeprecated = $this->isDeprecated;
224239
$self->isInternal = $this->isInternal;
@@ -399,6 +414,36 @@ public function getMixinTags(): array
399414
return $this->mixinTags;
400415
}
401416

417+
/**
418+
* @return array<TypeAliasTag>
419+
*/
420+
public function getTypeAliasTags(): array
421+
{
422+
if ($this->typeAliasTags === false) {
423+
$this->typeAliasTags = $this->phpDocNodeResolver->resolveTypeAliasTags(
424+
$this->phpDocNode,
425+
$this->getNameScope()
426+
);
427+
}
428+
429+
return $this->typeAliasTags;
430+
}
431+
432+
/**
433+
* @return array<TypeAliasImportTag>
434+
*/
435+
public function getTypeAliasImportTags(): array
436+
{
437+
if ($this->typeAliasImportTags === false) {
438+
$this->typeAliasImportTags = $this->phpDocNodeResolver->resolveTypeAliasImportTags(
439+
$this->phpDocNode,
440+
$this->getNameScope()
441+
);
442+
}
443+
444+
return $this->typeAliasImportTags;
445+
}
446+
402447
public function getDeprecatedTag(): ?\PHPStan\PhpDoc\Tag\DeprecatedTag
403448
{
404449
if ($this->deprecatedTag === false) {

src/PhpDoc/Tag/TypeAliasImportTag.php

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\PhpDoc\Tag;
4+
5+
final class TypeAliasImportTag
6+
{
7+
8+
private string $importedAlias;
9+
10+
private string $importedFrom;
11+
12+
private ?string $importedAs;
13+
14+
public function __construct(string $importedAlias, string $importedFrom, ?string $importedAs)
15+
{
16+
$this->importedAlias = $importedAlias;
17+
$this->importedFrom = $importedFrom;
18+
$this->importedAs = $importedAs;
19+
}
20+
21+
public function getImportedAlias(): string
22+
{
23+
return $this->importedAlias;
24+
}
25+
26+
public function getImportedFrom(): string
27+
{
28+
return $this->importedFrom;
29+
}
30+
31+
public function getImportedAs(): ?string
32+
{
33+
return $this->importedAs;
34+
}
35+
36+
}

src/PhpDoc/Tag/TypeAliasTag.php

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\PhpDoc\Tag;
4+
5+
use PHPStan\Analyser\NameScope;
6+
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
7+
8+
class TypeAliasTag
9+
{
10+
11+
private string $aliasName;
12+
13+
private TypeNode $typeNode;
14+
15+
private NameScope $nameScope;
16+
17+
public function __construct(
18+
string $aliasName,
19+
TypeNode $typeNode,
20+
NameScope $nameScope
21+
)
22+
{
23+
$this->aliasName = $aliasName;
24+
$this->typeNode = $typeNode;
25+
$this->nameScope = $nameScope;
26+
}
27+
28+
public function getAliasName(): string
29+
{
30+
return $this->aliasName;
31+
}
32+
33+
public function getTypeAlias(): \PHPStan\Type\TypeAlias
34+
{
35+
return new \PHPStan\Type\TypeAlias(
36+
$this->typeNode,
37+
$this->nameScope
38+
);
39+
}
40+
41+
}

src/PhpDoc/TypeAlias/TypeAliasesTypeNodeResolverExtension.php

-78
This file was deleted.

0 commit comments

Comments
 (0)