--- /dev/null
+package code
+
+import (
+ "bytes"
+ "go/ast"
+ "go/format"
+
+ "honnef.co/go/tools/pattern"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/ast/inspector"
+)
+
+func Preorder(pass *analysis.Pass, fn func(ast.Node), types ...ast.Node) {
+ pass.ResultOf[inspect.Analyzer].(*inspector.Inspector).Preorder(types, fn)
+}
+
+func PreorderStack(pass *analysis.Pass, fn func(ast.Node, []ast.Node), types ...ast.Node) {
+ pass.ResultOf[inspect.Analyzer].(*inspector.Inspector).WithStack(types, func(n ast.Node, push bool, stack []ast.Node) (proceed bool) {
+ if push {
+ fn(n, stack)
+ }
+ return true
+ })
+}
+
+func Match(pass *analysis.Pass, q pattern.Pattern, node ast.Node) (*pattern.Matcher, bool) {
+ // Note that we ignore q.Relevant – callers of Match usually use
+ // AST inspectors that already filter on nodes we're interested
+ // in.
+ m := &pattern.Matcher{TypesInfo: pass.TypesInfo}
+ ok := m.Match(q.Root, node)
+ return m, ok
+}
+
+func MatchAndEdit(pass *analysis.Pass, before, after pattern.Pattern, node ast.Node) (*pattern.Matcher, []analysis.TextEdit, bool) {
+ m, ok := Match(pass, before, node)
+ if !ok {
+ return m, nil, false
+ }
+ r := pattern.NodeToAST(after.Root, m.State)
+ buf := &bytes.Buffer{}
+ format.Node(buf, pass.Fset, r)
+ edit := []analysis.TextEdit{{
+ Pos: node.Pos(),
+ End: node.End(),
+ NewText: buf.Bytes(),
+ }}
+ return m, edit, true
+}