@@ -97,14 +97,19 @@ func ExtractToNewFile(ctx context.Context, snapshot *cache.Snapshot, fh file.Han
9797 if ! ok {
9898 return nil , bug .Errorf ("invalid selection" )
9999 }
100+ pgf .CheckPos (start ) // #70553
101+ // Inv: start is valid wrt pgf.Tok.
100102
101103 // select trailing empty lines
102104 offset , err := safetoken .Offset (pgf .Tok , end )
103105 if err != nil {
104106 return nil , err
105107 }
106108 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.
108113
109114 replaceRange , err := pgf .PosRange (start , end )
110115 if err != nil {
@@ -172,6 +177,7 @@ func ExtractToNewFile(ctx context.Context, snapshot *cache.Snapshot, fh file.Han
172177 }
173178
174179 fileStart := pgf .File .FileStart
180+ pgf .CheckPos (fileStart ) // #70553
175181 buf .Write (pgf .Src [start - fileStart : end - fileStart ])
176182
177183 newFileContent , err := format .Source (buf .Bytes ())
@@ -221,31 +227,42 @@ func selectedToplevelDecls(pgf *parsego.File, start, end token.Pos) (token.Pos,
221227 firstName := ""
222228 for _ , decl := range pgf .File .Decls {
223229 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 ) {
226235 case * ast.BadDecl :
227236 return 0 , 0 , "" , false
237+
228238 case * ast.FuncDecl :
229239 // if only selecting keyword "func" or function name, extend selection to the
230240 // 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.
233245 }
234- id = v .Name
246+ comment = decl .Doc
247+ id = decl .Name
248+
235249 case * ast.GenDecl :
236250 // selection cannot intersect an import declaration
237- if v .Tok == token .IMPORT {
251+ if decl .Tok == token .IMPORT {
238252 return 0 , 0 , "" , false
239253 }
240254 // if only selecting keyword "type", "const", or "var", extend selection to the
241255 // 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.
246262 }
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 ) {
249266 case * ast.TypeSpec :
250267 id = spec .Name
251268 case * ast.ValueSpec :
@@ -261,16 +278,10 @@ func selectedToplevelDecls(pgf *parsego.File, start, end token.Pos) (token.Pos,
261278 // may be "_"
262279 firstName = id .Name
263280 }
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.
274285 }
275286 }
276287 }
0 commit comments