github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/pointer/example_test.go (about) 1 // Copyright 2013 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 pointer_test 6 7 import ( 8 "fmt" 9 "sort" 10 11 "github.com/powerman/golang-tools/go/callgraph" 12 "github.com/powerman/golang-tools/go/loader" 13 "github.com/powerman/golang-tools/go/pointer" 14 "github.com/powerman/golang-tools/go/ssa" 15 "github.com/powerman/golang-tools/go/ssa/ssautil" 16 ) 17 18 // This program demonstrates how to use the pointer analysis to 19 // obtain a conservative call-graph of a Go program. 20 // It also shows how to compute the points-to set of a variable, 21 // in this case, (C).f's ch parameter. 22 // 23 func Example() { 24 const myprog = ` 25 package main 26 27 import "fmt" 28 29 type I interface { 30 f(map[string]int) 31 } 32 33 type C struct{} 34 35 func (C) f(m map[string]int) { 36 fmt.Println("C.f()") 37 } 38 39 func main() { 40 var i I = C{} 41 x := map[string]int{"one":1} 42 i.f(x) // dynamic method call 43 } 44 ` 45 var conf loader.Config 46 47 // Parse the input file, a string. 48 // (Command-line tools should use conf.FromArgs.) 49 file, err := conf.ParseFile("myprog.go", myprog) 50 if err != nil { 51 fmt.Print(err) // parse error 52 return 53 } 54 55 // Create single-file main package and import its dependencies. 56 conf.CreateFromFiles("main", file) 57 58 iprog, err := conf.Load() 59 if err != nil { 60 fmt.Print(err) // type error in some package 61 return 62 } 63 64 // Create SSA-form program representation. 65 prog := ssautil.CreateProgram(iprog, 0) 66 mainPkg := prog.Package(iprog.Created[0].Pkg) 67 68 // Build SSA code for bodies of all functions in the whole program. 69 prog.Build() 70 71 // Configure the pointer analysis to build a call-graph. 72 config := &pointer.Config{ 73 Mains: []*ssa.Package{mainPkg}, 74 BuildCallGraph: true, 75 } 76 77 // Query points-to set of (C).f's parameter m, a map. 78 C := mainPkg.Type("C").Type() 79 Cfm := prog.LookupMethod(C, mainPkg.Pkg, "f").Params[1] 80 config.AddQuery(Cfm) 81 82 // Run the pointer analysis. 83 result, err := pointer.Analyze(config) 84 if err != nil { 85 panic(err) // internal error in pointer analysis 86 } 87 88 // Find edges originating from the main package. 89 // By converting to strings, we de-duplicate nodes 90 // representing the same function due to context sensitivity. 91 var edges []string 92 callgraph.GraphVisitEdges(result.CallGraph, func(edge *callgraph.Edge) error { 93 caller := edge.Caller.Func 94 if caller.Pkg == mainPkg { 95 edges = append(edges, fmt.Sprint(caller, " --> ", edge.Callee.Func)) 96 } 97 return nil 98 }) 99 100 // Print the edges in sorted order. 101 sort.Strings(edges) 102 for _, edge := range edges { 103 fmt.Println(edge) 104 } 105 fmt.Println() 106 107 // Print the labels of (C).f(m)'s points-to set. 108 fmt.Println("m may point to:") 109 var labels []string 110 for _, l := range result.Queries[Cfm].PointsTo().Labels() { 111 label := fmt.Sprintf(" %s: %s", prog.Fset.Position(l.Pos()), l) 112 labels = append(labels, label) 113 } 114 sort.Strings(labels) 115 for _, label := range labels { 116 fmt.Println(label) 117 } 118 119 // Output: 120 // (main.C).f --> fmt.Println 121 // main.init --> fmt.init 122 // main.main --> (main.C).f 123 // 124 // m may point to: 125 // myprog.go:18:21: makemap 126 }