Skip to content

Commit ddc8c7a

Browse files
committed
Set start and end indexes to node attributes
1 parent f9ecd17 commit ddc8c7a

File tree

6 files changed

+70
-15
lines changed

6 files changed

+70
-15
lines changed

src/Ast/Attribute.php

+3
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,7 @@ final class Attribute
88
public const START_LINE = 'startLine';
99
public const END_LINE = 'endLine';
1010

11+
public const START_INDEX = 'startIndex';
12+
public const END_INDEX = 'endIndex';
13+
1114
}

src/Parser/PhpDocParser.php

+26-1
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ class PhpDocParser
3434
/** @var bool */
3535
private $useLinesAttributes;
3636

37+
/** @var bool */
38+
private $useIndexAttributes;
39+
3740
/**
38-
* @param array{lines?: bool} $usedAttributes
41+
* @param array{lines?: bool, indexes?: bool} $usedAttributes
3942
*/
4043
public function __construct(
4144
TypeParser $typeParser,
@@ -50,6 +53,7 @@ public function __construct(
5053
$this->requireWhitespaceBeforeDescription = $requireWhitespaceBeforeDescription;
5154
$this->preserveTypeAliasesWithInvalidTypes = $preserveTypeAliasesWithInvalidTypes;
5255
$this->useLinesAttributes = $usedAttributes['lines'] ?? false;
56+
$this->useIndexAttributes = $usedAttributes['indexes'] ?? false;
5357
}
5458

5559

@@ -91,26 +95,40 @@ private function parseChild(TokenIterator $tokens): Ast\PhpDoc\PhpDocChildNode
9195
{
9296
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) {
9397
$startLine = $tokens->currentTokenLine();
98+
$startIndex = $tokens->currentTokenIndex();
9499
$tag = $this->parseTag($tokens);
95100
$endLine = $tokens->currentTokenLine();
101+
$endIndex = $tokens->currentTokenIndex();
96102

97103
if ($this->useLinesAttributes) {
98104
$tag->setAttribute(Ast\Attribute::START_LINE, $startLine);
99105
$tag->setAttribute(Ast\Attribute::END_LINE, $endLine);
100106
}
101107

108+
if ($this->useIndexAttributes) {
109+
$tag->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
110+
$tag->setAttribute(Ast\Attribute::END_INDEX, $endIndex);
111+
}
112+
102113
return $tag;
103114
}
104115

105116
$startLine = $tokens->currentTokenLine();
117+
$startIndex = $tokens->currentTokenIndex();
106118
$text = $this->parseText($tokens);
107119
$endLine = $tokens->currentTokenLine();
120+
$endIndex = $tokens->currentTokenIndex();
108121

109122
if ($this->useLinesAttributes) {
110123
$text->setAttribute(Ast\Attribute::START_LINE, $startLine);
111124
$text->setAttribute(Ast\Attribute::END_LINE, $endLine);
112125
}
113126

127+
if ($this->useIndexAttributes) {
128+
$text->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
129+
$text->setAttribute(Ast\Attribute::END_INDEX, $endIndex);
130+
}
131+
114132
return $text;
115133
}
116134

@@ -155,6 +173,7 @@ public function parseTag(TokenIterator $tokens): Ast\PhpDoc\PhpDocTagNode
155173
public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\PhpDocTagValueNode
156174
{
157175
$startLine = $tokens->currentTokenLine();
176+
$startIndex = $tokens->currentTokenIndex();
158177

159178
try {
160179
$tokens->pushSavePoint();
@@ -284,12 +303,18 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
284303
}
285304

286305
$endLine = $tokens->currentTokenLine();
306+
$endIndex = $tokens->currentTokenIndex();
287307

288308
if ($this->useLinesAttributes) {
289309
$tagValue->setAttribute(Ast\Attribute::START_LINE, $startLine);
290310
$tagValue->setAttribute(Ast\Attribute::END_LINE, $endLine);
291311
}
292312

313+
if ($this->useIndexAttributes) {
314+
$tagValue->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
315+
$tagValue->setAttribute(Ast\Attribute::END_INDEX, $endIndex);
316+
}
317+
293318
return $tagValue;
294319
}
295320

src/Parser/TokenIterator.php

+6
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ public function currentTokenLine(): int
6666
}
6767

6868

69+
public function currentTokenIndex(): int
70+
{
71+
return $this->index;
72+
}
73+
74+
6975
public function isCurrentTokenValue(string $tokenValue): bool
7076
{
7177
return $this->tokens[$this->index][Lexer::VALUE_OFFSET] === $tokenValue;

src/Parser/TypeParser.php

+12-1
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ class TypeParser
2121
/** @var bool */
2222
private $useLinesAttributes;
2323

24+
/** @var bool */
25+
private $useIndexAttributes;
26+
2427
/**
25-
* @param array{lines?: bool} $usedAttributes
28+
* @param array{lines?: bool, indexes?: bool} $usedAttributes
2629
*/
2730
public function __construct(
2831
?ConstExprParser $constExprParser = null,
@@ -33,12 +36,14 @@ public function __construct(
3336
$this->constExprParser = $constExprParser;
3437
$this->quoteAwareConstExprString = $quoteAwareConstExprString;
3538
$this->useLinesAttributes = $usedAttributes['lines'] ?? false;
39+
$this->useIndexAttributes = $usedAttributes['indexes'] ?? false;
3640
}
3741

3842
/** @phpstan-impure */
3943
public function parse(TokenIterator $tokens): Ast\Type\TypeNode
4044
{
4145
$startLine = $tokens->currentTokenLine();
46+
$startIndex = $tokens->currentTokenIndex();
4247
if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) {
4348
$type = $this->parseNullable($tokens);
4449

@@ -53,12 +58,18 @@ public function parse(TokenIterator $tokens): Ast\Type\TypeNode
5358
}
5459
}
5560
$endLine = $tokens->currentTokenLine();
61+
$endIndex = $tokens->currentTokenIndex();
5662

5763
if ($this->useLinesAttributes) {
5864
$type->setAttribute(Ast\Attribute::START_LINE, $startLine);
5965
$type->setAttribute(Ast\Attribute::END_LINE, $endLine);
6066
}
6167

68+
if ($this->useIndexAttributes) {
69+
$type->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
70+
$type->setAttribute(Ast\Attribute::END_INDEX, $endIndex);
71+
}
72+
6273
return $type;
6374
}
6475

tests/PHPStan/Parser/PhpDocParserTest.php

+15-12
Original file line numberDiff line numberDiff line change
@@ -5522,7 +5522,7 @@ public function dataLines(): iterable
55225522
yield [
55235523
'/** @param Foo $a */',
55245524
[
5525-
[1, 1],
5525+
[1, 1, 1, 7],
55265526
],
55275527
];
55285528

@@ -5532,8 +5532,8 @@ public function dataLines(): iterable
55325532
* @param Bar $bar 2nd multi world description
55335533
*/',
55345534
[
5535-
[2, 2],
5536-
[3, 3],
5535+
[2, 2, 2, 16],
5536+
[3, 3, 17, 31],
55375537
],
55385538
];
55395539

@@ -5552,27 +5552,28 @@ public function dataLines(): iterable
55525552
* ))
55535553
*/',
55545554
[
5555-
[2, 2],
5556-
[3, 3],
5557-
[4, 4],
5558-
[5, 5],
5559-
[6, 6],
5560-
[7, 7],
5561-
[8, 12],
5555+
[2, 2, 2, 9],
5556+
[3, 3, 10, 13],
5557+
[4, 4, 14, 43],
5558+
[5, 5, 44, 44],
5559+
[6, 6, 45, 50],
5560+
[7, 7, 51, 51],
5561+
[8, 12, 52, 115],
55625562
],
55635563
];
55645564
}
55655565

55665566
/**
55675567
* @dataProvider dataLines
5568-
* @param list<array{int, int}> $childrenLines
5568+
* @param list<array{int, int, int, int}> $childrenLines
55695569
*/
5570-
public function testLines(string $phpDoc, array $childrenLines): void
5570+
public function testLinesAndIndexes(string $phpDoc, array $childrenLines): void
55715571
{
55725572
$tokens = new TokenIterator($this->lexer->tokenize($phpDoc));
55735573
$constExprParser = new ConstExprParser(true, true);
55745574
$usedAttributes = [
55755575
'lines' => true,
5576+
'indexes' => true,
55765577
];
55775578
$typeParser = new TypeParser($constExprParser, true, $usedAttributes);
55785579
$phpDocParser = new PhpDocParser($typeParser, $constExprParser, true, true, $usedAttributes);
@@ -5582,6 +5583,8 @@ public function testLines(string $phpDoc, array $childrenLines): void
55825583
foreach ($children as $i => $child) {
55835584
$this->assertSame($childrenLines[$i][0], $child->getAttribute(Attribute::START_LINE));
55845585
$this->assertSame($childrenLines[$i][1], $child->getAttribute(Attribute::END_LINE));
5586+
$this->assertSame($childrenLines[$i][2], $child->getAttribute(Attribute::START_INDEX));
5587+
$this->assertSame($childrenLines[$i][3], $child->getAttribute(Attribute::END_INDEX));
55855588
}
55865589
}
55875590

tests/PHPStan/Parser/TypeParserTest.php

+8-1
Original file line numberDiff line numberDiff line change
@@ -1911,6 +1911,8 @@ public function dataLines(): iterable
19111911
'int | object{foo: int}[]',
19121912
1,
19131913
1,
1914+
0,
1915+
13,
19141916
];
19151917

19161918
yield [
@@ -1920,21 +1922,26 @@ public function dataLines(): iterable
19201922
}',
19211923
1,
19221924
4,
1925+
0,
1926+
15,
19231927
];
19241928
}
19251929

19261930
/**
19271931
* @dataProvider dataLines
19281932
*/
1929-
public function testLines(string $input, int $startLine, int $endLine): void
1933+
public function testLines(string $input, int $startLine, int $endLine, int $startIndex, int $endIndex): void
19301934
{
19311935
$tokens = new TokenIterator($this->lexer->tokenize($input));
19321936
$typeParser = new TypeParser(new ConstExprParser(true, true), true, [
19331937
'lines' => true,
1938+
'indexes' => true,
19341939
]);
19351940
$typeNode = $typeParser->parse($tokens);
19361941
$this->assertSame($startLine, $typeNode->getAttribute(Attribute::START_LINE));
19371942
$this->assertSame($endLine, $typeNode->getAttribute(Attribute::END_LINE));
1943+
$this->assertSame($startIndex, $typeNode->getAttribute(Attribute::START_INDEX));
1944+
$this->assertSame($endIndex, $typeNode->getAttribute(Attribute::END_INDEX));
19381945
}
19391946

19401947
}

0 commit comments

Comments
 (0)