mirror of https://github.com/golang/go.git
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: 4c898741c0cf07cb765b759b1edf15e004fc1a0e
GitHub-Pull-Request: golang/tools#305
Reviewed-on: https://go-review.googlesource.com/c/tools/+/310311
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
Trust: Rebecca Stambler <rstambler@golang.org>
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
parent
cb5dc85ca1
commit
fe5037164a
|
|
@ -393,21 +393,45 @@ func _() {
|
|||
var bbbb1, bbbb2 b
|
||||
var _ b = bbbb
|
||||
}
|
||||
|
||||
type (
|
||||
c *d
|
||||
d *e
|
||||
e **c
|
||||
)
|
||||
|
||||
func _() {
|
||||
var (
|
||||
xxxxc c
|
||||
xxxxd d
|
||||
xxxxe e
|
||||
)
|
||||
|
||||
var _ c = xxxx
|
||||
var _ d = xxxx
|
||||
var _ e = xxxx
|
||||
}
|
||||
`
|
||||
|
||||
Run(t, files, func(t *testing.T, env *Env) {
|
||||
env.OpenFile("main.go")
|
||||
|
||||
completions := env.Completion("main.go", env.RegexpSearch("main.go", `var _ a = aaaa()`))
|
||||
diff := compareCompletionResults([]string{"aaaa1", "aaaa2"}, completions.Items)
|
||||
if diff != "" {
|
||||
t.Fatal(diff)
|
||||
tests := []struct {
|
||||
re string
|
||||
want []string
|
||||
}{
|
||||
{`var _ a = aaaa()`, []string{"aaaa1", "aaaa2"}},
|
||||
{`var _ b = bbbb()`, []string{"bbbb1", "bbbb2"}},
|
||||
{`var _ c = xxxx()`, []string{"***xxxxd", "**xxxxe", "xxxxc"}},
|
||||
{`var _ d = xxxx()`, []string{"***xxxxe", "*xxxxc", "xxxxd"}},
|
||||
{`var _ e = xxxx()`, []string{"**xxxxc", "*xxxxd", "xxxxe"}},
|
||||
}
|
||||
|
||||
completions = env.Completion("main.go", env.RegexpSearch("main.go", `var _ b = bbbb()`))
|
||||
diff = compareCompletionResults([]string{"bbbb1", "bbbb2"}, completions.Items)
|
||||
if diff != "" {
|
||||
t.Fatal(diff)
|
||||
for _, tt := range tests {
|
||||
completions := env.Completion("main.go", env.RegexpSearch("main.go", tt.re))
|
||||
diff := compareCompletionResults(tt.want, completions.Items)
|
||||
if diff != "" {
|
||||
t.Errorf("%s: %s", tt.re, diff)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,17 +222,24 @@ func FormatNode(fset *token.FileSet, n ast.Node) string {
|
|||
// Deref returns a pointer's element type, traversing as many levels as needed.
|
||||
// Otherwise it returns typ.
|
||||
//
|
||||
// It can return a pointer type if the type refers to itself (see golang/go#45510).
|
||||
// It can return a pointer type for cyclic types (see golang/go#45510).
|
||||
func Deref(typ types.Type) types.Type {
|
||||
var seen map[types.Type]struct{}
|
||||
for {
|
||||
p, ok := typ.Underlying().(*types.Pointer)
|
||||
if !ok {
|
||||
return typ
|
||||
}
|
||||
if typ == p.Elem() {
|
||||
if _, ok := seen[p.Elem()]; ok {
|
||||
return typ
|
||||
}
|
||||
|
||||
typ = p.Elem()
|
||||
|
||||
if seen == nil {
|
||||
seen = make(map[types.Type]struct{})
|
||||
}
|
||||
seen[typ] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue