forked from zimmski/go-mutesting
-
Notifications
You must be signed in to change notification settings - Fork 1
/
walk.go
114 lines (90 loc) · 2.5 KB
/
walk.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
package mutesting
import (
"fmt"
"go/ast"
"go/types"
"strings"
"github.com/zimmski/go-mutesting/mutator"
)
// CountWalk returns the number of corresponding mutations for a given mutator.
// It traverses the AST of the given node and calls the method Check of the given mutator for every node and sums up the returned counts. After completion of the traversal the final counter is returned.
func CountWalk(pkg *types.Package, info *types.Info, node ast.Node, m mutator.Mutator) int {
w := &countWalk{
count: 0,
mutator: m,
pkg: pkg,
info: info,
}
ast.Walk(w, node)
return w.count
}
type countWalk struct {
count int
mutator mutator.Mutator
pkg *types.Package
info *types.Info
}
// Visit implements the Visit method of the ast.Visitor interface
func (w *countWalk) Visit(node ast.Node) ast.Visitor {
if node == nil {
return w
}
w.count += len(w.mutator(w.pkg, w.info, node))
return w
}
// MutateWalk mutates the given node with the given mutator returning a channel to control the mutation steps.
// It traverses the AST of the given node and calls the method Check of the given mutator to verify that a node can be mutated by the mutator. If a node can be mutated the method Mutate of the given mutator is executed with the node and the control channel. After completion of the traversal the control channel is closed.
func MutateWalk(pkg *types.Package, info *types.Info, node ast.Node, m mutator.Mutator) chan bool {
w := &mutateWalk{
changed: make(chan bool),
mutator: m,
pkg: pkg,
info: info,
}
go func() {
ast.Walk(w, node)
close(w.changed)
}()
return w.changed
}
type mutateWalk struct {
changed chan bool
mutator mutator.Mutator
pkg *types.Package
info *types.Info
}
// Visit implements the Visit method of the ast.Visitor interface
func (w *mutateWalk) Visit(node ast.Node) ast.Visitor {
if node == nil {
return w
}
for _, m := range w.mutator(w.pkg, w.info, node) {
m.Change()
w.changed <- true
<-w.changed
m.Reset()
w.changed <- true
<-w.changed
}
return w
}
// PrintWalk traverses the AST of the given node and prints every node to STDOUT.
func PrintWalk(node ast.Node) {
w := &printWalk{
level: 0,
}
ast.Walk(w, node)
}
type printWalk struct {
level int
}
// Visit implements the Visit method of the ast.Visitor interface
func (w *printWalk) Visit(node ast.Node) ast.Visitor {
if node != nil {
w.level++
fmt.Printf("%s(%p)%#v\n", strings.Repeat("\t", w.level), node, node)
} else {
w.level--
}
return w
}