github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/analysis/code/visit.go (about)

     1  package code
     2  
     3  import (
     4  	"bytes"
     5  	"go/ast"
     6  	"go/format"
     7  
     8  	"github.com/amarpal/go-tools/pattern"
     9  
    10  	"golang.org/x/tools/go/analysis"
    11  	"golang.org/x/tools/go/analysis/passes/inspect"
    12  	"golang.org/x/tools/go/ast/inspector"
    13  )
    14  
    15  func Preorder(pass *analysis.Pass, fn func(ast.Node), types ...ast.Node) {
    16  	pass.ResultOf[inspect.Analyzer].(*inspector.Inspector).Preorder(types, fn)
    17  }
    18  
    19  func PreorderStack(pass *analysis.Pass, fn func(ast.Node, []ast.Node), types ...ast.Node) {
    20  	pass.ResultOf[inspect.Analyzer].(*inspector.Inspector).WithStack(types, func(n ast.Node, push bool, stack []ast.Node) (proceed bool) {
    21  		if push {
    22  			fn(n, stack)
    23  		}
    24  		return true
    25  	})
    26  }
    27  
    28  func Match(pass *analysis.Pass, q pattern.Pattern, node ast.Node) (*pattern.Matcher, bool) {
    29  	// Note that we ignore q.Relevant – callers of Match usually use
    30  	// AST inspectors that already filter on nodes we're interested
    31  	// in.
    32  	m := &pattern.Matcher{TypesInfo: pass.TypesInfo}
    33  	ok := m.Match(q, node)
    34  	return m, ok
    35  }
    36  
    37  func MatchAndEdit(pass *analysis.Pass, before, after pattern.Pattern, node ast.Node) (*pattern.Matcher, []analysis.TextEdit, bool) {
    38  	m, ok := Match(pass, before, node)
    39  	if !ok {
    40  		return m, nil, false
    41  	}
    42  	r := pattern.NodeToAST(after.Root, m.State)
    43  	buf := &bytes.Buffer{}
    44  	format.Node(buf, pass.Fset, r)
    45  	edit := []analysis.TextEdit{{
    46  		Pos:     node.Pos(),
    47  		End:     node.End(),
    48  		NewText: buf.Bytes(),
    49  	}}
    50  	return m, edit, true
    51  }