Skip to content

Local type aliases #460

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Apr 18, 2021
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e90d916
type aliases: extract TypeAliasResolver
jiripudil Dec 30, 2020
1cf6303
type aliases: add test
jiripudil Feb 27, 2021
72154c9
type aliases: support class-scoped local aliases
jiripudil Feb 27, 2021
f54f80e
type aliases: add test for nested aliases
jiripudil Feb 27, 2021
293d9b3
type aliases: support type alias imports
jiripudil Feb 27, 2021
390cb96
fix cs and phpstan baseline
jiripudil Feb 27, 2021
a4e48fe
Correct prefix priority
ondrejmirtes Feb 28, 2021
9ed65cc
type aliases: resolve type aliases lazily and in correct NameScope
jiripudil Mar 27, 2021
de4ff0c
type aliases: remove __set_state from PhpDoc\Tag classes as they are …
jiripudil Mar 27, 2021
b8941b6
type aliases: add TemplateTypeCheck tests for local aliases
jiripudil Mar 27, 2021
7f066e5
type aliases: keep the TypeNode already resolved by phpdoc-parser
jiripudil Apr 11, 2021
3519a52
type aliases: report invalid alias definitions via a Rule instead of …
jiripudil Apr 15, 2021
a5ea824
Microoptimization
ondrejmirtes Apr 18, 2021
ce5a49a
resolvingClassTypeAliases should be unset here as well
ondrejmirtes Apr 18, 2021
e2cfe20
fix LocalTypeAliasesRule registration
jiripudil Apr 18, 2021
ec36298
remove obsolete data provider
jiripudil Apr 18, 2021
1070463
Allow type aliases to be bypassed in SignatureMapParser
ondrejmirtes Apr 18, 2021
4fc1534
Fix LocalTypeAliasesRule
ondrejmirtes Apr 18, 2021
22eb90a
LocalTypeAliasesRuleTest does not require static reflection
ondrejmirtes Apr 18, 2021
b3fa374
treat TypeAliasImportTag::$importedFrom as a class name string
jiripudil Apr 18, 2021
c8f3f4f
resolve TypeAliasImportTag::$importedFrom in the name scope when reso…
jiripudil Apr 18, 2021
25013e6
Resolve type aliases directly in resolveIdentifierTypeNode, not throu…
ondrejmirtes Apr 18, 2021
334960c
Bump memory limit for tests-fast-static-reflection a bit
ondrejmirtes Apr 18, 2021
9a8738d
Microoptimization
ondrejmirtes Apr 18, 2021
31ea9a2
Regression test
ondrejmirtes Apr 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@
checkreturn="true"
>
<arg value="-d"/>
<arg value="memory_limit=768M"/>
<arg value="memory_limit=864M"/>
<arg path="${phpunit.executable}"/>
<arg value="-c"/>
<arg value="tests/phpunit.xml"/>
Expand Down
2 changes: 1 addition & 1 deletion build/baseline-7.4.neon
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,6 @@ parameters:
count: 1
path: ../src/Reflection/ReflectionProvider/SetterReflectionProviderProvider.php
-
message: "#^Class class@anonymous/src/Testing/TestCase\\.php\\:267 has an uninitialized property \\$reflectionProvider\\. Give it default value or assign it in the constructor\\.$#"
message: "#^Class class@anonymous/src/Testing/TestCase\\.php\\:270 has an uninitialized property \\$reflectionProvider\\. Give it default value or assign it in the constructor\\.$#"
count: 1
path: ../src/Testing/TestCase.php
7 changes: 7 additions & 0 deletions conf/config.level0.neon
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,10 @@ services:

-
class: PHPStan\Rules\Whitespace\FileWhitespaceRule

-
class: PHPStan\Rules\Classes\LocalTypeAliasesRule
arguments:
globalTypeAliases: %typeAliases%
tags:
- phpstan.rules.rule
13 changes: 5 additions & 8 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -366,13 +366,6 @@ services:
-
class: PHPStan\PhpDoc\ConstExprNodeResolver

-
class: PHPStan\PhpDoc\TypeAlias\TypeAliasesTypeNodeResolverExtension
arguments:
aliases: %typeAliases%
tags:
- phpstan.phpDoc.typeNodeResolverExtension

-
class: PHPStan\PhpDoc\TypeNodeResolver

Expand Down Expand Up @@ -747,7 +740,6 @@ services:
class: PHPStan\Rules\Generics\TemplateTypeCheck
arguments:
checkClassCaseSensitivity: %checkClassCaseSensitivity%
typeAliases: %typeAliases%

-
class: PHPStan\Rules\Generics\VarianceCheck
Expand Down Expand Up @@ -802,6 +794,11 @@ services:
-
class: PHPStan\Type\FileTypeMapper

-
class: PHPStan\Type\TypeAliasResolver
arguments:
globalTypeAliases: %typeAliases%

-
class: PHPStan\Type\Php\ArgumentBasedFunctionReturnTypeExtension
tags:
Expand Down
15 changes: 14 additions & 1 deletion src/Analyser/NameScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,21 @@ class NameScope

private TemplateTypeMap $templateTypeMap;

private bool $bypassTypeAliases;

/**
* @param string|null $namespace
* @param array<string, string> $uses alias(string) => fullName(string)
* @param string|null $className
*/
public function __construct(?string $namespace, array $uses, ?string $className = null, ?string $functionName = null, ?TemplateTypeMap $templateTypeMap = null)
public function __construct(?string $namespace, array $uses, ?string $className = null, ?string $functionName = null, ?TemplateTypeMap $templateTypeMap = null, bool $bypassTypeAliases = false)
{
$this->namespace = $namespace;
$this->uses = $uses;
$this->className = $className;
$this->functionName = $functionName;
$this->templateTypeMap = $templateTypeMap ?? TemplateTypeMap::createEmpty();
$this->bypassTypeAliases = $bypassTypeAliases;
}

public function getNamespace(): ?string
Expand Down Expand Up @@ -137,6 +140,16 @@ public function unsetTemplateType(string $name): self
);
}

public function bypassTypeAliases(): self
{
return new self($this->namespace, $this->uses, $this->className, $this->functionName, $this->templateTypeMap, true);
}

public function shouldBypassTypeAliases(): bool
{
return $this->bypassTypeAliases;
}

/**
* @param mixed[] $properties
* @return self
Expand Down
39 changes: 39 additions & 0 deletions src/PhpDoc/PhpDocNodeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use PHPStan\PhpDoc\Tag\ReturnTag;
use PHPStan\PhpDoc\Tag\TemplateTag;
use PHPStan\PhpDoc\Tag\ThrowsTag;
use PHPStan\PhpDoc\Tag\TypeAliasImportTag;
use PHPStan\PhpDoc\Tag\TypeAliasTag;
use PHPStan\PhpDoc\Tag\UsesTag;
use PHPStan\PhpDoc\Tag\VarTag;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNullNode;
Expand Down Expand Up @@ -365,6 +367,43 @@ public function resolveMixinTags(PhpDocNode $phpDocNode, NameScope $nameScope):
}, $phpDocNode->getMixinTagValues());
}

/**
* @return array<string, TypeAliasTag>
*/
public function resolveTypeAliasTags(PhpDocNode $phpDocNode, NameScope $nameScope): array
{
$resolved = [];

foreach (['@psalm-type', '@phpstan-type'] as $tagName) {
foreach ($phpDocNode->getTypeAliasTagValues($tagName) as $typeAliasTagValue) {
$alias = $typeAliasTagValue->alias;
$typeNode = $typeAliasTagValue->type;
$resolved[$alias] = new TypeAliasTag($alias, $typeNode, $nameScope);
}
}

return $resolved;
}

/**
* @return array<string, TypeAliasImportTag>
*/
public function resolveTypeAliasImportTags(PhpDocNode $phpDocNode, NameScope $nameScope): array
{
$resolved = [];

foreach (['@psalm-import-type', '@phpstan-import-type'] as $tagName) {
foreach ($phpDocNode->getTypeAliasImportTagValues($tagName) as $typeAliasImportTagValue) {
$importedAlias = $typeAliasImportTagValue->importedAlias;
$importedFrom = $nameScope->resolveStringName($typeAliasImportTagValue->importedFrom->name);
$importedAs = $typeAliasImportTagValue->importedAs;
$resolved[$importedAs ?? $importedAlias] = new TypeAliasImportTag($importedAlias, $importedFrom, $importedAs);
}
}

return $resolved;
}

public function resolveDeprecatedTag(PhpDocNode $phpDocNode, NameScope $nameScope): ?\PHPStan\PhpDoc\Tag\DeprecatedTag
{
foreach ($phpDocNode->getDeprecatedTagValues() as $deprecatedTagValue) {
Expand Down
45 changes: 45 additions & 0 deletions src/PhpDoc/ResolvedPhpDocBlock.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use PHPStan\PhpDoc\Tag\ParamTag;
use PHPStan\PhpDoc\Tag\ReturnTag;
use PHPStan\PhpDoc\Tag\ThrowsTag;
use PHPStan\PhpDoc\Tag\TypeAliasImportTag;
use PHPStan\PhpDoc\Tag\TypeAliasTag;
use PHPStan\PhpDoc\Tag\TypedTag;
use PHPStan\PhpDoc\Tag\VarTag;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
Expand Down Expand Up @@ -64,6 +66,12 @@ class ResolvedPhpDocBlock
/** @var array<MixinTag>|false */
private $mixinTags = false;

/** @var array<TypeAliasTag>|false */
private $typeAliasTags = false;

/** @var array<TypeAliasImportTag>|false */
private $typeAliasImportTags = false;

/** @var \PHPStan\PhpDoc\Tag\DeprecatedTag|false|null */
private $deprecatedTag = false;

Expand Down Expand Up @@ -133,6 +141,8 @@ public static function createEmpty(): self
$self->returnTag = null;
$self->throwsTag = null;
$self->mixinTags = [];
$self->typeAliasTags = [];
$self->typeAliasImportTags = [];
$self->deprecatedTag = null;
$self->isDeprecated = false;
$self->isInternal = false;
Expand Down Expand Up @@ -176,6 +186,8 @@ public function merge(array $parents, array $parentPhpDocBlocks): self
$result->returnTag = self::mergeReturnTags($this->getReturnTag(), $parents, $parentPhpDocBlocks);
$result->throwsTag = self::mergeThrowsTags($this->getThrowsTag(), $parents);
$result->mixinTags = $this->getMixinTags();
$result->typeAliasTags = $this->getTypeAliasTags();
$result->typeAliasImportTags = $this->getTypeAliasImportTags();
$result->deprecatedTag = $this->getDeprecatedTag();
$result->isDeprecated = $result->deprecatedTag !== null;
$result->isInternal = $this->isInternal();
Expand Down Expand Up @@ -219,6 +231,9 @@ public function changeParameterNamesByMapping(array $parameterNameMapping): self
$self->paramTags = $newParamTags;
$self->returnTag = $this->returnTag;
$self->throwsTag = $this->throwsTag;
$self->mixinTags = $this->mixinTags;
$self->typeAliasTags = $this->typeAliasTags;
$self->typeAliasImportTags = $this->typeAliasImportTags;
$self->deprecatedTag = $this->deprecatedTag;
$self->isDeprecated = $this->isDeprecated;
$self->isInternal = $this->isInternal;
Expand Down Expand Up @@ -399,6 +414,36 @@ public function getMixinTags(): array
return $this->mixinTags;
}

/**
* @return array<TypeAliasTag>
*/
public function getTypeAliasTags(): array
{
if ($this->typeAliasTags === false) {
$this->typeAliasTags = $this->phpDocNodeResolver->resolveTypeAliasTags(
$this->phpDocNode,
$this->getNameScope()
);
}

return $this->typeAliasTags;
}

/**
* @return array<TypeAliasImportTag>
*/
public function getTypeAliasImportTags(): array
{
if ($this->typeAliasImportTags === false) {
$this->typeAliasImportTags = $this->phpDocNodeResolver->resolveTypeAliasImportTags(
$this->phpDocNode,
$this->getNameScope()
);
}

return $this->typeAliasImportTags;
}

public function getDeprecatedTag(): ?\PHPStan\PhpDoc\Tag\DeprecatedTag
{
if ($this->deprecatedTag === false) {
Expand Down
36 changes: 36 additions & 0 deletions src/PhpDoc/Tag/TypeAliasImportTag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php declare(strict_types = 1);

namespace PHPStan\PhpDoc\Tag;

final class TypeAliasImportTag
{

private string $importedAlias;

private string $importedFrom;

private ?string $importedAs;

public function __construct(string $importedAlias, string $importedFrom, ?string $importedAs)
{
$this->importedAlias = $importedAlias;
$this->importedFrom = $importedFrom;
$this->importedAs = $importedAs;
}

public function getImportedAlias(): string
{
return $this->importedAlias;
}

public function getImportedFrom(): string
{
return $this->importedFrom;
}

public function getImportedAs(): ?string
{
return $this->importedAs;
}

}
41 changes: 41 additions & 0 deletions src/PhpDoc/Tag/TypeAliasTag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php declare(strict_types = 1);

namespace PHPStan\PhpDoc\Tag;

use PHPStan\Analyser\NameScope;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;

class TypeAliasTag
{

private string $aliasName;

private TypeNode $typeNode;

private NameScope $nameScope;

public function __construct(
string $aliasName,
TypeNode $typeNode,
NameScope $nameScope
)
{
$this->aliasName = $aliasName;
$this->typeNode = $typeNode;
$this->nameScope = $nameScope;
}

public function getAliasName(): string
{
return $this->aliasName;
}

public function getTypeAlias(): \PHPStan\Type\TypeAlias
{
return new \PHPStan\Type\TypeAlias(
$this->typeNode,
$this->nameScope
);
}

}
78 changes: 0 additions & 78 deletions src/PhpDoc/TypeAlias/TypeAliasesTypeNodeResolverExtension.php

This file was deleted.

Loading