@@ -73,70 +73,47 @@ func implementations(ctx context.Context, s Snapshot, f FileHandle, pp protocol.
73
73
if err != nil {
74
74
return nil , err
75
75
}
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
- }
102
76
103
77
var objs []types.Object
104
78
105
79
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 ())
126
98
}
127
99
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
135
110
}
136
-
137
- return nil , ErrNotAType
138
111
}
139
112
113
+ pkgs := make (map [* types.Package ]Package , len (knownPkgs ))
114
+ for _ , pkg := range knownPkgs {
115
+ pkgs [pkg .GetTypes ()] = pkg
116
+ }
140
117
seen := make (map [token.Position ]bool )
141
118
for _ , obj := range objs {
142
119
pos := s .FileSet ().Position (obj .Pos ())
@@ -153,13 +130,23 @@ func implementations(ctx context.Context, s Snapshot, f FileHandle, pp protocol.
153
130
return impls , nil
154
131
}
155
132
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 ) {
157
134
if types .NewMethodSet (queryType ).Len () == 0 {
158
135
return nil
159
136
}
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
+ }
160
148
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.
163
150
var (
164
151
candObj types.Object = named .Obj ()
165
152
candType = ensurePointer (named )
@@ -193,29 +180,39 @@ func findInterfaceImplementations(getAllNamed func() []*types.Named, s Snapshot,
193
180
return objs
194
181
}
195
182
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
+ }
211
197
}
198
+ }
212
199
200
+ // Look up functions that match.
201
+ if _ , isType := o .(* types.TypeName ); isType {
202
+ continue
203
+ }
204
+ if objectImplementsSignature (o , sig ) {
213
205
objs = append (objs , o )
214
206
}
215
207
}
216
208
return objs
217
209
}
218
210
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
+
219
216
// concreteImplementsIntf returns true if a is an interface type implemented by
220
217
// concrete type b, or vice versa.
221
218
func concreteImplementsIntf (a , b types.Type ) bool {
0 commit comments