diff --git a/lib/PhpParser/Comment.php b/lib/PhpParser/Comment.php index ff949d9b35..b687c7336f 100644 --- a/lib/PhpParser/Comment.php +++ b/lib/PhpParser/Comment.php @@ -153,56 +153,53 @@ public function __toString(): string { * without trailing whitespace on the first line, but with trailing whitespace * on all subsequent lines. * - * @return mixed|string + * @return string */ public function getReformattedText() { - $text = $this->text; - $newlinePos = strpos($text, "\n"); - if (false === $newlinePos) { - // Single line comments don't need further processing - return $text; - } - if (preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\R\s+\*.*)+$)', $text)) { - // Multi line comment of the type - // - // /* - // * Some text. - // * Some more text. - // */ - // - // is handled by replacing the whitespace sequences before the * by a single space - return preg_replace('(^\s+\*)m', ' *', $this->text); - } - if (preg_match('(^/\*\*?\s*[\r\n])', $text) && preg_match('(\n(\s*)\*/$)', $text, $matches)) { - // Multi line comment of the type - // - // /* - // Some text. - // Some more text. - // */ - // - // is handled by removing the whitespace sequence on the line before the closing - // */ on all lines. So if the last line is " */", then " " is removed at the - // start of all lines. - return preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $text); - } - if (preg_match('(^/\*\*?\s*(?!\s))', $text, $matches)) { - // Multi line comment of the type - // - // /* Some text. - // Some more text. - // Indented text. - // Even more text. */ - // - // is handled by removing the difference between the shortest whitespace prefix on all - // lines and the length of the "/* " opening sequence. - $prefixLen = $this->getShortestWhitespacePrefixLen(substr($text, $newlinePos + 1)); - $removeLen = $prefixLen - strlen($matches[0]); - return preg_replace('(^\s{' . $removeLen . '})m', '', $text); + if ( + $this->startLine !== $this->endLine + || ($this->endLine === -1 && strpos($this->text, "\n") !== false) + ) { + if (preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\R\s+\*.*)+$)', $this->text)) { + // Multi line comment of the type + // + // /* + // * Some text. + // * Some more text. + // */ + // + // is handled by replacing the whitespace sequences before the * by a single space + return (string) preg_replace('(^\s+\*)m', ' *', $this->text); + } + if (preg_match('(^/\*+\s*[\r\n])', $this->text) && preg_match('(^(\s*)\*/$)m', $this->text, $matches)) { + // Multi line comment of the type + // + // /* + // Some text. + // Some more text. + // */ + // + // is handled by removing the whitespace sequence on the line before the closing + // */ on all lines. So if the last line is " */", then " " is removed at the + // start of all lines. + return (string) preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $this->text); + } + if (preg_match('(^/\*+\s*(?!\s))m', $this->text, $matches)) { + // Multi line comment of the type + // + // /* Some text. + // Some more text. + // Indented text. + // Even more text. */ + // + // is handled by removing the difference between the shortest whitespace prefix on all + // lines and the length of the "/* " opening sequence. + $prefixLen = $this->getShortestWhitespacePrefixLen(explode("\n", $this->text, 2)[1]); + $removeLen = $prefixLen - strlen($matches[0]); + return (string) preg_replace('(^\s{' . $removeLen . '})m', '', $this->text); + } } - - // No idea how to format this comment, so simply return as is - return $text; + return trim($this->text); } /** @@ -217,7 +214,7 @@ private function getShortestWhitespacePrefixLen(string $str): int { $lines = explode("\n", $str); $shortestPrefixLen = \PHP_INT_MAX; foreach ($lines as $line) { - preg_match('(^\s*)', $line, $matches); + preg_match('(^\s*)m', $line, $matches); $prefixLen = strlen($matches[0]); if ($prefixLen < $shortestPrefixLen) { $shortestPrefixLen = $prefixLen; @@ -227,14 +224,13 @@ private function getShortestWhitespacePrefixLen(string $str): int { } /** - * @return array - * @psalm-return array{nodeType:string, text:mixed, line:mixed, filePos:mixed} + * @psalm-return array{nodeType: string, text: string, line: int, filePos: int, tokenPos: int, endLine: int, + * endFilePos: int, endTokenPos: int} */ public function jsonSerialize(): array { // Technically not a node, but we make it look like one anyway - $type = $this instanceof Comment\Doc ? 'Comment_Doc' : 'Comment'; return [ - 'nodeType' => $type, + 'nodeType' => 'Comment', 'text' => $this->text, // TODO: Rename these to include "start". 'line' => $this->startLine, diff --git a/lib/PhpParser/Comment/Doc.php b/lib/PhpParser/Comment/Doc.php index bb3e9146af..3650bc75af 100644 --- a/lib/PhpParser/Comment/Doc.php +++ b/lib/PhpParser/Comment/Doc.php @@ -2,5 +2,12 @@ namespace PhpParser\Comment; -class Doc extends \PhpParser\Comment { +class Doc extends \PhpParser\Comment +{ + /** + * @inheritdoc + */ + public function jsonSerialize() : array { + return ['nodeType' => 'Comment_Doc'] + parent::jsonSerialize(); + } } diff --git a/test/PhpParser/CommentTest.php b/test/PhpParser/CommentTest.php index 49cf631ae4..1b3e5f9067 100644 --- a/test/PhpParser/CommentTest.php +++ b/test/PhpParser/CommentTest.php @@ -23,15 +23,22 @@ public function testGetters() { /** * @dataProvider provideTestReformatting */ - public function testReformatting($commentText, $reformattedText) { - $comment = new Comment($commentText); + public function testReformatting( + $commentText, + $reformattedText, + $startLine, + $startFilePos, + $startTokenPos, + $endLine + ) { + $comment = new Comment($commentText, $startLine, $startFilePos, $startTokenPos, $endLine); $this->assertSame($reformattedText, $comment->getReformattedText()); } public function provideTestReformatting() { return [ - ['// Some text', '// Some text'], - ['/* Some text */', '/* Some text */'], + ['// Some text' . "\n", '// Some text', 1, 10, 2, 1], + ['/* Some text */', '/* Some text */', 1, 10, 2, 1], [ '/** * Some text. @@ -40,7 +47,8 @@ public function provideTestReformatting() { '/** * Some text. * Some more text. - */' + */', + 1, 10, 2, 4 ], [ '/* @@ -50,7 +58,8 @@ public function provideTestReformatting() { '/* Some text. Some more text. -*/' +*/', + 1, 10, 2, 4 ], [ '/* Some text. @@ -58,7 +67,8 @@ public function provideTestReformatting() { Even more text. */', '/* Some text. More text. - Even more text. */' + Even more text. */', + 1, 10, 2, 3 ], [ '/* Some text. @@ -67,6 +77,7 @@ public function provideTestReformatting() { '/* Some text. More text. Indented text. */', + 1, 10, 2, 4 ], // invalid comment -> no reformatting [ @@ -74,6 +85,7 @@ public function provideTestReformatting() { world', 'hallo world', + 1, 10, 2, 2 ], ]; }