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