Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2e17e4a

Browse files
jiripudilondrejmirtes
authored andcommitted
type aliases: support @phpstan-import-type and @psalm-import-type tags
1 parent 2d862ef commit 2e17e4a

File tree

4 files changed

+173
-2
lines changed

4 files changed

+173
-2
lines changed

‎src/Ast/PhpDoc/PhpDocNode.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,20 @@ public function getTypeAliasTagValues(string $tagName = '@phpstan-type'): array
252252
}
253253

254254

255+
/**
256+
* @return TypeAliasImportTagValueNode[]
257+
*/
258+
public function getTypeAliasImportTagValues(string $tagName = '@phpstan-import-type'): array
259+
{
260+
return array_column(
261+
array_filter($this->getTagsByName($tagName), static function (PhpDocTagNode $tag): bool {
262+
return $tag->value instanceof TypeAliasImportTagValueNode;
263+
}),
264+
'value'
265+
);
266+
}
267+
268+
255269
public function __toString(): string
256270
{
257271
return "/**\n * " . implode("\n * ", $this->children) . '*/';
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\PhpDocParser\Ast\PhpDoc;
4+
5+
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
6+
7+
class TypeAliasImportTagValueNode implements PhpDocTagValueNode
8+
{
9+
10+
/** @var string */
11+
public $importedAlias;
12+
13+
/** @var IdentifierTypeNode */
14+
public $importedFrom;
15+
16+
/** @var string|null */
17+
public $importedAs;
18+
19+
public function __construct(string $importedAlias, IdentifierTypeNode $importedFrom, ?string $importedAs)
20+
{
21+
$this->importedAlias = $importedAlias;
22+
$this->importedFrom = $importedFrom;
23+
$this->importedAs = $importedAs;
24+
}
25+
26+
public function __toString(): string
27+
{
28+
return trim(
29+
"{$this->importedAlias} from {$this->importedFrom}"
30+
. ($this->importedAs !== null ? " as {$this->importedAs}" : '')
31+
);
32+
}
33+
34+
}

‎src/Parser/PhpDocParser.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
194194
$tagValue = $this->parseTypeAliasTagValue($tokens);
195195
break;
196196

197+
case '@phpstan-import-type':
198+
case '@psalm-import-type':
199+
$tagValue = $this->parseTypeAliasImportTagValue($tokens);
200+
break;
201+
197202
default:
198203
$tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescription($tokens));
199204
break;
@@ -382,6 +387,32 @@ private function parseTypeAliasTagValue(TokenIterator $tokens): Ast\PhpDoc\TypeA
382387
return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $type);
383388
}
384389

390+
private function parseTypeAliasImportTagValue(TokenIterator $tokens): Ast\PhpDoc\TypeAliasImportTagValueNode
391+
{
392+
$importedAlias = $tokens->currentTokenValue();
393+
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
394+
395+
if (!$tokens->tryConsumeTokenValue('from')) {
396+
throw new \PHPStan\PhpDocParser\Parser\ParserException(
397+
$tokens->currentTokenValue(),
398+
$tokens->currentTokenType(),
399+
$tokens->currentTokenOffset(),
400+
Lexer::TOKEN_IDENTIFIER
401+
);
402+
}
403+
404+
$importedFrom = $this->typeParser->parse($tokens);
405+
assert($importedFrom instanceof IdentifierTypeNode);
406+
407+
$importedAs = null;
408+
if ($tokens->tryConsumeTokenValue('as')) {
409+
$importedAs = $tokens->currentTokenValue();
410+
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
411+
}
412+
413+
return new Ast\PhpDoc\TypeAliasImportTagValueNode($importedAlias, $importedFrom, $importedAs);
414+
}
415+
385416
private function parseOptionalVariableName(TokenIterator $tokens): string
386417
{
387418
if ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) {

‎tests/PHPStan/Parser/PhpDocParserTest.php

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
2424
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
2525
use PHPStan\PhpDocParser\Ast\PhpDoc\ThrowsTagValueNode;
26+
use PHPStan\PhpDocParser\Ast\PhpDoc\TypeAliasImportTagValueNode;
2627
use PHPStan\PhpDocParser\Ast\PhpDoc\TypeAliasTagValueNode;
2728
use PHPStan\PhpDocParser\Ast\PhpDoc\UsesTagValueNode;
2829
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
@@ -68,6 +69,7 @@ protected function setUp(): void
6869
* @dataProvider provideTemplateTagsData
6970
* @dataProvider provideExtendsTagsData
7071
* @dataProvider provideTypeAliasTagsData
72+
* @dataProvider provideTypeAliasImportTagsData
7173
* @dataProvider provideRealWorldExampleData
7274
* @dataProvider provideDescriptionWithOrWithoutHtml
7375
* @param string $label
@@ -2904,7 +2906,7 @@ public function provideTypeAliasTagsData(): \Iterator
29042906
'@phpstan-type',
29052907
new InvalidTagValueNode(
29062908
'TypeAlias',
2907-
new ParserException(
2909+
new \PHPStan\PhpDocParser\Parser\ParserException(
29082910
'*/',
29092911
Lexer::TOKEN_CLOSE_PHPDOC,
29102912
28,
@@ -2923,7 +2925,7 @@ public function provideTypeAliasTagsData(): \Iterator
29232925
'@phpstan-type',
29242926
new InvalidTagValueNode(
29252927
'',
2926-
new ParserException(
2928+
new \PHPStan\PhpDocParser\Parser\ParserException(
29272929
'*/',
29282930
Lexer::TOKEN_CLOSE_PHPDOC,
29292931
18,
@@ -2935,6 +2937,96 @@ public function provideTypeAliasTagsData(): \Iterator
29352937
];
29362938
}
29372939

2940+
public function provideTypeAliasImportTagsData(): \Iterator
2941+
{
2942+
yield [
2943+
'OK',
2944+
'/** @phpstan-import-type TypeAlias from AnotherClass */',
2945+
new PhpDocNode([
2946+
new PhpDocTagNode(
2947+
'@phpstan-import-type',
2948+
new TypeAliasImportTagValueNode(
2949+
'TypeAlias',
2950+
new IdentifierTypeNode('AnotherClass'),
2951+
null
2952+
)
2953+
),
2954+
]),
2955+
];
2956+
2957+
yield [
2958+
'OK with alias',
2959+
'/** @phpstan-import-type TypeAlias from AnotherClass as DifferentAlias */',
2960+
new PhpDocNode([
2961+
new PhpDocTagNode(
2962+
'@phpstan-import-type',
2963+
new TypeAliasImportTagValueNode(
2964+
'TypeAlias',
2965+
new IdentifierTypeNode('AnotherClass'),
2966+
'DifferentAlias'
2967+
)
2968+
),
2969+
]),
2970+
];
2971+
2972+
yield [
2973+
'invalid missing from',
2974+
'/** @phpstan-import-type TypeAlias */',
2975+
new PhpDocNode([
2976+
new PhpDocTagNode(
2977+
'@phpstan-import-type',
2978+
new InvalidTagValueNode(
2979+
'TypeAlias',
2980+
new \PHPStan\PhpDocParser\Parser\ParserException(
2981+
'*/',
2982+
Lexer::TOKEN_CLOSE_PHPDOC,
2983+
35,
2984+
Lexer::TOKEN_IDENTIFIER
2985+
)
2986+
)
2987+
),
2988+
]),
2989+
];
2990+
2991+
yield [
2992+
'invalid missing from with alias',
2993+
'/** @phpstan-import-type TypeAlias as DifferentAlias */',
2994+
new PhpDocNode([
2995+
new PhpDocTagNode(
2996+
'@phpstan-import-type',
2997+
new InvalidTagValueNode(
2998+
'TypeAlias as DifferentAlias',
2999+
new \PHPStan\PhpDocParser\Parser\ParserException(
3000+
'as',
3001+
Lexer::TOKEN_IDENTIFIER,
3002+
35,
3003+
Lexer::TOKEN_IDENTIFIER
3004+
)
3005+
)
3006+
),
3007+
]),
3008+
];
3009+
3010+
yield [
3011+
'invalid empty',
3012+
'/** @phpstan-import-type */',
3013+
new PhpDocNode([
3014+
new PhpDocTagNode(
3015+
'@phpstan-import-type',
3016+
new InvalidTagValueNode(
3017+
'',
3018+
new \PHPStan\PhpDocParser\Parser\ParserException(
3019+
'*/',
3020+
Lexer::TOKEN_CLOSE_PHPDOC,
3021+
25,
3022+
Lexer::TOKEN_IDENTIFIER
3023+
)
3024+
)
3025+
),
3026+
]),
3027+
];
3028+
}
3029+
29383030
public function providerDebug(): \Iterator
29393031
{
29403032
$sample = '/**

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /