--- /dev/null
+// Package lintdsl provides helpers for implementing static analysis
+// checks. Dot-importing this package is encouraged.
+package lintdsl
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/format"
+
+ "golang.org/x/tools/go/analysis"
+ "honnef.co/go/tools/pattern"
+)
+
+func Inspect(node ast.Node, fn func(node ast.Node) bool) {
+ if node == nil {
+ return
+ }
+ ast.Inspect(node, fn)
+}
+
+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
+}
+
+func Selector(x, sel string) *ast.SelectorExpr {
+ return &ast.SelectorExpr{
+ X: &ast.Ident{Name: x},
+ Sel: &ast.Ident{Name: sel},
+ }
+}
+
+// ExhaustiveTypeSwitch panics when called. It can be used to ensure
+// that type switches are exhaustive.
+func ExhaustiveTypeSwitch(v interface{}) {
+ panic(fmt.Sprintf("internal error: unhandled case %T", v))
+}