Source file src/cmd/vendor/golang.org/x/tools/go/ast/inspector/iter.go

     1  // Copyright 2024 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  //go:build go1.23
     6  
     7  package inspector
     8  
     9  import (
    10  	"go/ast"
    11  	"iter"
    12  )
    13  
    14  // PreorderSeq returns an iterator that visits all the
    15  // nodes of the files supplied to [New] in depth-first order.
    16  // It visits each node n before n's children.
    17  // The complete traversal sequence is determined by ast.Inspect.
    18  //
    19  // The types argument, if non-empty, enables type-based filtering:
    20  // only nodes whose type matches an element of the types slice are
    21  // included in the sequence.
    22  //
    23  // Example:
    24  //
    25  //	for call := range in.PreorderSeq((*ast.CallExpr)(nil)) { ... }
    26  //
    27  // The [All] function is more convenient if there is exactly one node type:
    28  //
    29  //	for call := range All[*ast.CallExpr](in) { ... }
    30  //
    31  // See also the newer and more flexible [Cursor] API, which lets you
    32  // start the traversal at an arbitrary node, and reports each matching
    33  // node by its Cursor, enabling easier navigation.
    34  // The above example would be written thus:
    35  //
    36  //	for curCall := range in.Root().Preorder((*ast.CallExpr)(nil)) {
    37  //		call := curCall.Node().(*ast.CallExpr)
    38  //		...
    39  //	}
    40  func (in *Inspector) PreorderSeq(types ...ast.Node) iter.Seq[ast.Node] {
    41  
    42  	// This implementation is identical to Preorder,
    43  	// except that it supports breaking out of the loop.
    44  
    45  	return func(yield func(ast.Node) bool) {
    46  		mask := maskOf(types)
    47  		for i := int32(0); i < int32(len(in.events)); {
    48  			ev := in.events[i]
    49  			if ev.index > i {
    50  				// push
    51  				if ev.typ&mask != 0 {
    52  					if !yield(ev.node) {
    53  						break
    54  					}
    55  				}
    56  				pop := ev.index
    57  				if in.events[pop].typ&mask == 0 {
    58  					// Subtrees do not contain types: skip them and pop.
    59  					i = pop + 1
    60  					continue
    61  				}
    62  			}
    63  			i++
    64  		}
    65  	}
    66  }
    67  
    68  // All[N] returns an iterator over all the nodes of type N.
    69  // N must be a pointer-to-struct type that implements ast.Node.
    70  //
    71  // Example:
    72  //
    73  //	for call := range All[*ast.CallExpr](in) { ... }
    74  //
    75  // See also the newer and more flexible [Cursor] API, which lets you
    76  // start the traversal at an arbitrary node, and reports each matching
    77  // node by its Cursor, enabling easier navigation.
    78  // The above example would be written thus:
    79  //
    80  //	for curCall := range in.Root().Preorder((*ast.CallExpr)(nil)) {
    81  //		call := curCall.Node().(*ast.CallExpr)
    82  //		...
    83  //	}
    84  func All[N interface {
    85  	*S
    86  	ast.Node
    87  }, S any](in *Inspector) iter.Seq[N] {
    88  
    89  	// To avoid additional dynamic call overheads,
    90  	// we duplicate rather than call the logic of PreorderSeq.
    91  
    92  	mask := typeOf((N)(nil))
    93  	return func(yield func(N) bool) {
    94  		for i := int32(0); i < int32(len(in.events)); {
    95  			ev := in.events[i]
    96  			if ev.index > i {
    97  				// push
    98  				if ev.typ&mask != 0 {
    99  					if !yield(ev.node.(N)) {
   100  						break
   101  					}
   102  				}
   103  				pop := ev.index
   104  				if in.events[pop].typ&mask == 0 {
   105  					// Subtrees do not contain types: skip them and pop.
   106  					i = pop + 1
   107  					continue
   108  				}
   109  			}
   110  			i++
   111  		}
   112  	}
   113  }
   114  

View as plain text