internal/lsp: send "extract variable" edits ordered

Edits from the code action "extract variable" wasn't ordered.

The reason this wasn't picked up by the tests (and in fact, the test
failed when edits were in order) is that multiple edits to the same file
was sent as multiple "DocumentChanges" with a single edit each.

By updating ApplyFix() to consolidate edits to the same file into a
single DocumentChange with multiple edits, we avoid the undefined(?)
behaviour of how clients should handle multiple DocumentChanges to the
same file & version.

Fixes golang/go#47486

Change-Id: Ie4a4718ceb40693b84c014f66c8fc0d221843d88
Reviewed-on: https://go-review.googlesource.com/c/tools/+/338869
Trust: Pontus Leitzler <leitzler@gmail.com>
Run-TryBot: Pontus Leitzler <leitzler@gmail.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/source/extract.go b/internal/lsp/source/extract.go
index 4f0de59..8f7010a 100644
--- a/internal/lsp/source/extract.go
+++ b/internal/lsp/source/extract.go
@@ -80,15 +80,15 @@
 	return &analysis.SuggestedFix{
 		TextEdits: []analysis.TextEdit{
 			{
-				Pos:     rng.Start,
-				End:     rng.End,
-				NewText: []byte(lhs),
-			},
-			{
 				Pos:     insertBeforeStmt.Pos(),
 				End:     insertBeforeStmt.Pos(),
 				NewText: []byte(assignment),
 			},
+			{
+				Pos:     rng.Start,
+				End:     rng.End,
+				NewText: []byte(lhs),
+			},
 		},
 	}, nil
 }
diff --git a/internal/lsp/source/fix.go b/internal/lsp/source/fix.go
index 3308aee..4cf270f 100644
--- a/internal/lsp/source/fix.go
+++ b/internal/lsp/source/fix.go
@@ -71,7 +71,7 @@
 		return nil, nil
 	}
 
-	var edits []protocol.TextDocumentEdit
+	var edits []protocol.TextEdit
 	for _, edit := range suggestion.TextEdits {
 		rng := span.NewRange(fset, edit.Pos, edit.End)
 		spn, err := rng.Span()
@@ -82,22 +82,20 @@
 		if err != nil {
 			return nil, err
 		}
-		edits = append(edits, protocol.TextDocumentEdit{
-			TextDocument: protocol.OptionalVersionedTextDocumentIdentifier{
-				Version: fh.Version(),
-				TextDocumentIdentifier: protocol.TextDocumentIdentifier{
-					URI: protocol.URIFromSpanURI(fh.URI()),
-				},
-			},
-			Edits: []protocol.TextEdit{
-				{
-					Range:   clRng,
-					NewText: string(edit.NewText),
-				},
-			},
+		edits = append(edits, protocol.TextEdit{
+			Range:   clRng,
+			NewText: string(edit.NewText),
 		})
 	}
-	return edits, nil
+	return []protocol.TextDocumentEdit{{
+		TextDocument: protocol.OptionalVersionedTextDocumentIdentifier{
+			Version: fh.Version(),
+			TextDocumentIdentifier: protocol.TextDocumentIdentifier{
+				URI: protocol.URIFromSpanURI(fh.URI()),
+			},
+		},
+		Edits: edits,
+	}}, nil
 }
 
 // getAllSuggestedFixInputs is a helper function to collect all possible needed