From d1362d7aca54cd4181c1c6bf3f8e6e855bed960d Mon Sep 17 00:00:00 2001 From: Shoshin Nikita Date: Wed, 14 Apr 2021 17:37:59 +0000 Subject: [PATCH] internal/lsp/source: fix an infinite loop in Deref function Return a pointer type if the type refers to itself (for example, type a *a). Fixes golang/go#45510 Change-Id: Ifaf9c0fe9df8a1cab300479394a7127dfb820a88 GitHub-Last-Rev: 009802341673cfd24c04d6a115a6082029dfa2a2 GitHub-Pull-Request: golang/tools#302 Reviewed-on: https://go-review.googlesource.com/c/tools/+/310050 Trust: Rebecca Stambler Trust: Heschi Kreinick Run-TryBot: Rebecca Stambler gopls-CI: kokoro TryBot-Result: Go Bot Reviewed-by: Rebecca Stambler --- .../regtest/completion/completion_test.go | 37 +++++++++++++++++++ internal/lsp/source/util.go | 5 +++ 2 files changed, 42 insertions(+) diff --git a/gopls/internal/regtest/completion/completion_test.go b/gopls/internal/regtest/completion/completion_test.go index 6e89c4f5c2..82f0757772 100644 --- a/gopls/internal/regtest/completion/completion_test.go +++ b/gopls/internal/regtest/completion/completion_test.go @@ -374,3 +374,40 @@ type S struct { } }) } + +func TestCompletion_Issue45510(t *testing.T) { + const files = ` +-- go.mod -- +module mod.com + +go 1.12 +-- main.go -- +package main + +func _() { + type a *a + var aaaa1, aaaa2 a + var _ a = aaaa + + type b a + var bbbb1, bbbb2 b + var _ b = bbbb +} +` + + 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) + } + + completions = env.Completion("main.go", env.RegexpSearch("main.go", `var _ b = bbbb()`)) + diff = compareCompletionResults([]string{"bbbb1", "bbbb2"}, completions.Items) + if diff != "" { + t.Fatal(diff) + } + }) +} diff --git a/internal/lsp/source/util.go b/internal/lsp/source/util.go index 690a781e04..d242c34dd5 100644 --- a/internal/lsp/source/util.go +++ b/internal/lsp/source/util.go @@ -221,12 +221,17 @@ 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). func Deref(typ types.Type) types.Type { for { p, ok := typ.Underlying().(*types.Pointer) if !ok { return typ } + if typ == p.Elem() { + return typ + } typ = p.Elem() } }