blob: 024dea42246bc7bde5b2482135c8610497274656 [file] [log] [blame]
// 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"
"go/build"
"go/parser"
"sort"
"code.google.com/p/go.tools/call"
"code.google.com/p/go.tools/importer"
"code.google.com/p/go.tools/pointer"
"code.google.com/p/go.tools/ssa"
)
// This program demonstrates how to use the pointer analysis to
// obtain a conservative call-graph of a Go program.
//
func Example() {
const myprog = `
package main
import "fmt"
type I interface {
f()
}
type C struct{}
func (C) f() {
fmt.Println("C.f()")
}
func main() {
var i I = C{}
i.f() // dynamic method call
}
`
// Construct an importer.
// Imports will be loaded as if by 'go build'.
imp := importer.New(&importer.Config{Build: &build.Default})
// Parse the input file.
file, err := parser.ParseFile(imp.Fset, "myprog.go", myprog, 0)
if err != nil {
fmt.Print(err) // parse error
return
}
// Create single-file main package and import its dependencies.
mainInfo := imp.CreatePackage("main", file)
// Create SSA-form program representation.
var mode ssa.BuilderMode
prog := ssa.NewProgram(imp.Fset, mode)
if err := prog.CreatePackages(imp); err != nil {
fmt.Print(err) // type error in some package
return
}
mainPkg := prog.Package(mainInfo.Pkg)
// Build SSA code for bodies of all functions in the whole program.
prog.BuildAll()
// Run the pointer analysis and build the complete callgraph.
config := &pointer.Config{
Mains: []*ssa.Package{mainPkg},
BuildCallGraph: true,
}
result := pointer.Analyze(config)
// 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
call.GraphVisitEdges(result.CallGraph, func(edge call.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)
}
// Output:
// (main.C).f --> fmt.Println
// main.init --> fmt.init
// main.main --> (main.C).f
}