Skip to content

Commit 9266cca

Browse files
committed
Refactor duplicated template parsing code into TemplateTagParser.
1 parent b278de7 commit 9266cca

8 files changed

+74
-99
lines changed

src/Ast/Type/CallableTypeNode.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class CallableTypeNode implements TypeNode
1313
/** @var IdentifierTypeNode */
1414
public $identifier;
1515

16-
/** @var CallableTypeTemplateNode[] */
16+
/** @var templateTagValueNode[] */
1717
public $templates;
1818

1919
/** @var CallableTypeParameterNode[] */
@@ -24,7 +24,7 @@ class CallableTypeNode implements TypeNode
2424

2525
/**
2626
* @param CallableTypeParameterNode[] $parameters
27-
* @param CallableTypeTemplateNode[] $templates
27+
* @param TemplateTagValueNode[] $templates
2828
*/
2929
public function __construct(IdentifierTypeNode $identifier, array $parameters, TypeNode $returnType, array $templates = [])
3030
{

src/Ast/Type/CallableTypeTemplateNode.php

-35
This file was deleted.

src/Parser/PhpDocParser.php

+13-29
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,13 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
439439
case '@template-contravariant':
440440
case '@phpstan-template-contravariant':
441441
case '@psalm-template-contravariant':
442-
$tagValue = $this->parseTemplateTagValue($tokens, true);
442+
$tagValue = TemplateTagParser::parseTemplateTagValue(
443+
$this->typeParser,
444+
$tokens,
445+
function ($tokens) {
446+
return $this->parseOptionalDescription($tokens);
447+
}
448+
);
443449
break;
444450

445451
case '@extends':
@@ -923,7 +929,12 @@ private function parseMethodTagValue(TokenIterator $tokens): Ast\PhpDoc\MethodTa
923929
do {
924930
$startLine = $tokens->currentTokenLine();
925931
$startIndex = $tokens->currentTokenIndex();
926-
$templateTypes[] = $this->enrichWithAttributes($tokens, $this->parseTemplateTagValue($tokens, false), $startLine, $startIndex);
932+
$templateTypes[] = $this->enrichWithAttributes(
933+
$tokens,
934+
TemplateTagParser::parseTemplateTagValue($this->typeParser, $tokens),
935+
$startLine,
936+
$startIndex
937+
);
927938
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
928939
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
929940
}
@@ -979,33 +990,6 @@ private function parseMethodTagValueParameter(TokenIterator $tokens): Ast\PhpDoc
979990
);
980991
}
981992

982-
private function parseTemplateTagValue(TokenIterator $tokens, bool $parseDescription): Ast\PhpDoc\TemplateTagValueNode
983-
{
984-
$name = $tokens->currentTokenValue();
985-
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
986-
987-
if ($tokens->tryConsumeTokenValue('of') || $tokens->tryConsumeTokenValue('as')) {
988-
$bound = $this->typeParser->parse($tokens);
989-
990-
} else {
991-
$bound = null;
992-
}
993-
994-
if ($tokens->tryConsumeTokenValue('=')) {
995-
$default = $this->typeParser->parse($tokens);
996-
} else {
997-
$default = null;
998-
}
999-
1000-
if ($parseDescription) {
1001-
$description = $this->parseOptionalDescription($tokens);
1002-
} else {
1003-
$description = '';
1004-
}
1005-
1006-
return new Ast\PhpDoc\TemplateTagValueNode($name, $bound, $description, $default);
1007-
}
1008-
1009993
private function parseExtendsTagValue(string $tagName, TokenIterator $tokens): Ast\PhpDoc\PhpDocTagValueNode
1010994
{
1011995
$startLine = $tokens->currentTokenLine();

src/Parser/TemplateTagParser.php

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\PhpDocParser\Parser;
4+
5+
use PHPStan\PhpDocParser\Ast;
6+
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
7+
use PHPStan\PhpDocParser\Lexer\Lexer;
8+
9+
class TemplateTagParser
10+
{
11+
/**
12+
* @throws ParserException
13+
* @param ?callable(TokenIterator): string $parseDescription
14+
*/
15+
public static function parseTemplateTagValue(
16+
TypeParser $typeParser,
17+
TokenIterator $tokens,
18+
?callable $parseDescription = null
19+
): TemplateTagValueNode
20+
{
21+
$name = $tokens->currentTokenValue();
22+
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
23+
24+
if ($tokens->tryConsumeTokenValue('of') || $tokens->tryConsumeTokenValue('as')) {
25+
$bound = $typeParser->parse($tokens);
26+
27+
} else {
28+
$bound = null;
29+
}
30+
31+
if ($tokens->tryConsumeTokenValue('=')) {
32+
$default = $typeParser->parse($tokens);
33+
} else {
34+
$default = null;
35+
}
36+
37+
if ($parseDescription !== null) {
38+
$description = $parseDescription($tokens);
39+
} else {
40+
$description = '';
41+
}
42+
43+
return new Ast\PhpDoc\TemplateTagValueNode($name, $bound, $description, $default);
44+
}
45+
}

src/Parser/TypeParser.php

+3-16
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNod
497497

498498

499499
/**
500-
* @return Ast\Type\CallableTypeTemplateNode[]
500+
* @return Ast\Type\TemplateTagValueNode[]
501501
*
502502
* @phpstan-impure
503503
*/
@@ -527,27 +527,14 @@ private function parseCallableTemplates(TokenIterator $tokens): array
527527
}
528528

529529

530-
private function parseCallableTemplateArgument(TokenIterator $tokens): Ast\Type\CallableTypeTemplateNode
530+
private function parseCallableTemplateArgument(TokenIterator $tokens): Ast\PhpDoc\TemplateTagValueNode
531531
{
532532
$startLine = $tokens->currentTokenLine();
533533
$startIndex = $tokens->currentTokenIndex();
534534

535-
$identifier = $this->enrichWithAttributes(
536-
$tokens,
537-
new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue()),
538-
$startLine,
539-
$startIndex
540-
);
541-
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
542-
543-
$bound = null;
544-
if ($tokens->tryConsumeTokenValue('of')) {
545-
$bound = $this->parse($tokens);
546-
}
547-
548535
return $this->enrichWithAttributes(
549536
$tokens,
550-
new Ast\Type\CallableTypeTemplateNode($identifier, $bound),
537+
TemplateTagParser::parseTemplateTagValue($this, $tokens),
551538
$startLine,
552539
$startIndex
553540
);

src/Printer/Printer.php

+1-7
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
4242
use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
4343
use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
44-
use PHPStan\PhpDocParser\Ast\Type\CallableTypeTemplateNode;
4544
use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeForParameterNode;
4645
use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeNode;
4746
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
@@ -226,11 +225,6 @@ function (PhpDocChildNode $child): string {
226225
$isOptional = $node->isOptional ? '=' : '';
227226
return trim("{$type}{$isReference}{$isVariadic}{$node->parameterName}") . $isOptional;
228227
}
229-
if ($node instanceof CallableTypeTemplateNode) {
230-
$identifier = $this->printType($node->identifier);
231-
$bound = $node->bound !== null ? ' of ' . $this->printType($node->bound) : '';
232-
return "{$identifier}{$bound}";
233-
}
234228
if ($node instanceof DoctrineAnnotation) {
235229
return (string) $node;
236230
}
@@ -378,7 +372,7 @@ private function printType(TypeNode $node): string
378372
$returnType = $this->printType($node->returnType);
379373
}
380374
$template = $node->templates !== []
381-
? '<' . implode(', ', array_map(function (CallableTypeTemplateNode $templateNode): string {
375+
? '<' . implode(', ', array_map(function (TemplateTagValueNode $templateNode): string {
382376
return $this->print($templateNode);
383377
}, $node->templates)) . '>'
384378
: '';

tests/PHPStan/Parser/TypeParserTest.php

+6-6
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
use PHPStan\PhpDocParser\Ast\ConstExpr\QuoteAwareConstExprStringNode;
1111
use PHPStan\PhpDocParser\Ast\Node;
1212
use PHPStan\PhpDocParser\Ast\NodeTraverser;
13+
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
1314
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode;
1415
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
1516
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
1617
use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
1718
use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
18-
use PHPStan\PhpDocParser\Ast\Type\CallableTypeTemplateNode;
1919
use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeForParameterNode;
2020
use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeNode;
2121
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
@@ -913,7 +913,7 @@ public function provideParseData(): array
913913
],
914914
new IdentifierTypeNode('C'),
915915
[
916-
new CallableTypeTemplateNode(new IdentifierTypeNode('A'), null),
916+
new TemplateTagValueNode('A', null, ''),
917917
]
918918
),
919919
],
@@ -951,7 +951,7 @@ public function provideParseData(): array
951951
new IdentifierTypeNode('false'),
952952
]),
953953
[
954-
new CallableTypeTemplateNode(new IdentifierTypeNode('T'), new IdentifierTypeNode('Model')),
954+
new TemplateTagValueNode('T', new IdentifierTypeNode('Model'), ''),
955955
]
956956
),
957957
],
@@ -988,11 +988,11 @@ public function provideParseData(): array
988988
),
989989
]),
990990
[
991-
new CallableTypeTemplateNode(new IdentifierTypeNode('Tx'), new UnionTypeNode([
991+
new TemplateTagValueNode('Tx', new UnionTypeNode([
992992
new IdentifierTypeNode('X'),
993993
new IdentifierTypeNode('Z'),
994-
])),
995-
new CallableTypeTemplateNode(new IdentifierTypeNode('Ty'), new IdentifierTypeNode('Y')),
994+
]), ''),
995+
new TemplateTagValueNode('Ty', new IdentifierTypeNode('Y'), ''),
996996
]
997997
),
998998
],

tests/PHPStan/Printer/PrinterTest.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
2929
use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
3030
use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
31-
use PHPStan\PhpDocParser\Ast\Type\CallableTypeTemplateNode;
3231
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
3332
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
3433
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
@@ -595,9 +594,10 @@ public function enterNode(Node $node)
595594
public function enterNode(Node $node)
596595
{
597596
if ($node instanceof CallableTypeNode) {
598-
$node->templates[] = new CallableTypeTemplateNode(
599-
new IdentifierTypeNode('T'),
600-
new IdentifierTypeNode('int')
597+
$node->templates[] = new TemplateTagValueNode(
598+
'T',
599+
new IdentifierTypeNode('int'),
600+
''
601601
);
602602
}
603603

0 commit comments

Comments
 (0)