internal/lsp/source: correct workspace symbol logic for unpacking receivers

The logic to extract the receiver identifier from a func decl was
incorrect, accepting only the common T and *T syntaxes, and panicking on
*(T).

Fix this by copying the logic from go/types.

Fixes golang/go#44806

Change-Id: I1c87ab21ac04e484972bc4161180ca1112df3c73
Reviewed-on: https://go-review.googlesource.com/c/tools/+/298852
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.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/workspace_symbol.go b/internal/lsp/source/workspace_symbol.go
index fb40e7d..c0aabf2 100644
--- a/internal/lsp/source/workspace_symbol.go
+++ b/internal/lsp/source/workspace_symbol.go
@@ -351,14 +351,9 @@
 		case *ast.FuncDecl:
 			kind := protocol.Function
 			var recv *ast.Ident
-			if decl.Recv != nil {
+			if decl.Recv.NumFields() > 0 {
 				kind = protocol.Method
-				switch typ := decl.Recv.List[0].Type.(type) {
-				case *ast.StarExpr:
-					recv = typ.X.(*ast.Ident)
-				case *ast.Ident:
-					recv = typ
-				}
+				recv = unpackRecv(decl.Recv.List[0].Type)
 			}
 			if recv != nil {
 				sc.match(decl.Name.Name, kind, decl.Name, recv)
@@ -385,6 +380,25 @@
 	}
 }
 
+func unpackRecv(rtyp ast.Expr) *ast.Ident {
+	// Extract the receiver identifier. Lifted from go/types/resolver.go
+L:
+	for {
+		switch t := rtyp.(type) {
+		case *ast.ParenExpr:
+			rtyp = t.X
+		case *ast.StarExpr:
+			rtyp = t.X
+		default:
+			break L
+		}
+	}
+	if name, _ := rtyp.(*ast.Ident); name != nil {
+		return name
+	}
+	return nil
+}
+
 // walkType processes symbols related to a type expression. path is path of
 // nested type identifiers to the type expression.
 func (sc *symbolCollector) walkType(typ ast.Expr, path ...*ast.Ident) {
diff --git a/internal/lsp/testdata/workspacesymbol/issue44806.go b/internal/lsp/testdata/workspacesymbol/issue44806.go
new file mode 100644
index 0000000..6a6e03a
--- /dev/null
+++ b/internal/lsp/testdata/workspacesymbol/issue44806.go
@@ -0,0 +1,10 @@
+package main
+
+type T struct{}
+
+// We should accept all valid receiver syntax when scanning symbols.
+func (*(T)) m1() {}
+func (*T) m2()   {}
+func (T) m3()    {}
+func ((T)) m4()    {}
+func ((*T)) m5()   {}