Skip to content

Commit 02be885

Browse files
committed
gopls/internal/lsp: update implementation to simplify loop body
1 parent 952df4b commit 02be885

File tree

2 files changed

+72
-75
lines changed

2 files changed

+72
-75
lines changed

gopls/internal/lsp/source/implementation.go

Lines changed: 70 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -73,70 +73,47 @@ func implementations(ctx context.Context, s Snapshot, f FileHandle, pp protocol.
7373
if err != nil {
7474
return nil, err
7575
}
76-
pkgs := make(map[*types.Package]Package, len(knownPkgs))
77-
for _, pkg := range knownPkgs {
78-
pkgs[pkg.GetTypes()] = pkg
79-
}
80-
81-
// Defer collection and caching of named types. It's only required for
82-
// interface definitions, not function type defintions.
83-
var allNamed []*types.Named
84-
getAllNamed := func() []*types.Named {
85-
if allNamed == nil {
86-
for _, pkg := range knownPkgs {
87-
for _, obj := range pkg.GetTypesInfo().Defs {
88-
obj, ok := obj.(*types.TypeName)
89-
// We ignore aliases 'type M = N' to avoid duplicate reporting
90-
// of the Named type N.
91-
if !ok || obj.IsAlias() {
92-
continue
93-
}
94-
if named, ok := obj.Type().(*types.Named); ok {
95-
allNamed = append(allNamed, named)
96-
}
97-
}
98-
}
99-
}
100-
return allNamed
101-
}
10276

10377
var objs []types.Object
10478

10579
for _, qo := range qos {
106-
var sig *types.Signature
107-
var iface types.Type
108-
var method *types.Func
109-
110-
switch obj := qo.obj.(type) {
111-
case *types.Func:
112-
recv := obj.Type().(*types.Signature).Recv()
113-
if recv == nil {
114-
break
115-
}
116-
iface = ensurePointer(recv.Type())
117-
method = obj
118-
case *types.TypeName:
119-
sig, _ = obj.Type().Underlying().(*types.Signature)
120-
if sig != nil {
121-
break
122-
}
123-
iface = ensurePointer(obj.Type())
124-
case *types.Var:
125-
sig, _ = obj.Type().Underlying().(*types.Signature)
80+
var queryType types.Type
81+
var queryMethod types.Object
82+
83+
sig, hasSig := qo.obj.Type().Underlying().(*types.Signature)
84+
// If there's a signature, then qo must be a function.
85+
// If there's no receiver, then search for implementations of the
86+
// function type, or function types that qo's signature matches.
87+
if hasSig && sig.Recv() != nil {
88+
// If there's a receiver, then qo must be a method.
89+
// Query for implementations of the interface's method /
90+
// interfaces that the method fully or partially implements.
91+
queryType = ensurePointer(sig.Recv().Type())
92+
queryMethod = qo.obj
93+
} else if !hasSig {
94+
// If there's no signature, then qo must be a type.
95+
// Query for implementations of the interface / types that
96+
// implement the interface.
97+
queryType = ensurePointer(qo.obj.Type())
12698
}
12799

128-
if iface != nil {
129-
objs = append(objs, findInterfaceImplementations(getAllNamed, s, iface, method)...)
130-
continue
131-
}
132-
if sig != nil && includeFuncs {
133-
objs = append(objs, findFunctionImplementations(pkgs, s, sig)...)
134-
continue
100+
if queryType != nil {
101+
for _, pkg := range knownPkgs {
102+
objs = append(objs, findInterfaceImplementations(pkg, queryType, queryMethod)...)
103+
}
104+
} else if hasSig && includeFuncs {
105+
for _, pkg := range knownPkgs {
106+
objs = append(objs, findFunctionImplementations(pkg, sig)...)
107+
}
108+
} else {
109+
return nil, ErrNotAType
135110
}
136-
137-
return nil, ErrNotAType
138111
}
139112

113+
pkgs := make(map[*types.Package]Package, len(knownPkgs))
114+
for _, pkg := range knownPkgs {
115+
pkgs[pkg.GetTypes()] = pkg
116+
}
140117
seen := make(map[token.Position]bool)
141118
for _, obj := range objs {
142119
pos := s.FileSet().Position(obj.Pos())
@@ -153,13 +130,23 @@ func implementations(ctx context.Context, s Snapshot, f FileHandle, pp protocol.
153130
return impls, nil
154131
}
155132

156-
func findInterfaceImplementations(getAllNamed func() []*types.Named, s Snapshot, queryType types.Type, queryMethod *types.Func) (objs []types.Object) {
133+
func findInterfaceImplementations(pkg Package, queryType types.Type, queryMethod types.Object) (objs []types.Object) {
157134
if types.NewMethodSet(queryType).Len() == 0 {
158135
return nil
159136
}
137+
for _, obj := range pkg.GetTypesInfo().Defs {
138+
obj, ok := obj.(*types.TypeName)
139+
// We ignore aliases 'type M = N' to avoid duplicate reporting
140+
// of the Named type N.
141+
if !ok || obj.IsAlias() {
142+
continue
143+
}
144+
named, ok := obj.Type().(*types.Named)
145+
if !ok {
146+
continue
147+
}
160148

161-
// Find all the named types that match our query.
162-
for _, named := range getAllNamed() {
149+
// Find all the named types that match our query.
163150
var (
164151
candObj types.Object = named.Obj()
165152
candType = ensurePointer(named)
@@ -193,29 +180,39 @@ func findInterfaceImplementations(getAllNamed func() []*types.Named, s Snapshot,
193180
return objs
194181
}
195182

196-
func findFunctionImplementations(pkgs map[*types.Package]Package, s Snapshot, sig *types.Signature) (objs []types.Object) {
197-
for pkg := range pkgs {
198-
for _, name := range pkg.Scope().Names() {
199-
o := pkg.Scope().Lookup(name)
200-
if _, isType := o.(*types.TypeName); isType {
201-
continue
202-
}
203-
var csig *types.Signature
204-
var isFunc bool
205-
if csig, isFunc = o.Type().Underlying().(*types.Signature); !isFunc {
206-
continue
207-
}
208-
209-
if !types.AssignableTo(sig, csig) {
210-
continue
183+
func findFunctionImplementations(pkg Package, sig *types.Signature) (objs []types.Object) {
184+
for _, name := range pkg.GetTypes().Scope().Names() {
185+
o := pkg.GetTypes().Scope().Lookup(name)
186+
187+
// Look up methods that match the signature.
188+
if obj, isTypeName := o.(*types.TypeName); isTypeName && !obj.IsAlias() {
189+
if named, isNamed := obj.Type().(*types.Named); isNamed {
190+
ms := types.NewMethodSet(ensurePointer(named))
191+
for i := 0; i < ms.Len(); i++ {
192+
o := ms.At(i).Obj()
193+
if objectImplementsSignature(o, sig) {
194+
objs = append(objs, o)
195+
}
196+
}
211197
}
198+
}
212199

200+
// Look up functions that match.
201+
if _, isType := o.(*types.TypeName); isType {
202+
continue
203+
}
204+
if objectImplementsSignature(o, sig) {
213205
objs = append(objs, o)
214206
}
215207
}
216208
return objs
217209
}
218210

211+
func objectImplementsSignature(o types.Object, sig *types.Signature) bool {
212+
csig, isSig := o.Type().Underlying().(*types.Signature)
213+
return isSig && types.AssignableTo(sig, csig)
214+
}
215+
219216
// concreteImplementsIntf returns true if a is an interface type implemented by
220217
// concrete type b, or vice versa.
221218
func concreteImplementsIntf(a, b types.Type) bool {

gopls/internal/lsp/testdata/implementation/implementation.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func implementationOfAnonymous2(data []byte) error { //@mark(implementationOfAno
5757
return nil
5858
}
5959

60-
func TestAnonymousFunction(af func([]byte) error) {
60+
func TestAnonymousFunction(af func([]byte, cry func(other.CryType)) error) {
6161
af([]byte{0, 1}) //implementations("af", implementationOfAnonymous1, implementationOfAnonymous2)
62+
cry(other.CryType(12)) //implementations("Cry", Cry)
6263
}
63-

0 commit comments

Comments
 (0)