Add end line / file position / token position to comments

This commit is contained in:
Nikita Popov 2020-02-09 16:53:46 +01:00
parent bf086d9833
commit 602af9060d
8 changed files with 138 additions and 36 deletions

View File

@ -5,9 +5,12 @@ namespace PhpParser;
class Comment implements \JsonSerializable
{
protected $text;
protected $line;
protected $filePos;
protected $tokenPos;
protected $startLine;
protected $startFilePos;
protected $startTokenPos;
protected $endLine;
protected $endFilePos;
protected $endTokenPos;
/**
* Constructs a comment node.
@ -18,12 +21,17 @@ class Comment implements \JsonSerializable
* @param int $startTokenPos Token offset the comment started on
*/
public function __construct(
string $text, int $startLine = -1, int $startFilePos = -1, int $startTokenPos = -1
string $text,
int $startLine = -1, int $startFilePos = -1, int $startTokenPos = -1,
int $endLine = -1, int $endFilePos = -1, int $endTokenPos = -1
) {
$this->text = $text;
$this->line = $startLine;
$this->filePos = $startFilePos;
$this->tokenPos = $startTokenPos;
$this->startLine = $startLine;
$this->startFilePos = $startFilePos;
$this->startTokenPos = $startTokenPos;
$this->endLine = $endLine;
$this->endFilePos = $endFilePos;
$this->endTokenPos = $endTokenPos;
}
/**
@ -38,28 +46,88 @@ class Comment implements \JsonSerializable
/**
* Gets the line number the comment started on.
*
* @return int Line number
* @return int Line number (or -1 if not available)
*/
public function getLine() : int {
return $this->line;
public function getStartLine() : int {
return $this->startLine;
}
/**
* Gets the file offset the comment started on.
*
* @return int File offset
* @return int File offset (or -1 if not available)
*/
public function getFilePos() : int {
return $this->filePos;
public function getStartFilePos() : int {
return $this->startFilePos;
}
/**
* Gets the token offset the comment started on.
*
* @return int Token offset (or -1 if not available)
*/
public function getStartTokenPos() : int {
return $this->startTokenPos;
}
/**
* Gets the line number the comment ends on.
*
* @return int Line number (or -1 if not available)
*/
public function getEndLine() : int {
return $this->endLine;
}
/**
* Gets the file offset the comment ends on.
*
* @return int File offset (or -1 if not available)
*/
public function getEndFilePos() : int {
return $this->endFilePos;
}
/**
* Gets the token offset the comment ends on.
*
* @return int Token offset (or -1 if not available)
*/
public function getEndTokenPos() : int {
return $this->endTokenPos;
}
/**
* Gets the line number the comment started on.
*
* @deprecated Use getStartLine() instead
*
* @return int Line number
*/
public function getLine() : int {
return $this->startLine;
}
/**
* Gets the file offset the comment started on.
*
* @deprecated Use getStartFilePos() instead
*
* @return int File offset
*/
public function getFilePos() : int {
return $this->startFilePos;
}
/**
* Gets the token offset the comment started on.
*
* @deprecated Use getStartTokenPos() instead
*
* @return int Token offset
*/
public function getTokenPos() : int {
return $this->tokenPos;
return $this->startTokenPos;
}
/**
@ -159,9 +227,13 @@ class Comment implements \JsonSerializable
return [
'nodeType' => $type,
'text' => $this->text,
'line' => $this->line,
'filePos' => $this->filePos,
'tokenPos' => $this->tokenPos,
// TODO: Rename these to include "start".
'line' => $this->startLine,
'filePos' => $this->startFilePos,
'tokenPos' => $this->startTokenPos,
'endLine' => $this->endLine,
'endFilePos' => $this->endFilePos,
'endTokenPos' => $this->endTokenPos,
];
}
}

View File

@ -73,7 +73,9 @@ class JsonDecoder
}
return new $className(
$value['text'], $value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1
$value['text'],
$value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1,
$value['endLine'] ?? -1, $value['endFilePos'] ?? -1, $value['endTokenPos'] ?? -1,
);
}

View File

@ -300,17 +300,23 @@ class Lexer
$this->line += substr_count($value, "\n");
$this->filePos += \strlen($value);
} else {
$origLine = $this->line;
$origFilePos = $this->filePos;
$this->line += substr_count($token[1], "\n");
$this->filePos += \strlen($token[1]);
if (\T_COMMENT === $token[0] || \T_DOC_COMMENT === $token[0]) {
if ($this->attributeCommentsUsed) {
$comment = \T_DOC_COMMENT === $token[0]
? new Comment\Doc($token[1], $this->line, $this->filePos, $this->pos)
: new Comment($token[1], $this->line, $this->filePos, $this->pos);
? new Comment\Doc($token[1],
$origLine, $origFilePos, $this->pos,
$this->line, $this->filePos - 1, $this->pos)
: new Comment($token[1],
$origLine, $origFilePos, $this->pos,
$this->line, $this->filePos - 1, $this->pos);
$startAttributes['comments'][] = $comment;
}
}
$this->line += substr_count($token[1], "\n");
$this->filePos += \strlen($token[1]);
continue;
}

View File

@ -762,7 +762,7 @@ abstract class PrettyPrinterAbstract
$comments = $arrItem->getComments();
$origComments = $origArrItem->getComments();
$commentStartPos = $origComments ? $origComments[0]->getTokenPos() : $itemStartPos;
$commentStartPos = $origComments ? $origComments[0]->getStartTokenPos() : $itemStartPos;
\assert($commentStartPos >= 0);
$commentsChanged = $comments !== $origComments;

View File

@ -4,14 +4,21 @@ namespace PhpParser;
class CommentTest extends \PHPUnit\Framework\TestCase
{
public function testGetSet() {
$comment = new Comment('/* Some comment */', 1, 10, 2);
public function testGetters() {
$comment = new Comment('/* Some comment */',
1, 10, 2, 1, 27, 2);
$this->assertSame('/* Some comment */', $comment->getText());
$this->assertSame('/* Some comment */', (string) $comment);
$this->assertSame(1, $comment->getLine());
$this->assertSame(10, $comment->getFilePos());
$this->assertSame(2, $comment->getTokenPos());
$this->assertSame(1, $comment->getStartLine());
$this->assertSame(10, $comment->getStartFilePos());
$this->assertSame(2, $comment->getStartTokenPos());
$this->assertSame(1, $comment->getEndLine());
$this->assertSame(27, $comment->getEndFilePos());
$this->assertSame(2, $comment->getEndTokenPos());
}
/**

View File

@ -103,7 +103,9 @@ class LexerTest extends \PHPUnit\Framework\TestCase
[
'startLine' => 3,
'comments' => [
new Comment\Doc('/** doc' . "\n" . 'comment */', 2, 14, 5),
new Comment\Doc('/** doc' . "\n" . 'comment */',
2, 14, 5,
3, 31, 5),
]
],
['endLine' => 3]
@ -120,10 +122,14 @@ class LexerTest extends \PHPUnit\Framework\TestCase
[
'startLine' => 2,
'comments' => [
new Comment('/* comment */', 1, 6, 1),
new Comment('// comment' . "\n", 1, 20, 3),
new Comment\Doc('/** docComment 1 */', 2, 31, 4),
new Comment\Doc('/** docComment 2 */', 2, 50, 5),
new Comment('/* comment */',
1, 6, 1, 1, 18, 1),
new Comment('// comment' . "\n",
1, 20, 3, 2, 30, 3),
new Comment\Doc('/** docComment 1 */',
2, 31, 4, 2, 49, 4),
new Comment\Doc('/** docComment 2 */',
2, 50, 5, 2, 68, 5),
],
],
['endLine' => 2]

View File

@ -301,14 +301,20 @@ PHP;
"text": "\/\/ comment\n",
"line": 2,
"filePos": 6,
"tokenPos": 1
"tokenPos": 1,
"endLine": 3,
"endFilePos": 16,
"endTokenPos": 1
},
{
"nodeType": "Comment_Doc",
"text": "\/** doc comment *\/",
"line": 3,
"filePos": 17,
"tokenPos": 2
"tokenPos": 2,
"endLine": 3,
"endFilePos": 34,
"endTokenPos": 2
}
],
"endLine": 6

View File

@ -60,7 +60,8 @@ EOC;
$this->assertInstanceOf(Stmt\Function_::class, $fn);
$this->assertEquals([
'comments' => [
new Comment\Doc('/** Doc comment */', 2, 6, 1),
new Comment\Doc('/** Doc comment */',
2, 6, 1, 2, 23, 1),
],
'startLine' => 3,
'endLine' => 7,
@ -82,8 +83,10 @@ EOC;
$this->assertInstanceOf(Stmt\Echo_::class, $echo);
$this->assertEquals([
'comments' => [
new Comment("// Line\n", 4, 49, 12),
new Comment("// Comments\n", 5, 61, 14),
new Comment("// Line\n",
4, 49, 12, 5, 56, 12),
new Comment("// Comments\n",
5, 61, 14, 6, 72, 14),
],
'startLine' => 6,
'endLine' => 6,