golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/go/ast/astutil/rewrite.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package astutil 6 7 import ( 8 "fmt" 9 "go/ast" 10 "reflect" 11 "sort" 12 ) 13 14 // An ApplyFunc is invoked by Apply for each node n, even if n is nil, 15 // before and/or after the node's children, using a Cursor describing 16 // the current node and providing operations on it. 17 // 18 // The return value of ApplyFunc controls the syntax tree traversal. 19 // See Apply for details. 20 type ApplyFunc func(*Cursor) bool 21 22 // Apply traverses a syntax tree recursively, starting with root, 23 // and calling pre and post for each node as described below. 24 // Apply returns the syntax tree, possibly modified. 25 // 26 // If pre is not nil, it is called for each node before the node's 27 // children are traversed (pre-order). If pre returns false, no 28 // children are traversed, and post is not called for that node. 29 // 30 // If post is not nil, and a prior call of pre didn't return false, 31 // post is called for each node after its children are traversed 32 // (post-order). If post returns false, traversal is terminated and 33 // Apply returns immediately. 34 // 35 // Only fields that refer to AST nodes are considered children; 36 // i.e., token.Pos, Scopes, Objects, and fields of basic types 37 // (strings, etc.) are ignored. 38 // 39 // Children are traversed in the order in which they appear in the 40 // respective node's struct definition. A package's files are 41 // traversed in the filenames' alphabetical order. 42 func Apply(root ast.Node, pre, post ApplyFunc) (result ast.Node) { 43 parent := &struct{ ast.Node }{root} 44 defer func() { 45 if r := recover(); r != nil && r != abort { 46 panic(r) 47 } 48 result = parent.Node 49 }() 50 a := &application{pre: pre, post: post} 51 a.apply(parent, "Node", nil, root) 52 return 53 } 54 55 var abort = new(int) // singleton, to signal termination of Apply 56 57 // A Cursor describes a node encountered during Apply. 58 // Information about the node and its parent is available 59 // from the Node, Parent, Name, and Index methods. 60 // 61 // If p is a variable of type and value of the current parent node 62 // c.Parent(), and f is the field identifier with name c.Name(), 63 // the following invariants hold: 64 // 65 // p.f == c.Node() if c.Index() < 0 66 // p.f[c.Index()] == c.Node() if c.Index() >= 0 67 // 68 // The methods Replace, Delete, InsertBefore, and InsertAfter 69 // can be used to change the AST without disrupting Apply. 70 type Cursor struct { 71 parent ast.Node 72 name string 73 iter *iterator // valid if non-nil 74 node ast.Node 75 } 76 77 // Node returns the current Node. 78 func (c *Cursor) Node() ast.Node { return c.node } 79 80 // Parent returns the parent of the current Node. 81 func (c *Cursor) Parent() ast.Node { return c.parent } 82 83 // Name returns the name of the parent Node field that contains the current Node. 84 // If the parent is a *ast.Package and the current Node is a *ast.File, Name returns 85 // the filename for the current Node. 86 func (c *Cursor) Name() string { return c.name } 87 88 // Index reports the index >= 0 of the current Node in the slice of Nodes that 89 // contains it, or a value < 0 if the current Node is not part of a slice. 90 // The index of the current node changes if InsertBefore is called while 91 // processing the current node. 92 func (c *Cursor) Index() int { 93 if c.iter != nil { 94 return c.iter.index 95 } 96 return -1 97 } 98 99 // field returns the current node's parent field value. 100 func (c *Cursor) field() reflect.Value { 101 return reflect.Indirect(reflect.ValueOf(c.parent)).FieldByName(c.name) 102 } 103 104 // Replace replaces the current Node with n. 105 // The replacement node is not walked by Apply. 106 func (c *Cursor) Replace(n ast.Node) { 107 if _, ok := c.node.(*ast.File); ok { 108 file, ok := n.(*ast.File) 109 if !ok { 110 panic("attempt to replace *ast.File with non-*ast.File") 111 } 112 c.parent.(*ast.Package).Files[c.name] = file 113 return 114 } 115 116 v := c.field() 117 if i := c.Index(); i >= 0 { 118 v = v.Index(i) 119 } 120 v.Set(reflect.ValueOf(n)) 121 } 122 123 // Delete deletes the current Node from its containing slice. 124 // If the current Node is not part of a slice, Delete panics. 125 // As a special case, if the current node is a package file, 126 // Delete removes it from the package's Files map. 127 func (c *Cursor) Delete() { 128 if _, ok := c.node.(*ast.File); ok { 129 delete(c.parent.(*ast.Package).Files, c.name) 130 return 131 } 132 133 i := c.Index() 134 if i < 0 { 135 panic("Delete node not contained in slice") 136 } 137 v := c.field() 138 l := v.Len() 139 reflect.Copy(v.Slice(i, l), v.Slice(i+1, l)) 140 v.Index(l - 1).Set(reflect.Zero(v.Type().Elem())) 141 v.SetLen(l - 1) 142 c.iter.step-- 143 } 144 145 // InsertAfter inserts n after the current Node in its containing slice. 146 // If the current Node is not part of a slice, InsertAfter panics. 147 // Apply does not walk n. 148 func (c *Cursor) InsertAfter(n ast.Node) { 149 i := c.Index() 150 if i < 0 { 151 panic("InsertAfter node not contained in slice") 152 } 153 v := c.field() 154 v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) 155 l := v.Len() 156 reflect.Copy(v.Slice(i+2, l), v.Slice(i+1, l)) 157 v.Index(i + 1).Set(reflect.ValueOf(n)) 158 c.iter.step++ 159 } 160 161 // InsertBefore inserts n before the current Node in its containing slice. 162 // If the current Node is not part of a slice, InsertBefore panics. 163 // Apply will not walk n. 164 func (c *Cursor) InsertBefore(n ast.Node) { 165 i := c.Index() 166 if i < 0 { 167 panic("InsertBefore node not contained in slice") 168 } 169 v := c.field() 170 v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) 171 l := v.Len() 172 reflect.Copy(v.Slice(i+1, l), v.Slice(i, l)) 173 v.Index(i).Set(reflect.ValueOf(n)) 174 c.iter.index++ 175 } 176 177 // application carries all the shared data so we can pass it around cheaply. 178 type application struct { 179 pre, post ApplyFunc 180 cursor Cursor 181 iter iterator 182 } 183 184 func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.Node) { 185 // convert typed nil into untyped nil 186 if v := reflect.ValueOf(n); v.Kind() == reflect.Ptr && v.IsNil() { 187 n = nil 188 } 189 190 // avoid heap-allocating a new cursor for each apply call; reuse a.cursor instead 191 saved := a.cursor 192 a.cursor.parent = parent 193 a.cursor.name = name 194 a.cursor.iter = iter 195 a.cursor.node = n 196 197 if a.pre != nil && !a.pre(&a.cursor) { 198 a.cursor = saved 199 return 200 } 201 202 // walk children 203 // (the order of the cases matches the order of the corresponding node types in go/ast) 204 switch n := n.(type) { 205 case nil: 206 // nothing to do 207 208 // Comments and fields 209 case *ast.Comment: 210 // nothing to do 211 212 case *ast.CommentGroup: 213 if n != nil { 214 a.applyList(n, "List") 215 } 216 217 case *ast.Field: 218 a.apply(n, "Doc", nil, n.Doc) 219 a.applyList(n, "Names") 220 a.apply(n, "Type", nil, n.Type) 221 a.apply(n, "Tag", nil, n.Tag) 222 a.apply(n, "Comment", nil, n.Comment) 223 224 case *ast.FieldList: 225 a.applyList(n, "List") 226 227 // Expressions 228 case *ast.BadExpr, *ast.Ident, *ast.BasicLit: 229 // nothing to do 230 231 case *ast.Ellipsis: 232 a.apply(n, "Elt", nil, n.Elt) 233 234 case *ast.FuncLit: 235 a.apply(n, "Type", nil, n.Type) 236 a.apply(n, "Body", nil, n.Body) 237 238 case *ast.CompositeLit: 239 a.apply(n, "Type", nil, n.Type) 240 a.applyList(n, "Elts") 241 242 case *ast.ParenExpr: 243 a.apply(n, "X", nil, n.X) 244 245 case *ast.SelectorExpr: 246 a.apply(n, "X", nil, n.X) 247 a.apply(n, "Sel", nil, n.Sel) 248 249 case *ast.IndexExpr: 250 a.apply(n, "X", nil, n.X) 251 a.apply(n, "Index", nil, n.Index) 252 253 case *ast.IndexListExpr: 254 a.apply(n, "X", nil, n.X) 255 a.applyList(n, "Indices") 256 257 case *ast.SliceExpr: 258 a.apply(n, "X", nil, n.X) 259 a.apply(n, "Low", nil, n.Low) 260 a.apply(n, "High", nil, n.High) 261 a.apply(n, "Max", nil, n.Max) 262 263 case *ast.TypeAssertExpr: 264 a.apply(n, "X", nil, n.X) 265 a.apply(n, "Type", nil, n.Type) 266 267 case *ast.CallExpr: 268 a.apply(n, "Fun", nil, n.Fun) 269 a.applyList(n, "Args") 270 271 case *ast.StarExpr: 272 a.apply(n, "X", nil, n.X) 273 274 case *ast.UnaryExpr: 275 a.apply(n, "X", nil, n.X) 276 277 case *ast.BinaryExpr: 278 a.apply(n, "X", nil, n.X) 279 a.apply(n, "Y", nil, n.Y) 280 281 case *ast.KeyValueExpr: 282 a.apply(n, "Key", nil, n.Key) 283 a.apply(n, "Value", nil, n.Value) 284 285 // Types 286 case *ast.ArrayType: 287 a.apply(n, "Len", nil, n.Len) 288 a.apply(n, "Elt", nil, n.Elt) 289 290 case *ast.StructType: 291 a.apply(n, "Fields", nil, n.Fields) 292 293 case *ast.FuncType: 294 if tparams := n.TypeParams; tparams != nil { 295 a.apply(n, "TypeParams", nil, tparams) 296 } 297 a.apply(n, "Params", nil, n.Params) 298 a.apply(n, "Results", nil, n.Results) 299 300 case *ast.InterfaceType: 301 a.apply(n, "Methods", nil, n.Methods) 302 303 case *ast.MapType: 304 a.apply(n, "Key", nil, n.Key) 305 a.apply(n, "Value", nil, n.Value) 306 307 case *ast.ChanType: 308 a.apply(n, "Value", nil, n.Value) 309 310 // Statements 311 case *ast.BadStmt: 312 // nothing to do 313 314 case *ast.DeclStmt: 315 a.apply(n, "Decl", nil, n.Decl) 316 317 case *ast.EmptyStmt: 318 // nothing to do 319 320 case *ast.LabeledStmt: 321 a.apply(n, "Label", nil, n.Label) 322 a.apply(n, "Stmt", nil, n.Stmt) 323 324 case *ast.ExprStmt: 325 a.apply(n, "X", nil, n.X) 326 327 case *ast.SendStmt: 328 a.apply(n, "Chan", nil, n.Chan) 329 a.apply(n, "Value", nil, n.Value) 330 331 case *ast.IncDecStmt: 332 a.apply(n, "X", nil, n.X) 333 334 case *ast.AssignStmt: 335 a.applyList(n, "Lhs") 336 a.applyList(n, "Rhs") 337 338 case *ast.GoStmt: 339 a.apply(n, "Call", nil, n.Call) 340 341 case *ast.DeferStmt: 342 a.apply(n, "Call", nil, n.Call) 343 344 case *ast.ReturnStmt: 345 a.applyList(n, "Results") 346 347 case *ast.BranchStmt: 348 a.apply(n, "Label", nil, n.Label) 349 350 case *ast.BlockStmt: 351 a.applyList(n, "List") 352 353 case *ast.IfStmt: 354 a.apply(n, "Init", nil, n.Init) 355 a.apply(n, "Cond", nil, n.Cond) 356 a.apply(n, "Body", nil, n.Body) 357 a.apply(n, "Else", nil, n.Else) 358 359 case *ast.CaseClause: 360 a.applyList(n, "List") 361 a.applyList(n, "Body") 362 363 case *ast.SwitchStmt: 364 a.apply(n, "Init", nil, n.Init) 365 a.apply(n, "Tag", nil, n.Tag) 366 a.apply(n, "Body", nil, n.Body) 367 368 case *ast.TypeSwitchStmt: 369 a.apply(n, "Init", nil, n.Init) 370 a.apply(n, "Assign", nil, n.Assign) 371 a.apply(n, "Body", nil, n.Body) 372 373 case *ast.CommClause: 374 a.apply(n, "Comm", nil, n.Comm) 375 a.applyList(n, "Body") 376 377 case *ast.SelectStmt: 378 a.apply(n, "Body", nil, n.Body) 379 380 case *ast.ForStmt: 381 a.apply(n, "Init", nil, n.Init) 382 a.apply(n, "Cond", nil, n.Cond) 383 a.apply(n, "Post", nil, n.Post) 384 a.apply(n, "Body", nil, n.Body) 385 386 case *ast.RangeStmt: 387 a.apply(n, "Key", nil, n.Key) 388 a.apply(n, "Value", nil, n.Value) 389 a.apply(n, "X", nil, n.X) 390 a.apply(n, "Body", nil, n.Body) 391 392 // Declarations 393 case *ast.ImportSpec: 394 a.apply(n, "Doc", nil, n.Doc) 395 a.apply(n, "Name", nil, n.Name) 396 a.apply(n, "Path", nil, n.Path) 397 a.apply(n, "Comment", nil, n.Comment) 398 399 case *ast.ValueSpec: 400 a.apply(n, "Doc", nil, n.Doc) 401 a.applyList(n, "Names") 402 a.apply(n, "Type", nil, n.Type) 403 a.applyList(n, "Values") 404 a.apply(n, "Comment", nil, n.Comment) 405 406 case *ast.TypeSpec: 407 a.apply(n, "Doc", nil, n.Doc) 408 a.apply(n, "Name", nil, n.Name) 409 if tparams := n.TypeParams; tparams != nil { 410 a.apply(n, "TypeParams", nil, tparams) 411 } 412 a.apply(n, "Type", nil, n.Type) 413 a.apply(n, "Comment", nil, n.Comment) 414 415 case *ast.BadDecl: 416 // nothing to do 417 418 case *ast.GenDecl: 419 a.apply(n, "Doc", nil, n.Doc) 420 a.applyList(n, "Specs") 421 422 case *ast.FuncDecl: 423 a.apply(n, "Doc", nil, n.Doc) 424 a.apply(n, "Recv", nil, n.Recv) 425 a.apply(n, "Name", nil, n.Name) 426 a.apply(n, "Type", nil, n.Type) 427 a.apply(n, "Body", nil, n.Body) 428 429 // Files and packages 430 case *ast.File: 431 a.apply(n, "Doc", nil, n.Doc) 432 a.apply(n, "Name", nil, n.Name) 433 a.applyList(n, "Decls") 434 // Don't walk n.Comments; they have either been walked already if 435 // they are Doc comments, or they can be easily walked explicitly. 436 437 case *ast.Package: 438 // collect and sort names for reproducible behavior 439 var names []string 440 for name := range n.Files { 441 names = append(names, name) 442 } 443 sort.Strings(names) 444 for _, name := range names { 445 a.apply(n, name, nil, n.Files[name]) 446 } 447 448 default: 449 panic(fmt.Sprintf("Apply: unexpected node type %T", n)) 450 } 451 452 if a.post != nil && !a.post(&a.cursor) { 453 panic(abort) 454 } 455 456 a.cursor = saved 457 } 458 459 // An iterator controls iteration over a slice of nodes. 460 type iterator struct { 461 index, step int 462 } 463 464 func (a *application) applyList(parent ast.Node, name string) { 465 // avoid heap-allocating a new iterator for each applyList call; reuse a.iter instead 466 saved := a.iter 467 a.iter.index = 0 468 for { 469 // must reload parent.name each time, since cursor modifications might change it 470 v := reflect.Indirect(reflect.ValueOf(parent)).FieldByName(name) 471 if a.iter.index >= v.Len() { 472 break 473 } 474 475 // element x may be nil in a bad AST - be cautious 476 var x ast.Node 477 if e := v.Index(a.iter.index); e.IsValid() { 478 x = e.Interface().(ast.Node) 479 } 480 481 a.iter.step = 1 482 a.apply(parent, name, &a.iter, x) 483 a.iter.index += a.iter.step 484 } 485 a.iter = saved 486 }