Skip to content

Commit 2f04713

Browse files
committed
gopls: fix out of bounds bug in extract
There was a bug where the code would try to access an out of bounds index when trimming extra space and comments in extract. This change also adds a regtest for extract. Fixes golang/go#55271 Change-Id: I7da716a6a68a9678011abf15def47acdea0b33fe Reviewed-on: https://go-review.googlesource.com/c/tools/+/432135 Run-TryBot: Suzy Mueller <suzmue@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> gopls-CI: kokoro <noreply+kokoro@google.com> Reviewed-by: Robert Findley <rfindley@google.com>
1 parent 16b9742 commit 2f04713

File tree

2 files changed

+76
-2
lines changed

2 files changed

+76
-2
lines changed

gopls/internal/lsp/source/extract.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ func adjustRangeForCommentsAndWhiteSpace(rng span.Range, tok *token.File, conten
676676
prevStart = start
677677
// If start is within a comment, move start to the end
678678
// of the comment group.
679-
if file.Comments[startComment].Pos() <= start && start < file.Comments[startComment].End() {
679+
if startComment < len(file.Comments) && file.Comments[startComment].Pos() <= start && start < file.Comments[startComment].End() {
680680
start = file.Comments[startComment].End()
681681
startComment++
682682
}
@@ -697,11 +697,16 @@ func adjustRangeForCommentsAndWhiteSpace(rng span.Range, tok *token.File, conten
697697
// Find the index for the first comment that ends after the range end.
698698
return file.Comments[i].End() >= rng.End
699699
})
700+
// Search will return n if not found, so we need to adjust if there are no
701+
// comments that would match.
702+
if endComment == len(file.Comments) {
703+
endComment = -1
704+
}
700705
for prevEnd != end {
701706
prevEnd = end
702707
// If end is within a comment, move end to the start
703708
// of the comment group.
704-
if file.Comments[endComment].Pos() < end && end <= file.Comments[endComment].End() {
709+
if endComment >= 0 && file.Comments[endComment].Pos() < end && end <= file.Comments[endComment].End() {
705710
end = file.Comments[endComment].Pos()
706711
endComment--
707712
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
package misc
5+
6+
import (
7+
"testing"
8+
9+
. "golang.org/x/tools/gopls/internal/lsp/regtest"
10+
"golang.org/x/tools/gopls/internal/lsp/tests/compare"
11+
12+
"golang.org/x/tools/gopls/internal/lsp/protocol"
13+
)
14+
15+
func TestExtractFunction(t *testing.T) {
16+
const files = `
17+
-- go.mod --
18+
module mod.com
19+
20+
go 1.12
21+
-- main.go --
22+
package main
23+
24+
func Foo() int {
25+
a := 5
26+
return a
27+
}
28+
`
29+
Run(t, files, func(t *testing.T, env *Env) {
30+
env.OpenFile("main.go")
31+
32+
start := env.RegexpSearch("main.go", "a := 5").ToProtocolPosition()
33+
end := env.RegexpSearch("main.go", "return a").ToProtocolPosition()
34+
35+
actions, err := env.Editor.CodeAction(env.Ctx, "main.go", &protocol.Range{Start: start, End: end}, nil)
36+
if err != nil {
37+
t.Fatal(err)
38+
}
39+
40+
// Find the extract function code action.
41+
var extractFunc *protocol.CodeAction
42+
for _, action := range actions {
43+
if action.Kind == protocol.RefactorExtract && action.Title == "Extract function" {
44+
extractFunc = &action
45+
break
46+
}
47+
}
48+
if extractFunc == nil {
49+
t.Fatal("could not find extract function action")
50+
}
51+
52+
env.ApplyCodeAction(*extractFunc)
53+
want := `package main
54+
55+
func Foo() int {
56+
a := newFunction()
57+
return a
58+
}
59+
60+
func newFunction() int {
61+
a := 5
62+
return a
63+
}
64+
`
65+
if got := env.Editor.BufferText("main.go"); got != want {
66+
t.Fatalf("TestFillStruct failed:\n%s", compare.Text(want, got))
67+
}
68+
})
69+
}

0 commit comments

Comments
 (0)