visit.go raw

   1  package code
   2  
   3  import (
   4  	"bytes"
   5  	"go/ast"
   6  	"go/format"
   7  
   8  	"honnef.co/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  }
  52