Skip to content

Commit de6eace

Browse files
committed
Refactor duplicated template parsing code into TypeParser.
1 parent b278de7 commit de6eace

File tree

7 files changed

+72
-107
lines changed

7 files changed

+72
-107
lines changed

src/Ast/Type/CallableTypeNode.php

+8-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\PhpDocParser\Ast\Type;
44

55
use PHPStan\PhpDocParser\Ast\NodeAttributes;
6+
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
67
use function implode;
78

89
class CallableTypeNode implements TypeNode
@@ -13,8 +14,8 @@ class CallableTypeNode implements TypeNode
1314
/** @var IdentifierTypeNode */
1415
public $identifier;
1516

16-
/** @var CallableTypeTemplateNode[] */
17-
public $templates;
17+
/** @var TemplateTagValueNode[] */
18+
public $templateTypes;
1819

1920
/** @var CallableTypeParameterNode[] */
2021
public $parameters;
@@ -24,14 +25,14 @@ class CallableTypeNode implements TypeNode
2425

2526
/**
2627
* @param CallableTypeParameterNode[] $parameters
27-
* @param CallableTypeTemplateNode[] $templates
28+
* @param TemplateTagValueNode[] $templateTypes
2829
*/
29-
public function __construct(IdentifierTypeNode $identifier, array $parameters, TypeNode $returnType, array $templates = [])
30+
public function __construct(IdentifierTypeNode $identifier, array $parameters, TypeNode $returnType, array $templateTypes = [])
3031
{
3132
$this->identifier = $identifier;
3233
$this->parameters = $parameters;
3334
$this->returnType = $returnType;
34-
$this->templates = $templates;
35+
$this->templateTypes = $templateTypes;
3536
}
3637

3738

@@ -41,8 +42,8 @@ public function __toString(): string
4142
if ($returnType instanceof self) {
4243
$returnType = "({$returnType})";
4344
}
44-
$template = $this->templates !== []
45-
? '<' . implode(', ', $this->templates) . '>'
45+
$template = $this->templateTypes !== []
46+
? '<' . implode(', ', $this->templateTypes) . '>'
4647
: '';
4748
$parameters = implode(', ', $this->parameters);
4849
return "{$this->identifier}{$template}({$parameters}): {$returnType}";

src/Ast/Type/CallableTypeTemplateNode.php

-35
This file was deleted.

src/Parser/PhpDocParser.php

+12-29
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,12 @@ 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 = $this->typeParser->parseTemplateTagValue(
443+
$tokens,
444+
function ($tokens) {
445+
return $this->parseOptionalDescription($tokens);
446+
}
447+
);
443448
break;
444449

445450
case '@extends':
@@ -923,7 +928,12 @@ private function parseMethodTagValue(TokenIterator $tokens): Ast\PhpDoc\MethodTa
923928
do {
924929
$startLine = $tokens->currentTokenLine();
925930
$startIndex = $tokens->currentTokenIndex();
926-
$templateTypes[] = $this->enrichWithAttributes($tokens, $this->parseTemplateTagValue($tokens, false), $startLine, $startIndex);
931+
$templateTypes[] = $this->enrichWithAttributes(
932+
$tokens,
933+
$this->typeParser->parseTemplateTagValue($tokens),
934+
$startLine,
935+
$startIndex
936+
);
927937
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
928938
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
929939
}
@@ -979,33 +989,6 @@ private function parseMethodTagValueParameter(TokenIterator $tokens): Ast\PhpDoc
979989
);
980990
}
981991

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-
1009992
private function parseExtendsTagValue(string $tagName, TokenIterator $tokens): Ast\PhpDoc\PhpDocTagValueNode
1010993
{
1011994
$startLine = $tokens->currentTokenLine();

src/Parser/TypeParser.php

+38-16
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use LogicException;
66
use PHPStan\PhpDocParser\Ast;
7+
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
78
use PHPStan\PhpDocParser\Lexer\Lexer;
89
use function in_array;
910
use function str_replace;
@@ -460,6 +461,40 @@ public function parseGenericTypeArgument(TokenIterator $tokens): array
460461
return [$type, $variance];
461462
}
462463

464+
/**
465+
* @throws ParserException
466+
* @param ?callable(TokenIterator): string $parseDescription
467+
*/
468+
public function parseTemplateTagValue(
469+
TokenIterator $tokens,
470+
?callable $parseDescription = null
471+
): TemplateTagValueNode
472+
{
473+
$name = $tokens->currentTokenValue();
474+
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
475+
476+
if ($tokens->tryConsumeTokenValue('of') || $tokens->tryConsumeTokenValue('as')) {
477+
$bound = $this->parse($tokens);
478+
479+
} else {
480+
$bound = null;
481+
}
482+
483+
if ($tokens->tryConsumeTokenValue('=')) {
484+
$default = $this->parse($tokens);
485+
} else {
486+
$default = null;
487+
}
488+
489+
if ($parseDescription !== null) {
490+
$description = $parseDescription($tokens);
491+
} else {
492+
$description = '';
493+
}
494+
495+
return new Ast\PhpDoc\TemplateTagValueNode($name, $bound, $description, $default);
496+
}
497+
463498

464499
/** @phpstan-impure */
465500
private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $identifier, bool $hasTemplate): Ast\Type\TypeNode
@@ -497,7 +532,7 @@ private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNod
497532

498533

499534
/**
500-
* @return Ast\Type\CallableTypeTemplateNode[]
535+
* @return Ast\PhpDoc\TemplateTagValueNode[]
501536
*
502537
* @phpstan-impure
503538
*/
@@ -527,27 +562,14 @@ private function parseCallableTemplates(TokenIterator $tokens): array
527562
}
528563

529564

530-
private function parseCallableTemplateArgument(TokenIterator $tokens): Ast\Type\CallableTypeTemplateNode
565+
private function parseCallableTemplateArgument(TokenIterator $tokens): Ast\PhpDoc\TemplateTagValueNode
531566
{
532567
$startLine = $tokens->currentTokenLine();
533568
$startIndex = $tokens->currentTokenIndex();
534569

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-
548570
return $this->enrichWithAttributes(
549571
$tokens,
550-
new Ast\Type\CallableTypeTemplateNode($identifier, $bound),
572+
$this->parseTemplateTagValue($tokens),
551573
$startLine,
552574
$startIndex
553575
);

src/Printer/Printer.php

+4-10
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;
@@ -98,7 +97,7 @@ final class Printer
9897
ArrayShapeNode::class . '->items' => ', ',
9998
ObjectShapeNode::class . '->items' => ', ',
10099
CallableTypeNode::class . '->parameters' => ', ',
101-
CallableTypeNode::class . '->templates' => ', ',
100+
CallableTypeNode::class . '->templateTypes' => ', ',
102101
GenericTypeNode::class . '->genericTypes' => ', ',
103102
ConstExprArrayNode::class . '->items' => ', ',
104103
MethodTagValueNode::class . '->parameters' => ', ',
@@ -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
}
@@ -377,10 +371,10 @@ private function printType(TypeNode $node): string
377371
} else {
378372
$returnType = $this->printType($node->returnType);
379373
}
380-
$template = $node->templates !== []
381-
? '<' . implode(', ', array_map(function (CallableTypeTemplateNode $templateNode): string {
374+
$template = $node->templateTypes !== []
375+
? '<' . implode(', ', array_map(function (TemplateTagValueNode $templateNode): string {
382376
return $this->print($templateNode);
383-
}, $node->templates)) . '>'
377+
}, $node->templateTypes)) . '>'
384378
: '';
385379
$parameters = implode(', ', array_map(function (CallableTypeParameterNode $parameterNode): string {
386380
return $this->print($parameterNode);

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->templateTypes[] = new TemplateTagValueNode(
598+
'T',
599+
new IdentifierTypeNode('int'),
600+
''
601601
);
602602
}
603603

0 commit comments

Comments
 (0)