github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/callgraph/vta/helpers_test.go (about) 1 // Copyright 2021 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 vta 6 7 import ( 8 "fmt" 9 "go/ast" 10 "go/parser" 11 "io/ioutil" 12 "sort" 13 "strings" 14 15 "github.com/powerman/golang-tools/go/callgraph" 16 "github.com/powerman/golang-tools/go/ssa/ssautil" 17 18 "github.com/powerman/golang-tools/go/loader" 19 "github.com/powerman/golang-tools/go/ssa" 20 ) 21 22 // want extracts the contents of the first comment 23 // section starting with "WANT:\n". The returned 24 // content is split into lines without // prefix. 25 func want(f *ast.File) []string { 26 for _, c := range f.Comments { 27 text := strings.TrimSpace(c.Text()) 28 if t := strings.TrimPrefix(text, "WANT:\n"); t != text { 29 return strings.Split(t, "\n") 30 } 31 } 32 return nil 33 } 34 35 // testProg returns an ssa representation of a program at 36 // `path`, assumed to define package "testdata," and the 37 // test want result as list of strings. 38 func testProg(path string) (*ssa.Program, []string, error) { 39 content, err := ioutil.ReadFile(path) 40 if err != nil { 41 return nil, nil, err 42 } 43 44 conf := loader.Config{ 45 ParserMode: parser.ParseComments, 46 } 47 48 f, err := conf.ParseFile(path, content) 49 if err != nil { 50 return nil, nil, err 51 } 52 53 conf.CreateFromFiles("testdata", f) 54 iprog, err := conf.Load() 55 if err != nil { 56 return nil, nil, err 57 } 58 59 prog := ssautil.CreateProgram(iprog, 0) 60 // Set debug mode to exercise DebugRef instructions. 61 prog.Package(iprog.Created[0].Pkg).SetDebugMode(true) 62 prog.Build() 63 return prog, want(f), nil 64 } 65 66 func firstRegInstr(f *ssa.Function) ssa.Value { 67 for _, b := range f.Blocks { 68 for _, i := range b.Instrs { 69 if v, ok := i.(ssa.Value); ok { 70 return v 71 } 72 } 73 } 74 return nil 75 } 76 77 // funcName returns a name of the function `f` 78 // prefixed with the name of the receiver type. 79 func funcName(f *ssa.Function) string { 80 recv := f.Signature.Recv() 81 if recv == nil { 82 return f.Name() 83 } 84 tp := recv.Type().String() 85 return tp[strings.LastIndex(tp, ".")+1:] + "." + f.Name() 86 } 87 88 // callGraphStr stringifes `g` into a list of strings where 89 // each entry is of the form 90 // f: cs1 -> f1, f2, ...; ...; csw -> fx, fy, ... 91 // f is a function, cs1, ..., csw are call sites in f, and 92 // f1, f2, ..., fx, fy, ... are the resolved callees. 93 func callGraphStr(g *callgraph.Graph) []string { 94 var gs []string 95 for f, n := range g.Nodes { 96 c := make(map[string][]string) 97 for _, edge := range n.Out { 98 cs := edge.Site.String() 99 c[cs] = append(c[cs], funcName(edge.Callee.Func)) 100 } 101 102 var cs []string 103 for site, fs := range c { 104 sort.Strings(fs) 105 entry := fmt.Sprintf("%v -> %v", site, strings.Join(fs, ", ")) 106 cs = append(cs, entry) 107 } 108 109 sort.Strings(cs) 110 entry := fmt.Sprintf("%v: %v", funcName(f), strings.Join(cs, "; ")) 111 gs = append(gs, entry) 112 } 113 return gs 114 }