github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/callgraph/rta/rta_test.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package rta_test 6 7 import ( 8 "bytes" 9 "fmt" 10 "go/ast" 11 "go/parser" 12 "go/token" 13 "io/ioutil" 14 "sort" 15 "strings" 16 "testing" 17 18 "llvm.org/llgo/third_party/gotools/go/callgraph" 19 "llvm.org/llgo/third_party/gotools/go/callgraph/rta" 20 "llvm.org/llgo/third_party/gotools/go/loader" 21 "llvm.org/llgo/third_party/gotools/go/ssa" 22 "llvm.org/llgo/third_party/gotools/go/types" 23 ) 24 25 var inputs = []string{ 26 "testdata/func.go", 27 "testdata/rtype.go", 28 "testdata/iface.go", 29 } 30 31 func expectation(f *ast.File) (string, token.Pos) { 32 for _, c := range f.Comments { 33 text := strings.TrimSpace(c.Text()) 34 if t := strings.TrimPrefix(text, "WANT:\n"); t != text { 35 return t, c.Pos() 36 } 37 } 38 return "", token.NoPos 39 } 40 41 // TestRTA runs RTA on each file in inputs, prints the results, and 42 // compares it with the golden results embedded in the WANT comment at 43 // the end of the file. 44 // 45 // The results string consists of two parts: the set of dynamic call 46 // edges, "f --> g", one per line, and the set of reachable functions, 47 // one per line. Each set is sorted. 48 // 49 func TestRTA(t *testing.T) { 50 for _, filename := range inputs { 51 content, err := ioutil.ReadFile(filename) 52 if err != nil { 53 t.Errorf("couldn't read file '%s': %s", filename, err) 54 continue 55 } 56 57 conf := loader.Config{ 58 ParserMode: parser.ParseComments, 59 } 60 f, err := conf.ParseFile(filename, content) 61 if err != nil { 62 t.Error(err) 63 continue 64 } 65 66 want, pos := expectation(f) 67 if pos == token.NoPos { 68 t.Errorf("No WANT: comment in %s", filename) 69 continue 70 } 71 72 conf.CreateFromFiles("main", f) 73 iprog, err := conf.Load() 74 if err != nil { 75 t.Error(err) 76 continue 77 } 78 79 prog := ssa.Create(iprog, 0) 80 mainPkg := prog.Package(iprog.Created[0].Pkg) 81 prog.BuildAll() 82 83 res := rta.Analyze([]*ssa.Function{ 84 mainPkg.Func("main"), 85 mainPkg.Func("init"), 86 }, true) 87 88 if got := printResult(res, mainPkg.Object); got != want { 89 t.Errorf("%s: got:\n%s\nwant:\n%s", 90 prog.Fset.Position(pos), got, want) 91 } 92 } 93 } 94 95 func printResult(res *rta.Result, from *types.Package) string { 96 var buf bytes.Buffer 97 98 writeSorted := func(ss []string) { 99 sort.Strings(ss) 100 for _, s := range ss { 101 fmt.Fprintf(&buf, " %s\n", s) 102 } 103 } 104 105 buf.WriteString("Dynamic calls\n") 106 var edges []string 107 callgraph.GraphVisitEdges(res.CallGraph, func(e *callgraph.Edge) error { 108 if strings.Contains(e.Description(), "dynamic") { 109 edges = append(edges, fmt.Sprintf("%s --> %s", 110 e.Caller.Func.RelString(from), 111 e.Callee.Func.RelString(from))) 112 } 113 return nil 114 }) 115 writeSorted(edges) 116 117 buf.WriteString("Reachable functions\n") 118 var reachable []string 119 for f := range res.Reachable { 120 reachable = append(reachable, f.RelString(from)) 121 } 122 writeSorted(reachable) 123 124 buf.WriteString("Reflect types\n") 125 var rtypes []string 126 res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) { 127 if value == false { // accessible to reflection 128 rtypes = append(rtypes, types.TypeString(from, key)) 129 } 130 }) 131 writeSorted(rtypes) 132 133 return strings.TrimSpace(buf.String()) 134 }