From 6ecd1830a69c46f64fc75a03d0af61aa086c9523 Mon Sep 17 00:00:00 2001 From: Anton Fedonyuk Date: Sun, 7 Aug 2022 14:38:25 +0300 Subject: [PATCH 01/11] Normalize comment classes --- lib/PhpParser/Comment.php | 31 ++++++++++++++----------------- lib/PhpParser/Comment/Doc.php | 6 ++++++ 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/lib/PhpParser/Comment.php b/lib/PhpParser/Comment.php index 2c604c2f91..806d151f75 100644 --- a/lib/PhpParser/Comment.php +++ b/lib/PhpParser/Comment.php @@ -147,16 +147,14 @@ public function __toString() : string { * without trailing whitespace on the first line, but with trailing whitespace * on all subsequent lines. * - * @return mixed|string + * @return string|null */ public function getReformattedText() { - $text = trim($this->text); - $newlinePos = strpos($text, "\n"); - if (false === $newlinePos) { + if (0 < ($this->endLine - $this->startLine)) { // Single line comments don't need further processing - return $text; + return $this->text; } - if (preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\R\s+\*.*)+$)', $text)) { + if (preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\R\s+\*.*)+$)', $this->text)) { // Multi line comment of the type // // /* @@ -167,7 +165,7 @@ public function getReformattedText() { // 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)) { + if (preg_match('(^/\*\*?\s*[\r\n])', $this->text) && preg_match('(\n(\s*)\*/$)', $this->text, $matches)) { // Multi line comment of the type // // /* @@ -178,9 +176,9 @@ public function getReformattedText() { // 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); + return preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $this->text); } - if (preg_match('(^/\*\*?\s*(?!\s))', $text, $matches)) { + if (preg_match('(^/\*\*?\s*(?!\s))', $this->text, $matches)) { // Multi line comment of the type // // /* Some text. @@ -190,13 +188,13 @@ public function getReformattedText() { // // 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)); + $prefixLen = $this->getShortestWhitespacePrefixLen(explode("\n", $this->text, 2)[1]); $removeLen = $prefixLen - strlen($matches[0]); - return preg_replace('(^\s{' . $removeLen . '})m', '', $text); + return preg_replace('(^\s{' . $removeLen . '})m', '', $this->text); } // No idea how to format this comment, so simply return as is - return $text; + return $this->text; } /** @@ -209,7 +207,7 @@ public function getReformattedText() { */ private function getShortestWhitespacePrefixLen(string $str) : int { $lines = explode("\n", $str); - $shortestPrefixLen = \INF; + $shortestPrefixLen = 0; foreach ($lines as $line) { preg_match('(^\s*)', $line, $matches); $prefixLen = strlen($matches[0]); @@ -221,14 +219,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 a9db6128f4..3650bc75af 100644 --- a/lib/PhpParser/Comment/Doc.php +++ b/lib/PhpParser/Comment/Doc.php @@ -4,4 +4,10 @@ class Doc extends \PhpParser\Comment { + /** + * @inheritdoc + */ + public function jsonSerialize() : array { + return ['nodeType' => 'Comment_Doc'] + parent::jsonSerialize(); + } } From f52ab931bafd2581367d175c3eeb977024085dde Mon Sep 17 00:00:00 2001 From: Anton Date: Sun, 7 Aug 2022 17:52:22 +0300 Subject: [PATCH 02/11] Replace INF to PHP_INT_MAX --- lib/PhpParser/Comment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/PhpParser/Comment.php b/lib/PhpParser/Comment.php index 6802e378c6..3617f2ee49 100644 --- a/lib/PhpParser/Comment.php +++ b/lib/PhpParser/Comment.php @@ -207,7 +207,7 @@ public function getReformattedText() { */ private function getShortestWhitespacePrefixLen(string $str) : int { $lines = explode("\n", $str); - $shortestPrefixLen = 0; + $shortestPrefixLen = \PHP_INT_MAX; foreach ($lines as $line) { preg_match('(^\s*)', $line, $matches); $prefixLen = strlen($matches[0]); From 57bd07de1c8c092b65cbfbbb20c30caeb22d7160 Mon Sep 17 00:00:00 2001 From: Anton Date: Sun, 7 Aug 2022 17:59:48 +0300 Subject: [PATCH 03/11] Normalize result of Comment::getReformattedText() --- lib/PhpParser/Comment.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/PhpParser/Comment.php b/lib/PhpParser/Comment.php index 3617f2ee49..92ac91799d 100644 --- a/lib/PhpParser/Comment.php +++ b/lib/PhpParser/Comment.php @@ -147,7 +147,7 @@ public function __toString() : string { * without trailing whitespace on the first line, but with trailing whitespace * on all subsequent lines. * - * @return string|null + * @return string */ public function getReformattedText() { if ($this->startLine === $this->endLine) { @@ -163,7 +163,7 @@ public function getReformattedText() { // */ // // is handled by replacing the whitespace sequences before the * by a single space - return preg_replace('(^\s+\*)m', ' *', $this->text); + return (string) preg_replace('(^\s+\*)m', ' *', $this->text); } if (preg_match('(^/\*\*?\s*[\r\n])', $this->text) && preg_match('(\n(\s*)\*/$)', $this->text, $matches)) { // Multi line comment of the type @@ -176,7 +176,7 @@ public function getReformattedText() { // 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', '', $this->text); + return (string) preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $this->text); } if (preg_match('(^/\*\*?\s*(?!\s))', $this->text, $matches)) { // Multi line comment of the type @@ -190,7 +190,7 @@ public function getReformattedText() { // lines and the length of the "/* " opening sequence. $prefixLen = $this->getShortestWhitespacePrefixLen(explode("\n", $this->text, 2)[1]); $removeLen = $prefixLen - strlen($matches[0]); - return preg_replace('(^\s{' . $removeLen . '})m', '', $this->text); + return (string) preg_replace('(^\s{' . $removeLen . '})m', '', $this->text); } // No idea how to format this comment, so simply return as is From 0c9765adf22141b82cfe3a618971126aabf2c8df Mon Sep 17 00:00:00 2001 From: Anton Date: Sun, 7 Aug 2022 22:19:56 +0300 Subject: [PATCH 04/11] Update CommentTest.php --- test/PhpParser/CommentTest.php | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/test/PhpParser/CommentTest.php b/test/PhpParser/CommentTest.php index 23174c7e08..8318175cce 100644 --- a/test/PhpParser/CommentTest.php +++ b/test/PhpParser/CommentTest.php @@ -24,15 +24,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. @@ -41,7 +48,8 @@ public function provideTestReformatting() { '/** * Some text. * Some more text. - */' + */', + 1, 10, 2, 4 ], [ '/* @@ -51,7 +59,8 @@ public function provideTestReformatting() { '/* Some text. Some more text. -*/' +*/', + 1, 10, 2, 4 ], [ '/* Some text. @@ -59,7 +68,8 @@ public function provideTestReformatting() { Even more text. */', '/* Some text. More text. - Even more text. */' + Even more text. */', + 1, 10, 2, 3 ], [ '/* Some text. @@ -68,6 +78,7 @@ public function provideTestReformatting() { '/* Some text. More text. Indented text. */', + 1, 10, 2, 4 ], // invalid comment -> no reformatting [ @@ -75,6 +86,7 @@ public function provideTestReformatting() { world', 'hallo world', + 1, 10, 2, 2 ], ]; } From 9e7f866540a8f56a28fd804c2808447108b1be06 Mon Sep 17 00:00:00 2001 From: Anton Date: Sun, 7 Aug 2022 22:21:01 +0300 Subject: [PATCH 05/11] Update Comment.php --- lib/PhpParser/Comment.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/PhpParser/Comment.php b/lib/PhpParser/Comment.php index 92ac91799d..02b7ee780b 100644 --- a/lib/PhpParser/Comment.php +++ b/lib/PhpParser/Comment.php @@ -150,9 +150,9 @@ public function __toString() : string { * @return string */ public function getReformattedText() { - if ($this->startLine === $this->endLine) { + if ($this->startLine === $this->endLine && $this->endLine !== -1) { // Single line comments don't need further processing - return $this->text; + return trim($this->text); } if (preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\R\s+\*.*)+$)', $this->text)) { // Multi line comment of the type @@ -165,7 +165,7 @@ public function getReformattedText() { // 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('(\n(\s*)\*/$)', $this->text, $matches)) { + if (preg_match('(^/\*+\s*[\r\n])', $this->text) && preg_match('(^(\s*)\*/$)m', $this->text, $matches)) { // Multi line comment of the type // // /* @@ -178,7 +178,7 @@ public function getReformattedText() { // start of all lines. return (string) preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $this->text); } - if (preg_match('(^/\*\*?\s*(?!\s))', $this->text, $matches)) { + if (preg_match('(^/\*+\s*(?!\s))m', $this->text, $matches)) { // Multi line comment of the type // // /* Some text. @@ -209,7 +209,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; From 18ab5ab63da86d59dfcc08b3bcfe2de15181e4c5 Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 9 Aug 2022 16:23:33 +0300 Subject: [PATCH 06/11] Update Comment.php --- lib/PhpParser/Comment.php | 81 +++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/lib/PhpParser/Comment.php b/lib/PhpParser/Comment.php index 02b7ee780b..1d2a7c20fb 100644 --- a/lib/PhpParser/Comment.php +++ b/lib/PhpParser/Comment.php @@ -150,50 +150,47 @@ public function __toString() : string { * @return string */ public function getReformattedText() { - if ($this->startLine === $this->endLine && $this->endLine !== -1) { - // Single line comments don't need further processing - return trim($this->text); - } - 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); + if ($this->startLine !== $this->endLine || $this->startLine !== -1) { + if (preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\R\s+\*.*)+$)m', $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])m', $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 $this->text; } From 3dd87753792e061b57a3ba2a81d34758779e3dbd Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 9 Aug 2022 16:30:18 +0300 Subject: [PATCH 07/11] Update Comment.php --- lib/PhpParser/Comment.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/PhpParser/Comment.php b/lib/PhpParser/Comment.php index 1d2a7c20fb..3a174a01f2 100644 --- a/lib/PhpParser/Comment.php +++ b/lib/PhpParser/Comment.php @@ -150,7 +150,7 @@ public function __toString() : string { * @return string */ public function getReformattedText() { - if ($this->startLine !== $this->endLine || $this->startLine !== -1) { + if ($this->startLine !== $this->endLine) { if (preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\R\s+\*.*)+$)m', $this->text)) { // Multi line comment of the type // @@ -191,7 +191,7 @@ public function getReformattedText() { } } - return $this->text; + return trim($this->text); } /** From 2201073a5466d9febe62c1e5fbc5aa1f6f93e814 Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 9 Aug 2022 16:34:48 +0300 Subject: [PATCH 08/11] Update Comment.php --- lib/PhpParser/Comment.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/PhpParser/Comment.php b/lib/PhpParser/Comment.php index 3a174a01f2..fcdbb4ff05 100644 --- a/lib/PhpParser/Comment.php +++ b/lib/PhpParser/Comment.php @@ -151,7 +151,7 @@ public function __toString() : string { */ public function getReformattedText() { if ($this->startLine !== $this->endLine) { - if (preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\R\s+\*.*)+$)m', $this->text)) { + if (preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\R\s+\*.*)+$)', $this->text)) { // Multi line comment of the type // // /* @@ -162,7 +162,7 @@ public function getReformattedText() { // 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])m', $this->text) && preg_match('(^(\s*)\*/$)m', $this->text, $matches)) { + if (preg_match('(^/\*+\s*[\r\n])', $this->text) && preg_match('(^(\s*)\*/$)', $this->text, $matches)) { // Multi line comment of the type // // /* @@ -175,7 +175,7 @@ public function getReformattedText() { // start of all lines. return (string) preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $this->text); } - if (preg_match('(^/\*+\s*(?!\s))m', $this->text, $matches)) { + if (preg_match('(^/\*+\s*(?!\s))', $this->text, $matches)) { // Multi line comment of the type // // /* Some text. From 1e18d16f196c5dd66de772c94411330123e25611 Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 9 Aug 2022 16:37:24 +0300 Subject: [PATCH 09/11] Update Comment.php --- lib/PhpParser/Comment.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/PhpParser/Comment.php b/lib/PhpParser/Comment.php index fcdbb4ff05..0b79693bb2 100644 --- a/lib/PhpParser/Comment.php +++ b/lib/PhpParser/Comment.php @@ -162,7 +162,7 @@ public function getReformattedText() { // 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*)\*/$)', $this->text, $matches)) { + if (preg_match('(^/\*+\s*[\r\n])', $this->text) && preg_match('(^(\s*)\*/$)m', $this->text, $matches)) { // Multi line comment of the type // // /* @@ -175,7 +175,7 @@ public function getReformattedText() { // start of all lines. return (string) preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $this->text); } - if (preg_match('(^/\*+\s*(?!\s))', $this->text, $matches)) { + if (preg_match('(^/\*+\s*(?!\s))m', $this->text, $matches)) { // Multi line comment of the type // // /* Some text. From f8ebbcc3a34d2534490d33516483334fe351d65f Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 9 Aug 2022 16:55:33 +0300 Subject: [PATCH 10/11] Update Comment.php --- lib/PhpParser/Comment.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/PhpParser/Comment.php b/lib/PhpParser/Comment.php index 0b79693bb2..957fd96137 100644 --- a/lib/PhpParser/Comment.php +++ b/lib/PhpParser/Comment.php @@ -190,7 +190,6 @@ public function getReformattedText() { return (string) preg_replace('(^\s{' . $removeLen . '})m', '', $this->text); } } - return trim($this->text); } From 936b5d255f81e3b00af57c929bf9d2c9c6ffbe62 Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 14 Sep 2022 01:28:42 +0300 Subject: [PATCH 11/11] Update Comment.php --- lib/PhpParser/Comment.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/PhpParser/Comment.php b/lib/PhpParser/Comment.php index 1008c419d3..b687c7336f 100644 --- a/lib/PhpParser/Comment.php +++ b/lib/PhpParser/Comment.php @@ -156,7 +156,10 @@ public function __toString(): string { * @return string */ public function getReformattedText() { - if ($this->startLine !== $this->endLine) { + 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 //