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.
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"
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.
35 func (C) f(m map[string]int) {
41 x := map[string]int{"one":1}
42 i.f(x) // dynamic method call
45 var conf loader.Config
47 // Parse the input file, a string.
48 // (Command-line tools should use conf.FromArgs.)
49 file, err := conf.ParseFile("myprog.go", myprog)
51 fmt.Print(err) // parse error
55 // Create single-file main package and import its dependencies.
56 conf.CreateFromFiles("main", file)
58 iprog, err := conf.Load()
60 fmt.Print(err) // type error in some package
64 // Create SSA-form program representation.
65 prog := ssautil.CreateProgram(iprog, 0)
66 mainPkg := prog.Package(iprog.Created[0].Pkg)
68 // Build SSA code for bodies of all functions in the whole program.
71 // Configure the pointer analysis to build a call-graph.
72 config := &pointer.Config{
73 Mains: []*ssa.Package{mainPkg},
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]
82 // Run the pointer analysis.
83 result, err := pointer.Analyze(config)
85 panic(err) // internal error in pointer analysis
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.
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))
100 // Print the edges in sorted order.
102 for _, edge := range edges {
107 // Print the labels of (C).f(m)'s points-to set.
108 fmt.Println("m may point to:")
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)
115 for _, label := range labels {
120 // (main.C).f --> fmt.Println
121 // main.init --> fmt.init
122 // main.main --> (main.C).f
125 // myprog.go:18:21: makemap