mirror of
https://github.com/golang/go
synced 2024-11-18 18:54:42 -07:00
go.tools/pointer: add runnable example.
Also: update TODO list. R=crawshaw CC=golang-dev https://golang.org/cl/13622043
This commit is contained in:
parent
c6e88b1b2a
commit
65f2ef9ae3
19
pointer/TODO
19
pointer/TODO
@ -4,7 +4,8 @@ Pointer analysis to-do list
|
||||
===========================
|
||||
|
||||
CONSTRAINT GENERATION:
|
||||
- reflection intrinsics
|
||||
- support reflection
|
||||
- implement native intrinsics. These vary by platform.
|
||||
- unsafe.Pointer conversions. Three options:
|
||||
1) unsoundly (but type-safely) treat p=unsafe.Pointer(x) conversions as
|
||||
allocations, losing aliases. This is what's currently implemented.
|
||||
@ -29,3 +30,19 @@ SOLVER:
|
||||
fast doubly-linked list (See Zhanh et al PLDI'13)
|
||||
(insertion order with fast membership test)
|
||||
dannyb recommends sparse bitmap.
|
||||
|
||||
API:
|
||||
- Rely less on callbacks and more on a 'result' type
|
||||
returned by Analyze().
|
||||
- Abstract the callgraph into a pure interface so that
|
||||
we can provide other implementations in future (e.g. RTA-based).
|
||||
Also provide the option to eliminate context-sensitivity
|
||||
in a callgraph to yield a smaller (less precise) callgraph.
|
||||
- Some optimisations (e.g. LE, PE) may change the API.
|
||||
Think about them sooner rather than later.
|
||||
- Eliminate Print probe now that we can query specific ssa.Values.
|
||||
|
||||
Misc:
|
||||
- os.Args should point to something; currently they don't.
|
||||
- Test on all platforms.
|
||||
Currently we assume these go/build tags: linux, amd64, !cgo.
|
||||
|
108
pointer/example_test.go
Normal file
108
pointer/example_test.go
Normal file
@ -0,0 +1,108 @@
|
||||
// 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/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, parser.DeclarationErrors)
|
||||
if err != nil {
|
||||
fmt.Print(err) // parse error
|
||||
return
|
||||
}
|
||||
|
||||
// Create a "main" package containing one file.
|
||||
mainInfo := imp.LoadMainPackage(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.
|
||||
callgraph := make(pointer.CallGraph)
|
||||
config := &pointer.Config{
|
||||
Mains: []*ssa.Package{mainPkg},
|
||||
Call: callgraph.AddEdge,
|
||||
}
|
||||
root := pointer.Analyze(config)
|
||||
|
||||
// Visit callgraph in depth-first order.
|
||||
//
|
||||
// There may be multiple nodes for the
|
||||
// same function due to context sensitivity.
|
||||
var edges []string // call edges originating from the main package.
|
||||
seen := make(map[pointer.CallGraphNode]bool)
|
||||
var visit func(cgn pointer.CallGraphNode)
|
||||
visit = func(cgn pointer.CallGraphNode) {
|
||||
if seen[cgn] {
|
||||
return // already seen
|
||||
}
|
||||
seen[cgn] = true
|
||||
caller := cgn.Func()
|
||||
for callee := range callgraph[cgn] {
|
||||
if caller.Pkg == mainPkg {
|
||||
edges = append(edges, fmt.Sprint(caller, " --> ", callee.Func()))
|
||||
}
|
||||
visit(callee)
|
||||
}
|
||||
}
|
||||
visit(root)
|
||||
|
||||
// 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user