Skip to content

Commit fe50371

Browse files
ShoshinNikitastamblerre
authored andcommitted
internal/lsp/source: fix Deref function for cyclic types
The previous fix (d1362d7) is not sufficient for all cyclic types. This change updates Deref function to support more complex cases. We use a map with underlying types to detect cycles. Fixes golang/go#45510 Change-Id: I28f655a9c1d4f363cb7ae3f47db3e8567fe6e80a GitHub-Last-Rev: 4c89874 GitHub-Pull-Request: #305 Reviewed-on: https://go-review.googlesource.com/c/tools/+/310311 Reviewed-by: Rebecca Stambler <[email protected]> Trust: Rebecca Stambler <[email protected]> Trust: Robert Findley <[email protected]> Run-TryBot: Rebecca Stambler <[email protected]> gopls-CI: kokoro <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent cb5dc85 commit fe50371

File tree

2 files changed

+42
-11
lines changed

2 files changed

+42
-11
lines changed

gopls/internal/regtest/completion/completion_test.go

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -393,21 +393,45 @@ func _() {
393393
var bbbb1, bbbb2 b
394394
var _ b = bbbb
395395
}
396+
397+
type (
398+
c *d
399+
d *e
400+
e **c
401+
)
402+
403+
func _() {
404+
var (
405+
xxxxc c
406+
xxxxd d
407+
xxxxe e
408+
)
409+
410+
var _ c = xxxx
411+
var _ d = xxxx
412+
var _ e = xxxx
413+
}
396414
`
397415

398416
Run(t, files, func(t *testing.T, env *Env) {
399417
env.OpenFile("main.go")
400418

401-
completions := env.Completion("main.go", env.RegexpSearch("main.go", `var _ a = aaaa()`))
402-
diff := compareCompletionResults([]string{"aaaa1", "aaaa2"}, completions.Items)
403-
if diff != "" {
404-
t.Fatal(diff)
419+
tests := []struct {
420+
re string
421+
want []string
422+
}{
423+
{`var _ a = aaaa()`, []string{"aaaa1", "aaaa2"}},
424+
{`var _ b = bbbb()`, []string{"bbbb1", "bbbb2"}},
425+
{`var _ c = xxxx()`, []string{"***xxxxd", "**xxxxe", "xxxxc"}},
426+
{`var _ d = xxxx()`, []string{"***xxxxe", "*xxxxc", "xxxxd"}},
427+
{`var _ e = xxxx()`, []string{"**xxxxc", "*xxxxd", "xxxxe"}},
405428
}
406-
407-
completions = env.Completion("main.go", env.RegexpSearch("main.go", `var _ b = bbbb()`))
408-
diff = compareCompletionResults([]string{"bbbb1", "bbbb2"}, completions.Items)
409-
if diff != "" {
410-
t.Fatal(diff)
429+
for _, tt := range tests {
430+
completions := env.Completion("main.go", env.RegexpSearch("main.go", tt.re))
431+
diff := compareCompletionResults(tt.want, completions.Items)
432+
if diff != "" {
433+
t.Errorf("%s: %s", tt.re, diff)
434+
}
411435
}
412436
})
413437
}

internal/lsp/source/util.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,17 +222,24 @@ func FormatNode(fset *token.FileSet, n ast.Node) string {
222222
// Deref returns a pointer's element type, traversing as many levels as needed.
223223
// Otherwise it returns typ.
224224
//
225-
// It can return a pointer type if the type refers to itself (see golang/go#45510).
225+
// It can return a pointer type for cyclic types (see golang/go#45510).
226226
func Deref(typ types.Type) types.Type {
227+
var seen map[types.Type]struct{}
227228
for {
228229
p, ok := typ.Underlying().(*types.Pointer)
229230
if !ok {
230231
return typ
231232
}
232-
if typ == p.Elem() {
233+
if _, ok := seen[p.Elem()]; ok {
233234
return typ
234235
}
236+
235237
typ = p.Elem()
238+
239+
if seen == nil {
240+
seen = make(map[types.Type]struct{})
241+
}
242+
seen[typ] = struct{}{}
236243
}
237244
}
238245

0 commit comments

Comments
 (0)