mirror of
https://github.com/golang/go
synced 2024-11-18 21:24:44 -07:00
3d82e7e94a
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
97 lines
2.2 KiB
Go
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
|
|
}
|