@@ -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
0 commit comments