@@ -22,6 +22,7 @@ import (
22
22
"golang.org/x/tools/gopls/internal/lsp/protocol"
23
23
"golang.org/x/tools/gopls/internal/lsp/safetoken"
24
24
"golang.org/x/tools/gopls/internal/span"
25
+ "golang.org/x/tools/internal/bug"
25
26
"golang.org/x/tools/internal/typeparams"
26
27
)
27
28
@@ -34,7 +35,7 @@ func stubSuggestedFixFunc(ctx context.Context, snapshot Snapshot, fh FileHandle,
34
35
if err != nil {
35
36
return nil , nil , fmt .Errorf ("getNodes: %w" , err )
36
37
}
37
- si := stubmethods .GetStubInfo (pkg .GetTypesInfo (), nodes , pos )
38
+ si := stubmethods .GetStubInfo (pkg .FileSet (), pkg . GetTypesInfo (), nodes , pos )
38
39
if si == nil {
39
40
return nil , nil , fmt .Errorf ("nil interface request" )
40
41
}
@@ -47,14 +48,14 @@ func stubSuggestedFixFunc(ctx context.Context, snapshot Snapshot, fh FileHandle,
47
48
}
48
49
49
50
// Parse the file defining the concrete type.
50
- concreteFilename := safetoken .StartPosition (snapshot . FileSet () , si .Concrete .Obj ().Pos ()).Filename
51
+ concreteFilename := safetoken .StartPosition (si . Fset , si .Concrete .Obj ().Pos ()).Filename
51
52
concreteFH , err := snapshot .GetFile (ctx , span .URIFromPath (concreteFilename ))
52
53
if err != nil {
53
54
return nil , nil , err
54
55
}
55
56
parsedConcreteFile , err := snapshot .ParseGo (ctx , concreteFH , ParseFull )
56
57
if err != nil {
57
- return nil , nil , fmt .Errorf ("failed to parse file declaring implementation type: %w" , err )
58
+ return nil , nil , fmt .Errorf ("failed to parse file %q declaring implementation type: %w" , concreteFH . URI () , err )
58
59
}
59
60
var (
60
61
methodsSrc []byte
@@ -72,21 +73,28 @@ func stubSuggestedFixFunc(ctx context.Context, snapshot Snapshot, fh FileHandle,
72
73
// Splice the methods into the file.
73
74
// The insertion point is after the top-level declaration
74
75
// enclosing the (package-level) type object.
75
- insertPos := parsedConcreteFile .File .End ()
76
+ insertOffset , err := safetoken .Offset (parsedConcreteFile .Tok , parsedConcreteFile .File .End ())
77
+ if err != nil {
78
+ return nil , nil , bug .Errorf ("internal error: end position outside file bounds: %v" , err )
79
+ }
80
+ concOffset , err := safetoken .Offset (pkg .FileSet ().File (conc .Pos ()), conc .Pos ())
81
+ if err != nil {
82
+ return nil , nil , bug .Errorf ("internal error: finding type decl offset: %v" , err )
83
+ }
76
84
for _ , decl := range parsedConcreteFile .File .Decls {
77
- if decl .End () > conc .Pos () {
78
- insertPos = decl .End ()
85
+ declEndOffset , err := safetoken .Offset (parsedConcreteFile .Tok , decl .End ())
86
+ if err != nil {
87
+ return nil , nil , bug .Errorf ("internal error: finding decl offset: %v" , err )
88
+ }
89
+ if declEndOffset > concOffset {
90
+ insertOffset = declEndOffset
79
91
break
80
92
}
81
93
}
82
94
concreteSrc , err := concreteFH .Read ()
83
95
if err != nil {
84
96
return nil , nil , fmt .Errorf ("error reading concrete file source: %w" , err )
85
97
}
86
- insertOffset , err := safetoken .Offset (parsedConcreteFile .Tok , insertPos )
87
- if err != nil || insertOffset >= len (concreteSrc ) {
88
- return nil , nil , fmt .Errorf ("insertion position is past the end of the file" )
89
- }
90
98
var buf bytes.Buffer
91
99
buf .Write (concreteSrc [:insertOffset ])
92
100
buf .WriteByte ('\n' )
@@ -126,7 +134,7 @@ func stubSuggestedFixFunc(ctx context.Context, snapshot Snapshot, fh FileHandle,
126
134
// that implement the given interface
127
135
func stubMethods (ctx context.Context , concreteFile * ast.File , si * stubmethods.StubInfo , snapshot Snapshot ) ([]byte , []* stubImport , error ) {
128
136
concMS := types .NewMethodSet (types .NewPointer (si .Concrete .Obj ().Type ()))
129
- missing , err := missingMethods (ctx , snapshot , concMS , si .Concrete .Obj ().Pkg (), si .Interface , map [string ]struct {}{})
137
+ missing , err := missingMethods (ctx , si . Fset , snapshot , concMS , si .Concrete .Obj ().Pkg (), si .Interface , map [string ]struct {}{})
130
138
if err != nil {
131
139
return nil , nil , fmt .Errorf ("missingMethods: %w" , err )
132
140
}
@@ -249,8 +257,10 @@ returns
249
257
missing: []*types.Func{Hello}
250
258
},
251
259
}
260
+
261
+ The provided FileSet must be the FileSet used when type-checking concPkg.
252
262
*/
253
- func missingMethods (ctx context.Context , snapshot Snapshot , concMS * types.MethodSet , concPkg * types.Package , ifaceObj * types.TypeName , visited map [string ]struct {}) ([]* missingInterface , error ) {
263
+ func missingMethods (ctx context.Context , fset * token. FileSet , snapshot Snapshot , concMS * types.MethodSet , concPkg * types.Package , ifaceObj * types.TypeName , visited map [string ]struct {}) ([]* missingInterface , error ) {
254
264
iface , ok := ifaceObj .Type ().Underlying ().(* types.Interface )
255
265
if ! ok {
256
266
return nil , fmt .Errorf ("expected %v to be an interface but got %T" , iface , ifaceObj .Type ().Underlying ())
@@ -270,7 +280,7 @@ func missingMethods(ctx context.Context, snapshot Snapshot, concMS *types.Method
270
280
}
271
281
272
282
// Parse the imports from the file that declares the interface.
273
- ifaceFilename := safetoken .StartPosition (snapshot . FileSet () , ifaceObj .Pos ()).Filename
283
+ ifaceFilename := safetoken .StartPosition (fset , ifaceObj .Pos ()).Filename
274
284
ifaceFH , err := snapshot .GetFile (ctx , span .URIFromPath (ifaceFilename ))
275
285
if err != nil {
276
286
return nil , err
@@ -311,7 +321,7 @@ func missingMethods(ctx context.Context, snapshot Snapshot, concMS *types.Method
311
321
var missingInterfaces []* missingInterface
312
322
for i := 0 ; i < iface .NumEmbeddeds (); i ++ {
313
323
eiface := iface .Embedded (i ).Obj ()
314
- em , err := missingMethods (ctx , snapshot , concMS , concPkg , eiface , visited )
324
+ em , err := missingMethods (ctx , fset , snapshot , concMS , concPkg , eiface , visited )
315
325
if err != nil {
316
326
return nil , err
317
327
}
0 commit comments