1
0
mirror of https://github.com/golang/go synced 2024-11-18 21:24:44 -07:00
go/pointer/example_test.go
Alan Donovan 3d82e7e94a go.tools/ssa: fix crash in SSA builder when using GCImporter to satisfy imports (ssadump -build=G).
Packages were not being created for all types.Packages,
specifically, indirectly imported packages were missing.
(*Program).CreatePackages now iterates over the type-checker's
package map too.

Also: removed all concurrency from importer.  I think it was
incorrect (and hard to fix).

Also: change LoadInitialPackages so that all named packages
are loaded from source.  This happens regardless of whether
GCImporter is used to satisfy imports.

Details:
- importer.Config.SourceImports flag determines whether to
  load all packages from *.go source.
  (Before, this was indicated by Config.Build != nil.)
- importer.Config.Build field effectively defaults to
  &go/build.Default.  A zero importer.Config is now usable.
- importer.Importer.Config field is now exported.
- LoadPackage renamed to ImportPackage since the resulting
  packages may come from GCImporter (and be incomplete).
- doImport and ImportPackage fused.

Fixes golang/go#7028

R=gri, axwalk
CC=golang-codereviews
https://golang.org/cl/48770043
2014-01-09 14:11:54 -05:00

97 lines
2.2 KiB
Go

// 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/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.
imp := importer.New(&importer.Config{SourceImports: true})
// 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
}