+++ /dev/null
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package pointer_test
-
-import (
- "fmt"
- "sort"
-
- "golang.org/x/tools/go/callgraph"
- "golang.org/x/tools/go/loader"
- "golang.org/x/tools/go/pointer"
- "golang.org/x/tools/go/ssa"
- "golang.org/x/tools/go/ssa/ssautil"
-)
-
-// This program demonstrates how to use the pointer analysis to
-// obtain a conservative call-graph of a Go program.
-// It also shows how to compute the points-to set of a variable,
-// in this case, (C).f's ch parameter.
-//
-func Example() {
- const myprog = `
-package main
-
-import "fmt"
-
-type I interface {
- f(map[string]int)
-}
-
-type C struct{}
-
-func (C) f(m map[string]int) {
- fmt.Println("C.f()")
-}
-
-func main() {
- var i I = C{}
- x := map[string]int{"one":1}
- i.f(x) // dynamic method call
-}
-`
- var conf loader.Config
-
- // Parse the input file, a string.
- // (Command-line tools should use conf.FromArgs.)
- file, err := conf.ParseFile("myprog.go", myprog)
- if err != nil {
- fmt.Print(err) // parse error
- return
- }
-
- // Create single-file main package and import its dependencies.
- conf.CreateFromFiles("main", file)
-
- iprog, err := conf.Load()
- if err != nil {
- fmt.Print(err) // type error in some package
- return
- }
-
- // Create SSA-form program representation.
- prog := ssautil.CreateProgram(iprog, 0)
- mainPkg := prog.Package(iprog.Created[0].Pkg)
-
- // Build SSA code for bodies of all functions in the whole program.
- prog.Build()
-
- // Configure the pointer analysis to build a call-graph.
- config := &pointer.Config{
- Mains: []*ssa.Package{mainPkg},
- BuildCallGraph: true,
- }
-
- // Query points-to set of (C).f's parameter m, a map.
- C := mainPkg.Type("C").Type()
- Cfm := prog.LookupMethod(C, mainPkg.Pkg, "f").Params[1]
- config.AddQuery(Cfm)
-
- // Run the pointer analysis.
- result, err := pointer.Analyze(config)
- if err != nil {
- panic(err) // internal error in pointer analysis
- }
-
- // Find edges originating from the main package.
- // By converting to strings, we de-duplicate nodes
- // representing the same function due to context sensitivity.
- var edges []string
- callgraph.GraphVisitEdges(result.CallGraph, func(edge *callgraph.Edge) error {
- caller := edge.Caller.Func
- if caller.Pkg == mainPkg {
- edges = append(edges, fmt.Sprint(caller, " --> ", edge.Callee.Func))
- }
- return nil
- })
-
- // Print the edges in sorted order.
- sort.Strings(edges)
- for _, edge := range edges {
- fmt.Println(edge)
- }
- fmt.Println()
-
- // Print the labels of (C).f(m)'s points-to set.
- fmt.Println("m may point to:")
- var labels []string
- for _, l := range result.Queries[Cfm].PointsTo().Labels() {
- label := fmt.Sprintf(" %s: %s", prog.Fset.Position(l.Pos()), l)
- labels = append(labels, label)
- }
- sort.Strings(labels)
- for _, label := range labels {
- fmt.Println(label)
- }
-
- // Output:
- // (main.C).f --> fmt.Println
- // main.init --> fmt.init
- // main.main --> (main.C).f
- //
- // m may point to:
- // myprog.go:18:21: makemap
-}