internal/lsp: reproduce and fix golang/go#41057

Fix the comment end position for multi-line comments to account for the
closing "*/".

Fixes golang/go#41057

Change-Id: I5dd3886a81d274514e78f47ac2e7194fd9cceb06
Reviewed-on: https://go-review.googlesource.com/c/tools/+/252457
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/internal/lsp/regtest/formatting_test.go b/internal/lsp/regtest/formatting_test.go
index 792797b..f0d3afa 100644
--- a/internal/lsp/regtest/formatting_test.go
+++ b/internal/lsp/regtest/formatting_test.go
@@ -1,6 +1,7 @@
 package regtest
 
 import (
+	"strings"
 	"testing"
 
 	"golang.org/x/tools/internal/lsp/tests"
@@ -159,3 +160,24 @@
 		}
 	})
 }
+
+// Reproduce golang/go#41057.
+func TestCRLF(t *testing.T) {
+	runner.Run(t, "-- main.go --", func(t *testing.T, env *Env) {
+		want := `package main
+
+/*
+Hi description
+*/
+func Hi() {
+}
+`
+		crlf := strings.ReplaceAll(want, "\n", "\r\n")
+		env.OpenFileWithContent("main.go", crlf)
+		env.SaveBuffer("main.go")
+		got := env.Editor.BufferText("main.go")
+		if want != got {
+			t.Errorf("unexpected content after save:\n%s", tests.Diff(want, got))
+		}
+	})
+}
diff --git a/internal/lsp/source/format.go b/internal/lsp/source/format.go
index 1b4cb42..5114d50 100644
--- a/internal/lsp/source/format.go
+++ b/internal/lsp/source/format.go
@@ -227,7 +227,14 @@
 	}
 	for _, c := range f.Comments {
 		if end := tok.Offset(c.End()); end > importEnd {
-			importEnd = maybeAdjustToLineEnd(c.End(), true)
+			// Work-around golang/go#41197: For multi-line comments add +2 to
+			// the offset. The end position does not account for the */ at the
+			// end.
+			endLine := tok.Position(c.End()).Line
+			if end+2 <= tok.Size() && tok.Position(tok.Pos(end+2)).Line == endLine {
+				end += 2
+			}
+			importEnd = maybeAdjustToLineEnd(tok.Pos(end), true)
 		}
 	}
 	if importEnd > len(src) {
diff --git a/internal/lsp/source/format_test.go b/internal/lsp/source/format_test.go
index 5030806..e0dfe15 100644
--- a/internal/lsp/source/format_test.go
+++ b/internal/lsp/source/format_test.go
@@ -2,6 +2,7 @@
 
 import (
 	"fmt"
+	"strings"
 	"testing"
 
 	"golang.org/x/tools/internal/lsp/diff"
@@ -37,6 +38,34 @@
 	}
 }
 
+func TestCRLFFile(t *testing.T) {
+	for i, tt := range []struct {
+		input, want string
+	}{
+		{
+			input: `package main
+
+/*
+Hi description
+*/
+func Hi() {
+}
+`,
+			want: `package main
+
+/*
+Hi description
+*/`,
+		},
+	} {
+		got := importPrefix([]byte(strings.ReplaceAll(tt.input, "\n", "\r\n")))
+		want := strings.ReplaceAll(tt.want, "\n", "\r\n")
+		if got != want {
+			t.Errorf("%d: failed for %q:\n%s", i, tt.input, diffStr(want, got))
+		}
+	}
+}
+
 func diffStr(want, got string) string {
 	if want == got {
 		return ""