/
query.go
120 lines (96 loc) · 2.44 KB
/
query.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package astutil
import (
"go/ast"
"go/token"
"go/types"
)
// IdentifiersInStatement returns all identifiers with their found in a statement.
func IdentifiersInStatement(pkg *types.Package, info *types.Info, stmt ast.Stmt) []ast.Expr {
w := &identifierWalker{
pkg: pkg,
info: info,
}
ast.Walk(w, stmt)
return w.identifiers
}
type identifierWalker struct {
identifiers []ast.Expr
pkg *types.Package
info *types.Info
}
func checkForSelectorExpr(node ast.Expr) bool {
switch n := node.(type) {
case *ast.Ident:
return true
case *ast.SelectorExpr:
return checkForSelectorExpr(n.X)
}
return false
}
func (w *identifierWalker) Visit(node ast.Node) ast.Visitor {
switch n := node.(type) {
case *ast.Ident:
// Ignore the blank identifier
if n.Name == "_" {
return nil
}
// Ignore keywords
if token.Lookup(n.Name) != token.IDENT {
return nil
}
// We are only interested in variables
if obj, ok := w.info.Uses[n]; ok {
if _, ok := obj.(*types.Var); !ok {
return nil
}
}
// FIXME instead of manually creating a new node, clone it and trim the node from its comments and position https://github.com/zimmski/go-mutesting/issues/49
w.identifiers = append(w.identifiers, &ast.Ident{
Name: n.Name,
})
return nil
case *ast.SelectorExpr:
if !checkForSelectorExpr(n) {
return nil
}
// Check if we need to instantiate the expression
initialize := false
if n.Sel != nil {
if obj, ok := w.info.Uses[n.Sel]; ok {
t := obj.Type()
switch t.Underlying().(type) {
case *types.Array, *types.Map, *types.Slice, *types.Struct:
initialize = true
}
}
}
if initialize {
// FIXME we need to clone the node and trim comments and position recursively https://github.com/zimmski/go-mutesting/issues/49
w.identifiers = append(w.identifiers, &ast.CompositeLit{
Type: n,
})
} else {
// FIXME we need to clone the node and trim comments and position recursively https://github.com/zimmski/go-mutesting/issues/49
w.identifiers = append(w.identifiers, n)
}
return nil
}
return w
}
// Functions returns all found functions.
func Functions(n ast.Node) []*ast.FuncDecl {
w := &functionWalker{}
ast.Walk(w, n)
return w.functions
}
type functionWalker struct {
functions []*ast.FuncDecl
}
func (w *functionWalker) Visit(node ast.Node) ast.Visitor {
switch n := node.(type) {
case *ast.FuncDecl:
w.functions = append(w.functions, n)
return nil
}
return w
}