@@ -97,14 +97,19 @@ func ExtractToNewFile(ctx context.Context, snapshot *cache.Snapshot, fh file.Han
97
97
if ! ok {
98
98
return nil , bug .Errorf ("invalid selection" )
99
99
}
100
+ pgf .CheckPos (start ) // #70553
101
+ // Inv: start is valid wrt pgf.Tok.
100
102
101
103
// select trailing empty lines
102
104
offset , err := safetoken .Offset (pgf .Tok , end )
103
105
if err != nil {
104
106
return nil , err
105
107
}
106
108
rest := pgf .Src [offset :]
107
- end += token .Pos (len (rest ) - len (bytes .TrimLeft (rest , " \t \n " )))
109
+ spaces := len (rest ) - len (bytes .TrimLeft (rest , " \t \n " ))
110
+ end += token .Pos (spaces )
111
+ pgf .CheckPos (end ) // #70553
112
+ // Inv: end is valid wrt pgf.Tok.
108
113
109
114
replaceRange , err := pgf .PosRange (start , end )
110
115
if err != nil {
@@ -172,6 +177,7 @@ func ExtractToNewFile(ctx context.Context, snapshot *cache.Snapshot, fh file.Han
172
177
}
173
178
174
179
fileStart := pgf .File .FileStart
180
+ pgf .CheckPos (fileStart ) // #70553
175
181
buf .Write (pgf .Src [start - fileStart : end - fileStart ])
176
182
177
183
newFileContent , err := format .Source (buf .Bytes ())
@@ -221,31 +227,42 @@ func selectedToplevelDecls(pgf *parsego.File, start, end token.Pos) (token.Pos,
221
227
firstName := ""
222
228
for _ , decl := range pgf .File .Decls {
223
229
if posRangeIntersects (start , end , decl .Pos (), decl .End ()) {
224
- var id * ast.Ident
225
- switch v := decl .(type ) {
230
+ var (
231
+ comment * ast.CommentGroup // (include comment preceding decl)
232
+ id * ast.Ident
233
+ )
234
+ switch decl := decl .(type ) {
226
235
case * ast.BadDecl :
227
236
return 0 , 0 , "" , false
237
+
228
238
case * ast.FuncDecl :
229
239
// if only selecting keyword "func" or function name, extend selection to the
230
240
// whole function
231
- if posRangeContains (v .Pos (), v .Name .End (), start , end ) {
232
- start , end = v .Pos (), v .End ()
241
+ if posRangeContains (decl .Pos (), decl .Name .End (), start , end ) {
242
+ pgf .CheckNode (decl ) // #70553
243
+ start , end = decl .Pos (), decl .End ()
244
+ // Inv: start, end are valid wrt pgf.Tok.
233
245
}
234
- id = v .Name
246
+ comment = decl .Doc
247
+ id = decl .Name
248
+
235
249
case * ast.GenDecl :
236
250
// selection cannot intersect an import declaration
237
- if v .Tok == token .IMPORT {
251
+ if decl .Tok == token .IMPORT {
238
252
return 0 , 0 , "" , false
239
253
}
240
254
// if only selecting keyword "type", "const", or "var", extend selection to the
241
255
// whole declaration
242
- if v .Tok == token .TYPE && posRangeContains (v .Pos (), v .Pos ()+ token .Pos (len ("type" )), start , end ) ||
243
- v .Tok == token .CONST && posRangeContains (v .Pos (), v .Pos ()+ token .Pos (len ("const" )), start , end ) ||
244
- v .Tok == token .VAR && posRangeContains (v .Pos (), v .Pos ()+ token .Pos (len ("var" )), start , end ) {
245
- start , end = v .Pos (), v .End ()
256
+ if decl .Tok == token .TYPE && posRangeContains (decl .Pos (), decl .Pos ()+ token .Pos (len ("type" )), start , end ) ||
257
+ decl .Tok == token .CONST && posRangeContains (decl .Pos (), decl .Pos ()+ token .Pos (len ("const" )), start , end ) ||
258
+ decl .Tok == token .VAR && posRangeContains (decl .Pos (), decl .Pos ()+ token .Pos (len ("var" )), start , end ) {
259
+ pgf .CheckNode (decl ) // #70553
260
+ start , end = decl .Pos (), decl .End ()
261
+ // Inv: start, end are valid wrt pgf.Tok.
246
262
}
247
- if len (v .Specs ) > 0 {
248
- switch spec := v .Specs [0 ].(type ) {
263
+ comment = decl .Doc
264
+ if len (decl .Specs ) > 0 {
265
+ switch spec := decl .Specs [0 ].(type ) {
249
266
case * ast.TypeSpec :
250
267
id = spec .Name
251
268
case * ast.ValueSpec :
@@ -261,16 +278,10 @@ func selectedToplevelDecls(pgf *parsego.File, start, end token.Pos) (token.Pos,
261
278
// may be "_"
262
279
firstName = id .Name
263
280
}
264
- // extends selection to docs comments
265
- var c * ast.CommentGroup
266
- switch decl := decl .(type ) {
267
- case * ast.GenDecl :
268
- c = decl .Doc
269
- case * ast.FuncDecl :
270
- c = decl .Doc
271
- }
272
- if c != nil && c .Pos () < start {
273
- start = c .Pos ()
281
+ if comment != nil && comment .Pos () < start {
282
+ pgf .CheckNode (comment ) // #70553
283
+ start = comment .Pos ()
284
+ // Inv: start is valid wrt pgf.Tok.
274
285
}
275
286
}
276
287
}
0 commit comments