Source file src/cmd/vendor/golang.org/x/tools/go/ast/inspector/cursor.go
1 // Copyright 2025 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 inspector 6 7 import ( 8 "fmt" 9 "go/ast" 10 "go/token" 11 "iter" 12 "reflect" 13 14 "golang.org/x/tools/go/ast/edge" 15 ) 16 17 // A Cursor represents an [ast.Node]. It is immutable. 18 // 19 // Two Cursors compare equal if they represent the same node. 20 // 21 // Call [Inspector.Root] to obtain a valid cursor for the virtual root 22 // node of the traversal. 23 // 24 // Use the following methods to navigate efficiently around the tree: 25 // - for ancestors, use [Cursor.Parent] and [Cursor.Enclosing]; 26 // - for children, use [Cursor.Child], [Cursor.Children], 27 // [Cursor.FirstChild], and [Cursor.LastChild]; 28 // - for siblings, use [Cursor.PrevSibling] and [Cursor.NextSibling]; 29 // - for descendants, use [Cursor.FindByPos], [Cursor.FindNode], 30 // [Cursor.Inspect], and [Cursor.Preorder]. 31 // 32 // Use the [Cursor.ChildAt] and [Cursor.ParentEdge] methods for 33 // information about the edges in a tree: which field (and slice 34 // element) of the parent node holds the child. 35 type Cursor struct { 36 in *Inspector 37 index int32 // index of push node; -1 for virtual root node 38 } 39 40 // Root returns a cursor for the virtual root node, 41 // whose children are the files provided to [New]. 42 // 43 // Its [Cursor.Node] and [Cursor.Stack] methods return nil. 44 func (in *Inspector) Root() Cursor { 45 return Cursor{in, -1} 46 } 47 48 // At returns the cursor at the specified index in the traversal, 49 // which must have been obtained from [Cursor.Index] on a Cursor 50 // belonging to the same Inspector (see [Cursor.Inspector]). 51 func (in *Inspector) At(index int32) Cursor { 52 if index < 0 { 53 panic("negative index") 54 } 55 if int(index) >= len(in.events) { 56 panic("index out of range for this inspector") 57 } 58 if in.events[index].index < index { 59 panic("invalid index") // (a push, not a pop) 60 } 61 return Cursor{in, index} 62 } 63 64 // Inspector returns the cursor's Inspector. 65 func (c Cursor) Inspector() *Inspector { return c.in } 66 67 // Index returns the index of this cursor position within the package. 68 // 69 // Clients should not assume anything about the numeric Index value 70 // except that it increases monotonically throughout the traversal. 71 // It is provided for use with [At]. 72 // 73 // Index must not be called on the Root node. 74 func (c Cursor) Index() int32 { 75 if c.index < 0 { 76 panic("Index called on Root node") 77 } 78 return c.index 79 } 80 81 // Node returns the node at the current cursor position, 82 // or nil for the cursor returned by [Inspector.Root]. 83 func (c Cursor) Node() ast.Node { 84 if c.index < 0 { 85 return nil 86 } 87 return c.in.events[c.index].node 88 } 89 90 // String returns information about the cursor's node, if any. 91 func (c Cursor) String() string { 92 if c.in == nil { 93 return "(invalid)" 94 } 95 if c.index < 0 { 96 return "(root)" 97 } 98 return reflect.TypeOf(c.Node()).String() 99 } 100 101 // indices return the [start, end) half-open interval of event indices. 102 func (c Cursor) indices() (int32, int32) { 103 if c.index < 0 { 104 return 0, int32(len(c.in.events)) // root: all events 105 } else { 106 return c.index, c.in.events[c.index].index + 1 // just one subtree 107 } 108 } 109 110 // Preorder returns an iterator over the nodes of the subtree 111 // represented by c in depth-first order. Each node in the sequence is 112 // represented by a Cursor that allows access to the Node, but may 113 // also be used to start a new traversal, or to obtain the stack of 114 // nodes enclosing the cursor. 115 // 116 // The traversal sequence is determined by [ast.Inspect]. The types 117 // argument, if non-empty, enables type-based filtering of events. The 118 // function f if is called only for nodes whose type matches an 119 // element of the types slice. 120 // 121 // If you need control over descent into subtrees, 122 // or need both pre- and post-order notifications, use [Cursor.Inspect] 123 func (c Cursor) Preorder(types ...ast.Node) iter.Seq[Cursor] { 124 mask := maskOf(types) 125 126 return func(yield func(Cursor) bool) { 127 events := c.in.events 128 129 for i, limit := c.indices(); i < limit; { 130 ev := events[i] 131 if ev.index > i { // push? 132 if ev.typ&mask != 0 && !yield(Cursor{c.in, i}) { 133 break 134 } 135 pop := ev.index 136 if events[pop].typ&mask == 0 { 137 // Subtree does not contain types: skip. 138 i = pop + 1 139 continue 140 } 141 } 142 i++ 143 } 144 } 145 } 146 147 // Inspect visits the nodes of the subtree represented by c in 148 // depth-first order. It calls f(n) for each node n before it 149 // visits n's children. If f returns true, Inspect invokes f 150 // recursively for each of the non-nil children of the node. 151 // 152 // Each node is represented by a Cursor that allows access to the 153 // Node, but may also be used to start a new traversal, or to obtain 154 // the stack of nodes enclosing the cursor. 155 // 156 // The complete traversal sequence is determined by [ast.Inspect]. 157 // The types argument, if non-empty, enables type-based filtering of 158 // events. The function f if is called only for nodes whose type 159 // matches an element of the types slice. 160 func (c Cursor) Inspect(types []ast.Node, f func(c Cursor) (descend bool)) { 161 mask := maskOf(types) 162 events := c.in.events 163 for i, limit := c.indices(); i < limit; { 164 ev := events[i] 165 if ev.index > i { 166 // push 167 pop := ev.index 168 if ev.typ&mask != 0 && !f(Cursor{c.in, i}) || 169 events[pop].typ&mask == 0 { 170 // The user opted not to descend, or the 171 // subtree does not contain types: 172 // skip past the pop. 173 i = pop + 1 174 continue 175 } 176 } 177 i++ 178 } 179 } 180 181 // Enclosing returns an iterator over the nodes enclosing the current 182 // current node, starting with the Cursor itself. 183 // 184 // Enclosing must not be called on the Root node (whose [Cursor.Node] returns nil). 185 // 186 // The types argument, if non-empty, enables type-based filtering of 187 // events: the sequence includes only enclosing nodes whose type 188 // matches an element of the types slice. 189 func (c Cursor) Enclosing(types ...ast.Node) iter.Seq[Cursor] { 190 if c.index < 0 { 191 panic("Cursor.Enclosing called on Root node") 192 } 193 194 mask := maskOf(types) 195 196 return func(yield func(Cursor) bool) { 197 events := c.in.events 198 for i := c.index; i >= 0; i = events[i].parent { 199 if events[i].typ&mask != 0 && !yield(Cursor{c.in, i}) { 200 break 201 } 202 } 203 } 204 } 205 206 // Parent returns the parent of the current node. 207 // 208 // Parent must not be called on the Root node (whose [Cursor.Node] returns nil). 209 func (c Cursor) Parent() Cursor { 210 if c.index < 0 { 211 panic("Cursor.Parent called on Root node") 212 } 213 214 return Cursor{c.in, c.in.events[c.index].parent} 215 } 216 217 // ParentEdge returns the identity of the field in the parent node 218 // that holds this cursor's node, and if it is a list, the index within it. 219 // 220 // For example, f(x, y) is a CallExpr whose three children are Idents. 221 // f has edge kind [edge.CallExpr_Fun] and index -1. 222 // x and y have kind [edge.CallExpr_Args] and indices 0 and 1, respectively. 223 // 224 // If called on a child of the Root node, it returns ([edge.Invalid], -1). 225 // 226 // ParentEdge must not be called on the Root node (whose [Cursor.Node] returns nil). 227 func (c Cursor) ParentEdge() (edge.Kind, int) { 228 if c.index < 0 { 229 panic("Cursor.ParentEdge called on Root node") 230 } 231 events := c.in.events 232 pop := events[c.index].index 233 return unpackEdgeKindAndIndex(events[pop].parent) 234 } 235 236 // ChildAt returns the cursor for the child of the 237 // current node identified by its edge and index. 238 // The index must be -1 if the edge.Kind is not a slice. 239 // The indicated child node must exist. 240 // 241 // ChildAt must not be called on the Root node (whose [Cursor.Node] returns nil). 242 // 243 // Invariant: c.Parent().ChildAt(c.ParentEdge()) == c. 244 func (c Cursor) ChildAt(k edge.Kind, idx int) Cursor { 245 target := packEdgeKindAndIndex(k, idx) 246 247 // Unfortunately there's no shortcut to looping. 248 events := c.in.events 249 i := c.index + 1 250 for { 251 pop := events[i].index 252 if pop < i { 253 break 254 } 255 if events[pop].parent == target { 256 return Cursor{c.in, i} 257 } 258 i = pop + 1 259 } 260 panic(fmt.Sprintf("ChildAt(%v, %d): no such child of %v", k, idx, c)) 261 } 262 263 // Child returns the cursor for n, which must be a direct child of c's Node. 264 // 265 // Child must not be called on the Root node (whose [Cursor.Node] returns nil). 266 func (c Cursor) Child(n ast.Node) Cursor { 267 if c.index < 0 { 268 panic("Cursor.Child called on Root node") 269 } 270 271 if false { 272 // reference implementation 273 for child := range c.Children() { 274 if child.Node() == n { 275 return child 276 } 277 } 278 279 } else { 280 // optimized implementation 281 events := c.in.events 282 for i := c.index + 1; events[i].index > i; i = events[i].index + 1 { 283 if events[i].node == n { 284 return Cursor{c.in, i} 285 } 286 } 287 } 288 panic(fmt.Sprintf("Child(%T): not a child of %v", n, c)) 289 } 290 291 // NextSibling returns the cursor for the next sibling node in the same list 292 // (for example, of files, decls, specs, statements, fields, or expressions) as 293 // the current node. It returns (zero, false) if the node is the last node in 294 // the list, or is not part of a list. 295 // 296 // NextSibling must not be called on the Root node. 297 // 298 // See note at [Cursor.Children]. 299 func (c Cursor) NextSibling() (Cursor, bool) { 300 if c.index < 0 { 301 panic("Cursor.NextSibling called on Root node") 302 } 303 304 events := c.in.events 305 i := events[c.index].index + 1 // after corresponding pop 306 if i < int32(len(events)) { 307 if events[i].index > i { // push? 308 return Cursor{c.in, i}, true 309 } 310 } 311 return Cursor{}, false 312 } 313 314 // PrevSibling returns the cursor for the previous sibling node in the 315 // same list (for example, of files, decls, specs, statements, fields, 316 // or expressions) as the current node. It returns zero if the node is 317 // the first node in the list, or is not part of a list. 318 // 319 // It must not be called on the Root node. 320 // 321 // See note at [Cursor.Children]. 322 func (c Cursor) PrevSibling() (Cursor, bool) { 323 if c.index < 0 { 324 panic("Cursor.PrevSibling called on Root node") 325 } 326 327 events := c.in.events 328 i := c.index - 1 329 if i >= 0 { 330 if j := events[i].index; j < i { // pop? 331 return Cursor{c.in, j}, true 332 } 333 } 334 return Cursor{}, false 335 } 336 337 // FirstChild returns the first direct child of the current node, 338 // or zero if it has no children. 339 func (c Cursor) FirstChild() (Cursor, bool) { 340 events := c.in.events 341 i := c.index + 1 // i=0 if c is root 342 if i < int32(len(events)) && events[i].index > i { // push? 343 return Cursor{c.in, i}, true 344 } 345 return Cursor{}, false 346 } 347 348 // LastChild returns the last direct child of the current node, 349 // or zero if it has no children. 350 func (c Cursor) LastChild() (Cursor, bool) { 351 events := c.in.events 352 if c.index < 0 { // root? 353 if len(events) > 0 { 354 // return push of final event (a pop) 355 return Cursor{c.in, events[len(events)-1].index}, true 356 } 357 } else { 358 j := events[c.index].index - 1 // before corresponding pop 359 // Inv: j == c.index if c has no children 360 // or j is last child's pop. 361 if j > c.index { // c has children 362 return Cursor{c.in, events[j].index}, true 363 } 364 } 365 return Cursor{}, false 366 } 367 368 // Children returns an iterator over the direct children of the 369 // current node, if any. 370 // 371 // When using Children, NextChild, and PrevChild, bear in mind that a 372 // Node's children may come from different fields, some of which may 373 // be lists of nodes without a distinguished intervening container 374 // such as [ast.BlockStmt]. 375 // 376 // For example, [ast.CaseClause] has a field List of expressions and a 377 // field Body of statements, so the children of a CaseClause are a mix 378 // of expressions and statements. Other nodes that have "uncontained" 379 // list fields include: 380 // 381 // - [ast.ValueSpec] (Names, Values) 382 // - [ast.CompositeLit] (Type, Elts) 383 // - [ast.IndexListExpr] (X, Indices) 384 // - [ast.CallExpr] (Fun, Args) 385 // - [ast.AssignStmt] (Lhs, Rhs) 386 // 387 // So, do not assume that the previous sibling of an ast.Stmt is also 388 // an ast.Stmt, or if it is, that they are executed sequentially, 389 // unless you have established that, say, its parent is a BlockStmt 390 // or its [Cursor.ParentEdge] is [edge.BlockStmt_List]. 391 // For example, given "for S1; ; S2 {}", the predecessor of S2 is S1, 392 // even though they are not executed in sequence. 393 func (c Cursor) Children() iter.Seq[Cursor] { 394 return func(yield func(Cursor) bool) { 395 c, ok := c.FirstChild() 396 for ok && yield(c) { 397 c, ok = c.NextSibling() 398 } 399 } 400 } 401 402 // Contains reports whether c contains or is equal to c2. 403 // 404 // Both Cursors must belong to the same [Inspector]; 405 // neither may be its Root node. 406 func (c Cursor) Contains(c2 Cursor) bool { 407 if c.in != c2.in { 408 panic("different inspectors") 409 } 410 events := c.in.events 411 return c.index <= c2.index && events[c2.index].index <= events[c.index].index 412 } 413 414 // FindNode returns the cursor for node n if it belongs to the subtree 415 // rooted at c. It returns zero if n is not found. 416 func (c Cursor) FindNode(n ast.Node) (Cursor, bool) { 417 418 // FindNode is equivalent to this code, 419 // but more convenient and 15-20% faster: 420 if false { 421 for candidate := range c.Preorder(n) { 422 if candidate.Node() == n { 423 return candidate, true 424 } 425 } 426 return Cursor{}, false 427 } 428 429 // TODO(adonovan): opt: should we assume Node.Pos is accurate 430 // and combine type-based filtering with position filtering 431 // like FindByPos? 432 433 mask := maskOf([]ast.Node{n}) 434 events := c.in.events 435 436 for i, limit := c.indices(); i < limit; i++ { 437 ev := events[i] 438 if ev.index > i { // push? 439 if ev.typ&mask != 0 && ev.node == n { 440 return Cursor{c.in, i}, true 441 } 442 pop := ev.index 443 if events[pop].typ&mask == 0 { 444 // Subtree does not contain type of n: skip. 445 i = pop 446 } 447 } 448 } 449 return Cursor{}, false 450 } 451 452 // FindByPos returns the cursor for the innermost node n in the tree 453 // rooted at c such that n.Pos() <= start && end <= n.End(). 454 // (For an *ast.File, it uses the bounds n.FileStart-n.FileEnd.) 455 // 456 // It returns zero if none is found. 457 // Precondition: start <= end. 458 // 459 // See also [astutil.PathEnclosingInterval], which 460 // tolerates adjoining whitespace. 461 func (c Cursor) FindByPos(start, end token.Pos) (Cursor, bool) { 462 if end < start { 463 panic("end < start") 464 } 465 events := c.in.events 466 467 // This algorithm could be implemented using c.Inspect, 468 // but it is about 2.5x slower. 469 470 best := int32(-1) // push index of latest (=innermost) node containing range 471 for i, limit := c.indices(); i < limit; i++ { 472 ev := events[i] 473 if ev.index > i { // push? 474 n := ev.node 475 var nodeEnd token.Pos 476 if file, ok := n.(*ast.File); ok { 477 nodeEnd = file.FileEnd 478 // Note: files may be out of Pos order. 479 if file.FileStart > start { 480 i = ev.index // disjoint, after; skip to next file 481 continue 482 } 483 } else { 484 nodeEnd = n.End() 485 if n.Pos() > start { 486 break // disjoint, after; stop 487 } 488 } 489 // Inv: node.{Pos,FileStart} <= start 490 if end <= nodeEnd { 491 // node fully contains target range 492 best = i 493 } else if nodeEnd < start { 494 i = ev.index // disjoint, before; skip forward 495 } 496 } 497 } 498 if best >= 0 { 499 return Cursor{c.in, best}, true 500 } 501 return Cursor{}, false 502 } 503