@@ -75,14 +75,30 @@ func stubMethodsFixer(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.
75
75
importEnv [importPath ] = name // latest alias wins
76
76
}
77
77
78
+ // Record all direct methods of the current object
79
+ concreteFuncs := make (map [string ]struct {})
80
+ for i := 0 ; i < si .Concrete .NumMethods (); i ++ {
81
+ concreteFuncs [si .Concrete .Method (i ).Name ()] = struct {}{}
82
+ }
83
+
78
84
// Find subset of interface methods that the concrete type lacks.
79
- var missing []* types.Func
80
85
ifaceType := si .Interface .Type ().Underlying ().(* types.Interface )
86
+
87
+ type missingFn struct {
88
+ fn * types.Func
89
+ needSubtle string
90
+ }
91
+
92
+ var (
93
+ missing []missingFn
94
+ concreteStruct , isStruct = si .Concrete .Origin ().Underlying ().(* types.Struct )
95
+ )
96
+
81
97
for i := 0 ; i < ifaceType .NumMethods (); i ++ {
82
98
imethod := ifaceType .Method (i )
83
- cmethod , _ , _ := types .LookupFieldOrMethod (si .Concrete , si .Pointer , imethod .Pkg (), imethod .Name ())
99
+ cmethod , index , _ := types .LookupFieldOrMethod (si .Concrete , si .Pointer , imethod .Pkg (), imethod .Name ())
84
100
if cmethod == nil {
85
- missing = append (missing , imethod )
101
+ missing = append (missing , missingFn { fn : imethod } )
86
102
continue
87
103
}
88
104
@@ -92,10 +108,27 @@ func stubMethodsFixer(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.
92
108
conc .Name (), imethod .Name ())
93
109
}
94
110
95
- if ! types .Identical (cmethod .Type (), imethod .Type ()) {
96
- return nil , nil , fmt .Errorf ("method %s.%s already exists but has the wrong type: got %s, want %s" ,
97
- conc .Name (), imethod .Name (), cmethod .Type (), imethod .Type ())
111
+ if _ , exist := concreteFuncs [imethod .Name ()]; exist {
112
+ if ! types .Identical (cmethod .Type (), imethod .Type ()) {
113
+ return nil , nil , fmt .Errorf ("method %s.%s already exists but has the wrong type: got %s, want %s" ,
114
+ conc .Name (), imethod .Name (), cmethod .Type (), imethod .Type ())
115
+ }
116
+ continue
117
+ }
118
+
119
+ mf := missingFn {fn : imethod }
120
+ if isStruct && len (index ) > 0 {
121
+ field := concreteStruct .Field (index [0 ])
122
+
123
+ fn := field .Name ()
124
+ if _ , ok := field .Type ().(* types.Pointer ); ok {
125
+ fn = "*" + fn
126
+ }
127
+
128
+ mf .needSubtle = fmt .Sprintf ("// Subtle: this method shadows the method (%s).%s of %s.%s.\n " , fn , imethod .Name (), si .Concrete .Obj ().Name (), field .Name ())
98
129
}
130
+
131
+ missing = append (missing , mf )
99
132
}
100
133
if len (missing ) == 0 {
101
134
return nil , nil , fmt .Errorf ("no missing methods found" )
@@ -159,19 +192,20 @@ func stubMethodsFixer(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.
159
192
160
193
// Format the new methods.
161
194
var newMethods bytes.Buffer
162
- for _ , method := range missing {
195
+ for index := range missing {
163
196
fmt .Fprintf (& newMethods , `// %s implements %s.
164
- func (%s%s%s) %s%s {
197
+ %sfunc (%s%s%s) %s%s {
165
198
panic("unimplemented")
166
199
}
167
200
` ,
168
- method .Name (),
201
+ missing [ index ]. fn .Name (),
169
202
iface ,
203
+ missing [index ].needSubtle ,
170
204
star ,
171
205
si .Concrete .Obj ().Name (),
172
206
FormatTypeParams (si .Concrete .TypeParams ()),
173
- method .Name (),
174
- strings .TrimPrefix (types .TypeString (method .Type (), qual ), "func" ))
207
+ missing [ index ]. fn .Name (),
208
+ strings .TrimPrefix (types .TypeString (missing [ index ]. fn .Type (), qual ), "func" ))
175
209
}
176
210
177
211
// Compute insertion point for new methods:
0 commit comments