visit.go 1.4 KB

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