internal/lsp: sort rename results

We recommend that gopls integrators apply the []TextEdit responses in
reverse order to get a correct resulting document. This strategy works
when the response is already sorted. Have gopls return sorted []TextEdit
for each file.

Fixes golang/go#33123

Change-Id: Ib570881c9623695d2ae3194fa8a97b0a681a3250
Reviewed-on: https://go-review.googlesource.com/c/tools/+/186258
Run-TryBot: Suzy Mueller <suzmue@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Suzy Mueller 2019-07-15 17:02:40 -04:00
parent 9e48ab1d90
commit a0f5e6c5c2
4 changed files with 18 additions and 21 deletions

View File

@ -582,7 +582,6 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
func applyEdits(contents string, edits []source.TextEdit) string { func applyEdits(contents string, edits []source.TextEdit) string {
res := contents res := contents
sortSourceTextEdits(edits)
// Apply the edits from the end of the file forward // Apply the edits from the end of the file forward
// to preserve the offsets // to preserve the offsets
@ -596,15 +595,6 @@ func applyEdits(contents string, edits []source.TextEdit) string {
return res return res
} }
func sortSourceTextEdits(d []source.TextEdit) {
sort.Slice(d, func(i int, j int) bool {
if r := span.Compare(d[i].Span, d[j].Span); r != 0 {
return r < 0
}
return d[i].NewText < d[j].NewText
})
}
func (r *runner) Symbol(t *testing.T, data tests.Symbols) { func (r *runner) Symbol(t *testing.T, data tests.Symbols) {
for uri, expectedSymbols := range data { for uri, expectedSymbols := range data {
params := &protocol.DocumentSymbolParams{ params := &protocol.DocumentSymbolParams{

View File

@ -85,7 +85,16 @@ func (i *IdentifierInfo) Rename(ctx context.Context, newName string) (map[span.U
return nil, fmt.Errorf(r.errors) return nil, fmt.Errorf(r.errors)
} }
return r.update() changes, err := r.update()
if err != nil {
return nil, err
}
// Sort edits for each file.
for _, edits := range changes {
sortTextEdits(edits)
}
return changes, nil
} }
// Rename all references to the identifier. // Rename all references to the identifier.

View File

@ -547,7 +547,6 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
func applyEdits(contents string, edits []source.TextEdit) string { func applyEdits(contents string, edits []source.TextEdit) string {
res := contents res := contents
sortSourceTextEdits(edits)
// Apply the edits from the end of the file forward // Apply the edits from the end of the file forward
// to preserve the offsets // to preserve the offsets
@ -561,15 +560,6 @@ func applyEdits(contents string, edits []source.TextEdit) string {
return res return res
} }
func sortSourceTextEdits(d []source.TextEdit) {
sort.Slice(d, func(i int, j int) bool {
if r := span.Compare(d[i].Span, d[j].Span); r != 0 {
return r < 0
}
return d[i].NewText < d[j].NewText
})
}
func (r *runner) Symbol(t *testing.T, data tests.Symbols) { func (r *runner) Symbol(t *testing.T, data tests.Symbols) {
ctx := r.ctx ctx := r.ctx
for uri, expectedSymbols := range data { for uri, expectedSymbols := range data {

View File

@ -9,6 +9,7 @@ import (
"go/ast" "go/ast"
"go/token" "go/token"
"go/types" "go/types"
"sort"
"strings" "strings"
"golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis"
@ -318,3 +319,10 @@ func EditsToDiff(edits []TextEdit) []*diff.Op {
} }
return ops return ops
} }
func sortTextEdits(d []TextEdit) {
// Use a stable sort to maintain the order of edits inserted at the same position.
sort.SliceStable(d, func(i int, j int) bool {
return span.Compare(d[i].Span, d[j].Span) < 0
})
}