2019-11-07 20:05:39 +01:00
|
|
|
|
// Package lintdsl provides helpers for implementing static analysis
|
|
|
|
|
// checks. Dot-importing this package is encouraged.
|
|
|
|
|
package lintdsl
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"fmt"
|
|
|
|
|
"go/ast"
|
2020-02-26 19:46:17 +01:00
|
|
|
|
"go/format"
|
2019-11-07 20:05:39 +01:00
|
|
|
|
|
|
|
|
|
"golang.org/x/tools/go/analysis"
|
2020-02-26 19:46:17 +01:00
|
|
|
|
"honnef.co/go/tools/pattern"
|
2019-11-07 20:05:39 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func Inspect(node ast.Node, fn func(node ast.Node) bool) {
|
|
|
|
|
if node == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
ast.Inspect(node, fn)
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-26 19:46:17 +01:00
|
|
|
|
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
|
2019-11-07 20:05:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-26 19:46:17 +01:00
|
|
|
|
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
|
2019-11-07 20:05:39 +01:00
|
|
|
|
}
|
2020-02-26 19:46:17 +01:00
|
|
|
|
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
|
2019-11-07 20:05:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-26 19:46:17 +01:00
|
|
|
|
func Selector(x, sel string) *ast.SelectorExpr {
|
|
|
|
|
return &ast.SelectorExpr{
|
|
|
|
|
X: &ast.Ident{Name: x},
|
|
|
|
|
Sel: &ast.Ident{Name: sel},
|
2019-11-07 20:05:39 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-26 19:46:17 +01:00
|
|
|
|
// 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))
|
2019-11-07 20:05:39 +01:00
|
|
|
|
}
|