diff --git a/lib/PhpParser/ParserAbstract.php b/lib/PhpParser/ParserAbstract.php index e1f28dc44f..0f20a676b7 100644 --- a/lib/PhpParser/ParserAbstract.php +++ b/lib/PhpParser/ParserAbstract.php @@ -487,12 +487,13 @@ protected function getExpectedTokens(int $state): array { */ protected function getAttributes(int $tokenStartPos, int $tokenEndPos): array { $startToken = $this->tokens[$tokenStartPos]; + $endToken = $this->tokens[$tokenEndPos]; $afterEndToken = $this->tokens[$tokenEndPos + 1]; return [ 'startLine' => $startToken->line, 'startTokenPos' => $tokenStartPos, 'startFilePos' => $startToken->pos, - 'endLine' => $afterEndToken->line, + 'endLine' => $afterEndToken->line - (substr($endToken->text, -1) === "\n" ? 1 : 0), 'endTokenPos' => $tokenEndPos, 'endFilePos' => $afterEndToken->pos - 1, ]; diff --git a/test/PhpParser/ParserTestAbstract.php b/test/PhpParser/ParserTestAbstract.php index 9f083b2eee..35085dab05 100644 --- a/test/PhpParser/ParserTestAbstract.php +++ b/test/PhpParser/ParserTestAbstract.php @@ -107,6 +107,33 @@ function test($a) { ], $var->getAttributes()); } + public function testEndLineAfterTrailingNewline(): void { + $parser = $this->getParser(new Lexer()); + foreach (["\n", "\r\n"] as $newline) { + foreach ([ + ['' . $newline . 'foo' . $newline, [[2, 2], [3, 3]]], + ['' . $newline . 'foo' . $newline . $newline, [[2, 2], [3, 4]]], + ['' . $newline . 'foo', [[2, 2], [3, 3]]], + ['' . $newline, [[2, 2]]], + ] as [$code, $expected]) { + $lines = []; + foreach ($parser->parse($code) as $node) { + $lines[] = [$node->getStartLine(), $node->getEndLine()]; + } + $this->assertSame($expected, $lines); + } + } + } + + public function testInterpolatedStringPartEndLine(): void { + $parser = $this->getParser(new Lexer()); + $stmts = $parser->parse('expr->parts[1]; + $this->assertInstanceOf(Node\InterpolatedStringPart::class, $part); + $this->assertSame(2, $part->getStartLine()); + $this->assertSame(2, $part->getEndLine()); + } + public function testInvalidToken(): void { $this->expectException(\RangeException::class); $this->expectExceptionMessage('The lexer returned an invalid token (id=999, value=foobar)'); diff --git a/test/code/parser/scalar/flexibleDocStringErrors.test b/test/code/parser/scalar/flexibleDocStringErrors.test index cb64e0fdd2..4689b26b1f 100644 --- a/test/code/parser/scalar/flexibleDocStringErrors.test +++ b/test/code/parser/scalar/flexibleDocStringErrors.test @@ -42,9 +42,9 @@ Invalid indentation - tabs and spaces cannot be mixed from 8:1 to 8:3 Invalid indentation - tabs and spaces cannot be mixed from 10:6 to 12:5 Invalid body indentation level (expecting an indentation level of at least 5) from 14:6 to 18:8 Invalid body indentation level (expecting an indentation level of at least 1) from 20:1 to 22:4 -Invalid body indentation level (expecting an indentation level of at least 2) from 25:1 to 26:0 +Invalid body indentation level (expecting an indentation level of at least 2) from 25:1 to 25:0 Invalid body indentation level (expecting an indentation level of at least 1) from 30:1 to 30:4 -Invalid body indentation level (expecting an indentation level of at least 1) from 34:1 to 35:0 +Invalid body indentation level (expecting an indentation level of at least 1) from 34:1 to 34:0 array( 0: Stmt_Expression( expr: Scalar_String(