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 }