github.com/mshitrit/go-mutesting@v0.0.0-20210528084812-ff81dcaedfea/walk.go (about) 1 package mutesting 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/types" 7 "strings" 8 9 "github.com/zimmski/go-mutesting/mutator" 10 ) 11 12 // CountWalk returns the number of corresponding mutations for a given mutator. 13 // 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. 14 func CountWalk(pkg *types.Package, info *types.Info, node ast.Node, m mutator.Mutator) int { 15 w := &countWalk{ 16 count: 0, 17 mutator: m, 18 pkg: pkg, 19 info: info, 20 } 21 22 ast.Walk(w, node) 23 24 return w.count 25 } 26 27 type countWalk struct { 28 count int 29 mutator mutator.Mutator 30 pkg *types.Package 31 info *types.Info 32 } 33 34 // Visit implements the Visit method of the ast.Visitor interface 35 func (w *countWalk) Visit(node ast.Node) ast.Visitor { 36 if node == nil { 37 return w 38 } 39 40 w.count += len(w.mutator(w.pkg, w.info, node)) 41 42 return w 43 } 44 45 // MutateWalk mutates the given node with the given mutator returning a channel to control the mutation steps. 46 // 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. 47 func MutateWalk(pkg *types.Package, info *types.Info, node ast.Node, m mutator.Mutator) chan bool { 48 w := &mutateWalk{ 49 changed: make(chan bool), 50 mutator: m, 51 pkg: pkg, 52 info: info, 53 } 54 55 go func() { 56 ast.Walk(w, node) 57 58 close(w.changed) 59 }() 60 61 return w.changed 62 } 63 64 type mutateWalk struct { 65 changed chan bool 66 mutator mutator.Mutator 67 pkg *types.Package 68 info *types.Info 69 } 70 71 // Visit implements the Visit method of the ast.Visitor interface 72 func (w *mutateWalk) Visit(node ast.Node) ast.Visitor { 73 if node == nil { 74 return w 75 } 76 77 for _, m := range w.mutator(w.pkg, w.info, node) { 78 m.Change() 79 w.changed <- true 80 <-w.changed 81 82 m.Reset() 83 w.changed <- true 84 <-w.changed 85 } 86 87 return w 88 } 89 90 // PrintWalk traverses the AST of the given node and prints every node to STDOUT. 91 func PrintWalk(node ast.Node) { 92 w := &printWalk{ 93 level: 0, 94 } 95 96 ast.Walk(w, node) 97 } 98 99 type printWalk struct { 100 level int 101 } 102 103 // Visit implements the Visit method of the ast.Visitor interface 104 func (w *printWalk) Visit(node ast.Node) ast.Visitor { 105 if node != nil { 106 w.level++ 107 108 fmt.Printf("%s(%p)%#v\n", strings.Repeat("\t", w.level), node, node) 109 } else { 110 w.level-- 111 } 112 113 return w 114 }