Skip to content

Commit ffaba4f

Browse files
committed
Fix attributes for more types
1 parent 142198e commit ffaba4f

File tree

3 files changed

+73
-12
lines changed

3 files changed

+73
-12
lines changed

src/Parser/PhpDocParser.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -493,10 +493,15 @@ private function parseTemplateTagValue(TokenIterator $tokens, bool $parseDescrip
493493

494494
private function parseExtendsTagValue(string $tagName, TokenIterator $tokens): Ast\PhpDoc\PhpDocTagValueNode
495495
{
496+
$startLine = $tokens->currentTokenLine();
497+
$startIndex = $tokens->currentTokenIndex();
496498
$baseType = new IdentifierTypeNode($tokens->currentTokenValue());
497499
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
498500

499-
$type = $this->typeParser->parseGeneric($tokens, $baseType);
501+
$type = $this->typeParser->parseGeneric(
502+
$tokens,
503+
$this->typeParser->enrichWithAttributes($tokens, $baseType, $startLine, $startIndex)
504+
);
500505

501506
$description = $this->parseOptionalDescription($tokens);
502507

src/Parser/TypeParser.php

+63-11
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,12 @@ public function parse(TokenIterator $tokens): Ast\Type\TypeNode
6262
}
6363

6464
/**
65+
* @internal
6566
* @template T of Ast\Node
6667
* @param T $type
6768
* @return T
6869
*/
69-
private function enrichWithAttributes(TokenIterator $tokens, Ast\Node $type, int $startLine, int $startIndex): Ast\Node
70+
public function enrichWithAttributes(TokenIterator $tokens, Ast\Node $type, int $startLine, int $startIndex): Ast\Node
7071
{
7172
$endLine = $tokens->currentTokenLine();
7273
$endIndex = $tokens->currentTokenIndex();
@@ -166,7 +167,7 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
166167
$isHtml = $this->isHtml($tokens);
167168
$tokens->rollback();
168169
if ($isHtml) {
169-
return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
170+
return $type;
170171
}
171172

172173
$type = $this->parseGeneric($tokens, $type);
@@ -188,7 +189,10 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
188189
}
189190

190191
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
191-
$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
192+
$type = $this->tryParseArrayOrOffsetAccess(
193+
$tokens,
194+
$this->enrichWithAttributes($tokens, $type, $startLine, $startIndex)
195+
);
192196
}
193197
}
194198

@@ -398,7 +402,14 @@ public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode
398402
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
399403
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
400404
// trailing comma case
401-
return new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances);
405+
$type = new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances);
406+
$startLine = $baseType->getAttribute(Ast\Attribute::START_LINE);
407+
$startIndex = $baseType->getAttribute(Ast\Attribute::START_INDEX);
408+
if ($startLine !== null && $startIndex !== null) {
409+
$type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
410+
}
411+
412+
return $type;
402413
}
403414
[$genericTypes[], $variances[]] = $this->parseGenericTypeArgument($tokens);
404415
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
@@ -407,7 +418,14 @@ public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode
407418
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
408419
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
409420

410-
return new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances);
421+
$type = new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances);
422+
$startLine = $baseType->getAttribute(Ast\Attribute::START_LINE);
423+
$startIndex = $baseType->getAttribute(Ast\Attribute::START_INDEX);
424+
if ($startLine !== null && $startIndex !== null) {
425+
$type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
426+
}
427+
428+
return $type;
411429
}
412430

413431

@@ -417,9 +435,11 @@ public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode
417435
*/
418436
public function parseGenericTypeArgument(TokenIterator $tokens): array
419437
{
438+
$startLine = $tokens->currentTokenLine();
439+
$startIndex = $tokens->currentTokenIndex();
420440
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) {
421441
return [
422-
new Ast\Type\IdentifierTypeNode('mixed'),
442+
$this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode('mixed'), $startLine, $startIndex),
423443
Ast\Type\GenericTypeNode::VARIANCE_BIVARIANT,
424444
];
425445
}
@@ -498,6 +518,8 @@ private function parseCallableParameter(TokenIterator $tokens): Ast\Type\Callabl
498518
/** @phpstan-impure */
499519
private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNode
500520
{
521+
$startLine = $tokens->currentTokenLine();
522+
$startIndex = $tokens->currentTokenIndex();
501523
if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) {
502524
$type = $this->parseNullable($tokens);
503525

@@ -510,15 +532,33 @@ private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNo
510532
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
511533

512534
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
513-
$type = $this->parseGeneric($tokens, $type);
535+
$type = $this->parseGeneric(
536+
$tokens,
537+
$this->enrichWithAttributes(
538+
$tokens,
539+
$type,
540+
$startLine,
541+
$startIndex
542+
)
543+
);
514544

515545
} elseif (in_array($type->name, ['array', 'list'], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {
516-
$type = $this->parseArrayShape($tokens, $type, $type->name);
546+
$type = $this->parseArrayShape($tokens, $this->enrichWithAttributes(
547+
$tokens,
548+
$type,
549+
$startLine,
550+
$startIndex
551+
), $type->name);
517552
}
518553
}
519554

520555
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
521-
$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
556+
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
557+
$tokens,
558+
$type,
559+
$startLine,
560+
$startIndex
561+
));
522562
}
523563

524564
return $type;
@@ -545,6 +585,8 @@ private function tryParseCallable(TokenIterator $tokens, Ast\Type\IdentifierType
545585
/** @phpstan-impure */
546586
private function tryParseArrayOrOffsetAccess(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode
547587
{
588+
$startLine = $tokens->currentTokenLine();
589+
$startIndex = $tokens->currentTokenIndex();
548590
try {
549591
while ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
550592
$tokens->pushSavePoint();
@@ -556,11 +598,21 @@ private function tryParseArrayOrOffsetAccess(TokenIterator $tokens, Ast\Type\Typ
556598
$offset = $this->parse($tokens);
557599
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET);
558600
$tokens->dropSavePoint();
559-
$type = new Ast\Type\OffsetAccessTypeNode($type, $offset);
601+
$type = $this->enrichWithAttributes(
602+
$tokens,
603+
new Ast\Type\OffsetAccessTypeNode($type, $offset),
604+
$startLine,
605+
$startIndex
606+
);
560607
} else {
561608
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET);
562609
$tokens->dropSavePoint();
563-
$type = new Ast\Type\ArrayTypeNode($type);
610+
$type = $this->enrichWithAttributes(
611+
$tokens,
612+
new Ast\Type\ArrayTypeNode($type),
613+
$startLine,
614+
$startIndex
615+
);
564616
}
565617
}
566618

tests/PHPStan/Parser/TypeParserTest.php

+4
Original file line numberDiff line numberDiff line change
@@ -1935,6 +1935,10 @@ public function provideParseData(): array
19351935
)
19361936
),
19371937
],
1938+
[
1939+
'callable(): ?int',
1940+
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new NullableTypeNode(new IdentifierTypeNode('int'))),
1941+
],
19381942
];
19391943
}
19401944

0 commit comments

Comments
 (0)