作者:4hono
项目:obd
func TestSwitches(t *testing.T) {
conf := loader.Config{ParserMode: parser.ParseComments}
f, err := conf.ParseFile("testdata/switches.go", nil)
if err != nil {
t.Error(err)
return
}
conf.CreateFromFiles("main", f)
iprog, err := conf.Load()
if err != nil {
t.Error(err)
return
}
prog := ssa.Create(iprog, 0)
mainPkg := prog.Package(iprog.Created[0].Pkg)
mainPkg.Build()
for _, mem := range mainPkg.Members {
if fn, ok := mem.(*ssa.Function); ok {
if fn.Synthetic != "" {
continue // e.g. init()
}
// Each (multi-line) "switch" comment within
// this function must match the printed form
// of a ConstSwitch.
var wantSwitches []string
for _, c := range f.Comments {
if fn.Syntax().Pos() <= c.Pos() && c.Pos() < fn.Syntax().End() {
text := strings.TrimSpace(c.Text())
if strings.HasPrefix(text, "switch ") {
wantSwitches = append(wantSwitches, text)
}
}
}
switches := ssautil.Switches(fn)
if len(switches) != len(wantSwitches) {
t.Errorf("in %s, found %d switches, want %d", fn, len(switches), len(wantSwitches))
}
for i, sw := range switches {
got := sw.String()
if i >= len(wantSwitches) {
continue
}
want := wantSwitches[i]
if got != want {
t.Errorf("in %s, found switch %d: got <<%s>>, want <<%s>>", fn, i, got, want)
}
}
}
}
}
作者:4hono
项目:obd
func create(t *testing.T, content string) []*ssa.Package {
var conf loader.Config
f, err := conf.ParseFile("foo_test.go", content)
if err != nil {
t.Fatal(err)
}
conf.CreateFromFiles("foo", f)
iprog, err := conf.Load()
if err != nil {
t.Fatal(err)
}
// We needn't call Build.
return ssa.Create(iprog, ssa.SanityCheckFunctions).AllPackages()
}
作者:4hono
项目:obd
func newOracle(iprog *loader.Program, ptalog io.Writer, needs int, reflection bool) (*Oracle, error) {
o := &Oracle{fset: iprog.Fset}
// Retain type info for all ASTs in the program.
if needs&needRetainTypeInfo != 0 {
o.typeInfo = iprog.AllPackages
}
// Create SSA package for the initial packages and their dependencies.
if needs&needSSA != 0 {
var mode ssa.BuilderMode
if needs&needSSADebug != 0 {
mode |= ssa.GlobalDebug
}
prog := ssa.Create(iprog, mode)
// For each initial package (specified on the command line),
// if it has a main function, analyze that,
// otherwise analyze its tests, if any.
var testPkgs, mains []*ssa.Package
for _, info := range iprog.InitialPackages() {
initialPkg := prog.Package(info.Pkg)
// Add package to the pointer analysis scope.
if initialPkg.Func("main") != nil {
mains = append(mains, initialPkg)
} else {
testPkgs = append(testPkgs, initialPkg)
}
}
if testPkgs != nil {
if p := prog.CreateTestMainPackage(testPkgs...); p != nil {
mains = append(mains, p)
}
}
if mains == nil {
return nil, fmt.Errorf("analysis scope has no main and no tests")
}
o.ptaConfig.Log = ptalog
o.ptaConfig.Reflection = reflection
o.ptaConfig.Mains = mains
o.prog = prog
}
return o, nil
}
作者:bryanx
项目:go-zh.tool
// CreateTestMainPackage should return nil if there were no tests.
func TestNullTestmainPackage(t *testing.T) {
var conf loader.Config
if err := conf.CreateFromFilenames("", "testdata/b_test.go"); err != nil {
t.Fatalf("ParseFile failed: %s", err)
}
iprog, err := conf.Load()
if err != nil {
t.Fatalf("CreatePackages failed: %s", err)
}
prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
mainPkg := prog.Package(iprog.Created[0].Pkg)
if mainPkg.Func("main") != nil {
t.Fatalf("unexpected main function")
}
if prog.CreateTestMainPackage(mainPkg) != nil {
t.Fatalf("CreateTestMainPackage returned non-nil")
}
}
作者:Karthikv
项目:15640_project
// TestTypesWithMethodSets tests that Package.TypesWithMethodSets includes all necessary types.
func TestTypesWithMethodSets(t *testing.T) {
tests := []struct {
input string
want []string
}{
// An exported package-level type is needed.
{`package A; type T struct{}; func (T) f() {}`,
[]string{"*p.T", "p.T"},
},
// An unexported package-level type is not needed.
{`package B; type t struct{}; func (t) f() {}`,
nil,
},
// Subcomponents of type of exported package-level var are needed.
{`package C; import "bytes"; var V struct {*bytes.Buffer}`,
[]string{"*struct{*bytes.Buffer}", "struct{*bytes.Buffer}"},
},
// Subcomponents of type of unexported package-level var are not needed.
{`package D; import "bytes"; var v struct {*bytes.Buffer}`,
nil,
},
// Subcomponents of type of exported package-level function are needed.
{`package E; import "bytes"; func F(struct {*bytes.Buffer}) {}`,
[]string{"struct{*bytes.Buffer}"},
},
// Subcomponents of type of unexported package-level function are not needed.
{`package F; import "bytes"; func f(struct {*bytes.Buffer}) {}`,
nil,
},
// Subcomponents of type of exported method of uninstantiated unexported type are not needed.
{`package G; import "bytes"; type x struct{}; func (x) G(struct {*bytes.Buffer}) {}; var v x`,
nil,
},
// ...unless used by MakeInterface.
{`package G2; import "bytes"; type x struct{}; func (x) G(struct {*bytes.Buffer}) {}; var v interface{} = x{}`,
[]string{"*p.x", "p.x", "struct{*bytes.Buffer}"},
},
// Subcomponents of type of unexported method are not needed.
{`package I; import "bytes"; type X struct{}; func (X) G(struct {*bytes.Buffer}) {}`,
[]string{"*p.X", "p.X", "struct{*bytes.Buffer}"},
},
// Local types aren't needed.
{`package J; import "bytes"; func f() { type T struct {*bytes.Buffer}; var t T; _ = t }`,
nil,
},
// ...unless used by MakeInterface.
{`package K; import "bytes"; func f() { type T struct {*bytes.Buffer}; _ = interface{}(T{}) }`,
[]string{"*p.T", "p.T"},
},
// Types used as operand of MakeInterface are needed.
{`package L; import "bytes"; func f() { _ = interface{}(struct{*bytes.Buffer}{}) }`,
[]string{"struct{*bytes.Buffer}"},
},
// MakeInterface is optimized away when storing to a blank.
{`package M; import "bytes"; var _ interface{} = struct{*bytes.Buffer}{}`,
nil,
},
}
for _, test := range tests {
// Create a single-file main package.
var conf loader.Config
f, err := conf.ParseFile("<input>", test.input, 0)
if err != nil {
t.Errorf("test %q: %s", test.input[:15], err)
continue
}
conf.CreateFromFiles("p", f)
iprog, err := conf.Load()
if err != nil {
t.Errorf("test 'package %s': Load: %s", f.Name.Name, err)
continue
}
prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
mainPkg := prog.Package(iprog.Created[0].Pkg)
prog.BuildAll()
var typstrs []string
for _, T := range mainPkg.TypesWithMethodSets() {
typstrs = append(typstrs, T.String())
}
sort.Strings(typstrs)
if !reflect.DeepEqual(typstrs, test.want) {
t.Errorf("test 'package %s': got %q, want %q", f.Name.Name, typstrs, test.want)
}
}
}
作者:hackrol
项目:daily-progra
func TestObjValueLookup(t *testing.T) {
conf := loader.Config{ParserMode: parser.ParseComments}
f, err := conf.ParseFile("testdata/objlookup.go", nil)
if err != nil {
t.Error(err)
return
}
conf.CreateFromFiles("main", f)
// Maps each var Ident (represented "name:linenum") to the
// kind of ssa.Value we expect (represented "Constant", "&Alloc").
expectations := make(map[string]string)
// Find all annotations of form x::BinOp, &y::Alloc, etc.
re := regexp.MustCompile(`(\b|&)?(\w*)::(\w*)\b`)
for _, c := range f.Comments {
text := c.Text()
pos := conf.Fset.Position(c.Pos())
for _, m := range re.FindAllStringSubmatch(text, -1) {
key := fmt.Sprintf("%s:%d", m[2], pos.Line)
value := m[1] + m[3]
expectations[key] = value
}
}
iprog, err := conf.Load()
if err != nil {
t.Error(err)
return
}
prog := ssa.Create(iprog, 0 /*|ssa.LogFunctions*/)
mainInfo := iprog.Created[0]
mainPkg := prog.Package(mainInfo.Pkg)
mainPkg.SetDebugMode(true)
mainPkg.Build()
var varIds []*ast.Ident
var varObjs []*types.Var
for id, obj := range mainInfo.Defs {
// Check invariants for func and const objects.
switch obj := obj.(type) {
case *types.Func:
checkFuncValue(t, prog, obj)
case *types.Const:
checkConstValue(t, prog, obj)
case *types.Var:
if id.Name == "_" {
continue
}
varIds = append(varIds, id)
varObjs = append(varObjs, obj)
}
}
for id, obj := range mainInfo.Uses {
if obj, ok := obj.(*types.Var); ok {
varIds = append(varIds, id)
varObjs = append(varObjs, obj)
}
}
// Check invariants for var objects.
// The result varies based on the specific Ident.
for i, id := range varIds {
obj := varObjs[i]
ref, _ := astutil.PathEnclosingInterval(f, id.Pos(), id.Pos())
pos := prog.Fset.Position(id.Pos())
exp := expectations[fmt.Sprintf("%s:%d", id.Name, pos.Line)]
if exp == "" {
t.Errorf("%s: no expectation for var ident %s ", pos, id.Name)
continue
}
wantAddr := false
if exp[0] == '&' {
wantAddr = true
exp = exp[1:]
}
checkVarValue(t, prog, mainPkg, ref, obj, exp, wantAddr)
}
}
作者:hackrol
项目:daily-progra
// Ensure that, in debug mode, we can determine the ssa.Value
// corresponding to every ast.Expr.
func TestValueForExpr(t *testing.T) {
conf := loader.Config{ParserMode: parser.ParseComments}
f, err := conf.ParseFile("testdata/valueforexpr.go", nil)
if err != nil {
t.Error(err)
return
}
conf.CreateFromFiles("main", f)
iprog, err := conf.Load()
if err != nil {
t.Error(err)
return
}
mainInfo := iprog.Created[0]
prog := ssa.Create(iprog, 0)
mainPkg := prog.Package(mainInfo.Pkg)
mainPkg.SetDebugMode(true)
mainPkg.Build()
if false {
// debugging
for _, mem := range mainPkg.Members {
if fn, ok := mem.(*ssa.Function); ok {
fn.WriteTo(os.Stderr)
}
}
}
// Find the actual AST node for each canonical position.
parenExprByPos := make(map[token.Pos]*ast.ParenExpr)
ast.Inspect(f, func(n ast.Node) bool {
if n != nil {
if e, ok := n.(*ast.ParenExpr); ok {
parenExprByPos[e.Pos()] = e
}
}
return true
})
// Find all annotations of form /*@kind*/.
for _, c := range f.Comments {
text := strings.TrimSpace(c.Text())
if text == "" || text[0] != '@' {
continue
}
text = text[1:]
pos := c.End() + 1
position := prog.Fset.Position(pos)
var e ast.Expr
if target := parenExprByPos[pos]; target == nil {
t.Errorf("%s: annotation doesn't precede ParenExpr: %q", position, text)
continue
} else {
e = target.X
}
path, _ := astutil.PathEnclosingInterval(f, pos, pos)
if path == nil {
t.Errorf("%s: can't find AST path from root to comment: %s", position, text)
continue
}
fn := ssa.EnclosingFunction(mainPkg, path)
if fn == nil {
t.Errorf("%s: can't find enclosing function", position)
continue
}
v, gotAddr := fn.ValueForExpr(e) // (may be nil)
got := strings.TrimPrefix(fmt.Sprintf("%T", v), "*ssa.")
if want := text; got != want {
t.Errorf("%s: got value %q, want %q", position, got, want)
}
if v != nil {
T := v.Type()
if gotAddr {
T = T.Underlying().(*types.Pointer).Elem() // deref
}
if !types.Identical(T, mainInfo.TypeOf(e)) {
t.Errorf("%s: got type %s, want %s", position, mainInfo.TypeOf(e), T)
}
}
}
}
作者:4hono
项目:obd
func doOneInput(input, filename string) bool {
conf := loader.Config{SourceImports: true}
// Parsing.
f, err := conf.ParseFile(filename, input)
if err != nil {
fmt.Println(err)
return false
}
// Create single-file main package and import its dependencies.
conf.CreateFromFiles("main", f)
iprog, err := conf.Load()
if err != nil {
fmt.Println(err)
return false
}
mainPkgInfo := iprog.Created[0].Pkg
// SSA creation + building.
prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
prog.BuildAll()
mainpkg := prog.Package(mainPkgInfo)
ptrmain := mainpkg // main package for the pointer analysis
if mainpkg.Func("main") == nil {
// No main function; assume it's a test.
ptrmain = prog.CreateTestMainPackage(mainpkg)
}
// Find all calls to the built-in print(x). Analytically,
// print is a no-op, but it's a convenient hook for testing
// the PTS of an expression, so our tests use it.
probes := make(map[*ssa.CallCommon]bool)
for fn := range ssautil.AllFunctions(prog) {
if fn.Pkg == mainpkg {
for _, b := range fn.Blocks {
for _, instr := range b.Instrs {
if instr, ok := instr.(ssa.CallInstruction); ok {
if b, ok := instr.Common().Value.(*ssa.Builtin); ok && b.Name() == "print" {
probes[instr.Common()] = true
}
}
}
}
}
}
ok := true
lineMapping := make(map[string]string) // maps "file:line" to @line tag
// Parse expectations in this input.
var exps []*expectation
re := regexp.MustCompile("// *@([a-z]*) *(.*)$")
lines := strings.Split(input, "\n")
for linenum, line := range lines {
linenum++ // make it 1-based
if matches := re.FindAllStringSubmatch(line, -1); matches != nil {
match := matches[0]
kind, rest := match[1], match[2]
e := &expectation{kind: kind, filename: filename, linenum: linenum}
if kind == "line" {
if rest == "" {
ok = false
e.errorf("@%s expectation requires identifier", kind)
} else {
lineMapping[fmt.Sprintf("%s:%d", filename, linenum)] = rest
}
continue
}
if e.needsProbe() && !strings.Contains(line, "print(") {
ok = false
e.errorf("@%s expectation must follow call to print(x)", kind)
continue
}
switch kind {
case "pointsto":
e.args = split(rest, "|")
case "types":
for _, typstr := range split(rest, "|") {
var t types.Type = types.Typ[types.Invalid] // means "..."
if typstr != "..." {
texpr, err := parser.ParseExpr(typstr)
if err != nil {
ok = false
// Don't print err since its location is bad.
e.errorf("'%s' is not a valid type", typstr)
continue
}
mainFileScope := mainpkg.Object.Scope().Child(0)
t, _, err = types.EvalNode(prog.Fset, texpr, mainpkg.Object, mainFileScope)
if err != nil {
ok = false
// Don't print err since its location is bad.
e.errorf("'%s' is not a valid type: %s", typstr, err)
//.........这里部分代码省略.........
作者:pombredann
项目:tardisg
func doTestable(args []string) error {
conf := loader.Config{
Build: &build.Default,
SourceImports: true,
}
// TODO(adonovan): make go/types choose its default Sizes from
// build.Default or a specified *build.Context.
var wordSize int64 = 8
switch conf.Build.GOARCH {
case "386", "arm":
wordSize = 4
}
wordSize = 4 // TARDIS Go addition to force default int size to 32 bits
//conf.Build.GOARCH = "tardisgo" // TARDIS Go addition to ensure no architecure-specific code will compile
//conf.Build.GOOS = "tardisgo" // TARDIS Go addition to ensure no OS-specific code will compile
conf.TypeChecker.Sizes = &types.StdSizes{
MaxAlign: 8,
WordSize: wordSize,
}
var mode ssa.BuilderMode
for _, c := range *buildFlag {
switch c {
case 'D':
mode |= ssa.GlobalDebug
case 'P':
mode |= ssa.LogPackages | ssa.BuildSerially
case 'F':
mode |= ssa.LogFunctions | ssa.BuildSerially
case 'S':
mode |= ssa.LogSource | ssa.BuildSerially
case 'C':
mode |= ssa.SanityCheckFunctions
case 'N':
mode |= ssa.NaiveForm
case 'G':
conf.SourceImports = false
case 'L':
mode |= ssa.BuildSerially
default:
log.Fatalf("Unknown -build option: '%c'.", c)
}
}
var interpMode interp.Mode
for _, c := range *interpFlag {
switch c {
case 'T':
interpMode |= interp.EnableTracing
case 'R':
interpMode |= interp.DisableRecover
default:
log.Fatalf("Unknown -interp option: '%c'.", c)
}
}
if len(args) == 0 {
//fmt.Fprint(os.Stderr, usage)
return fmt.Errorf("%v", usage)
}
// Profiling support.
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
return err
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
// TARDIS Go TEST
// Really need to find a way to replace entire packages, this experiment did not work...
/*
conf.Fset = token.NewFileSet()
f, err := parser.ParseFile(conf.Fset, conf.Build.GOPATH+"/src/github.com/tardisgo/tardisgo/golibruntime/runtime/runtime.go", nil, 0)
if err != nil {
fmt.Println(err)
return err
}
conf.CreateFromFiles("", f)
fmt.Printf("DEBUG %s %s\n", f.Name.Name, "") //, f.Name.Obj.Name)
*/
// end TARDIS Go TEST
// Use the initial packages from the command line.
args, err := conf.FromArgs(args, *testFlag)
if err != nil {
return err
}
// The interpreter needs the runtime package.
if *runFlag {
conf.Import("runtime")
conf.Import("github.com/tardisgo/tardisgo/golibruntime/runtime") // This required for TARDIS go to run runtime
}
//.........这里部分代码省略.........
作者:samuelyao31
项目:myg
// Run runs program analysis and computes the resulting markup,
// populating *result in a thread-safe manner, first with type
// information then later with pointer analysis information if
// enabled by the pta flag.
//
func Run(pta bool, result *Result) {
conf := loader.Config{
SourceImports: true,
AllowTypeErrors: true,
}
errors := make(map[token.Pos][]string)
conf.TypeChecker.Error = func(e error) {
err := e.(types.Error)
errors[err.Pos] = append(errors[err.Pos], err.Msg)
}
var roots, args []string // roots[i] ends with os.PathSeparator
// Enumerate packages in $GOROOT.
root := filepath.Join(runtime.GOROOT(), "src", "pkg") + string(os.PathSeparator)
roots = append(roots, root)
args = allPackages(root)
log.Printf("GOROOT=%s: %s\n", root, args)
// Enumerate packages in $GOPATH.
for i, dir := range filepath.SplitList(build.Default.GOPATH) {
root := filepath.Join(dir, "src") + string(os.PathSeparator)
roots = append(roots, root)
pkgs := allPackages(root)
log.Printf("GOPATH[%d]=%s: %s\n", i, root, pkgs)
args = append(args, pkgs...)
}
// Uncomment to make startup quicker during debugging.
//args = []string{"code.google.com/p/go.tools/cmd/godoc"}
//args = []string{"fmt"}
if _, err := conf.FromArgs(args, true); err != nil {
log.Print(err) // import error
return
}
log.Print("Loading and type-checking packages...")
iprog, err := conf.Load()
if iprog != nil {
log.Printf("Loaded %d packages.", len(iprog.AllPackages))
}
if err != nil {
// TODO(adonovan): loader: don't give up just because
// of one parse error.
log.Print(err) // parse error in some package
return
}
// Create SSA-form program representation.
// Only the transitively error-free packages are used.
prog := ssa.Create(iprog, ssa.GlobalDebug)
// Compute the set of main packages, including testmain.
allPackages := prog.AllPackages()
var mainPkgs []*ssa.Package
if testmain := prog.CreateTestMainPackage(allPackages...); testmain != nil {
mainPkgs = append(mainPkgs, testmain)
}
for _, pkg := range allPackages {
if pkg.Object.Name() == "main" && pkg.Func("main") != nil {
mainPkgs = append(mainPkgs, pkg)
}
}
log.Print("Main packages: ", mainPkgs)
// Build SSA code for bodies of all functions in the whole program.
log.Print("Building SSA...")
prog.BuildAll()
log.Print("SSA building complete")
a := analysis{
result: result,
prog: prog,
pcgs: make(map[*ssa.Package]*packageCallGraph),
}
// Build a mapping from openable filenames to godoc file URLs,
// i.e. "/src/pkg/" plus path relative to GOROOT/src/pkg or GOPATH[i]/src.
a.path2url = make(map[string]string)
for _, info := range iprog.AllPackages {
nextfile:
for _, f := range info.Files {
abs := iprog.Fset.File(f.Pos()).Name()
// Find the root to which this file belongs.
for _, root := range roots {
rel := strings.TrimPrefix(abs, root)
if len(rel) < len(abs) {
a.path2url[abs] = "/src/pkg/" + filepath.ToSlash(rel)
continue nextfile
}
}
log.Printf("Can't locate file %s (package %q) beneath any root",
//.........这里部分代码省略.........
作者:juanman
项目:dot-emac
func main() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: errorpaths scope pkg-pattern\n")
fmt.Fprint(os.Stderr, loader.FromArgsUsage)
}
flag.Parse()
args := flag.Args()
if len(args) != 2 {
flag.Usage()
}
conf := loader.Config{
SourceImports: true,
}
_, err := conf.FromArgs(args[0:1])
if err != nil {
log.Fatalf("cannot initialise loader: %v", err)
}
pkgPat, err := regexp.Compile("^" + args[1] + "$")
if err != nil {
log.Fatalf("cann compile regexp %q: %s", args[1], err)
}
lprog, err := conf.Load()
if err != nil {
log.Fatalf("cannot load program: %v", err)
}
or, err := oracle.New(lprog, nil, false)
if err != nil {
log.Fatalf("cannot make oracle: %v", err)
}
ssaProg := ssa.Create(lprog, ssa.SanityCheckFunctions)
ctxt := &context{
lprog: lprog,
ssaProg: ssaProg,
oracle: or,
infos: make(map[*ssa.Function]*errorInfo),
locs: make(map[*ssa.Function]errorLocations),
}
var foundPkgs []*types.Package
log.Printf("searching %d packages", len(lprog.AllPackages))
for pkg, _ := range lprog.AllPackages {
if pkgPat.MatchString(pkg.Path()) {
foundPkgs = append(foundPkgs, pkg)
break
}
}
if len(foundPkgs) == 0 {
log.Fatalf("failed to find any matching packages")
}
for _, pkg := range foundPkgs {
log.Printf("package %s", pkg.Name())
ssaPkg := ssaProg.Package(pkg)
ssaPkg.Build()
for name, m := range ssaPkg.Members {
log.Printf("name %s", name)
if f, ok := m.(*ssa.Function); ok && returnsError(f) {
fmt.Printf("%s\n", f)
locs := ctxt.errorLocations(f)
ctxt.dumpErrorLocs(locs, os.Stdout, "\t")
}
}
}
}
作者:hackrol
项目:daily-progra
// Tests that synthesized init functions are correctly formed.
// Bare init functions omit calls to dependent init functions and the use of
// an init guard. They are useful in cases where the client uses a different
// calling convention for init functions, or cases where it is easier for a
// client to analyze bare init functions. Both of these aspects are used by
// the llgo compiler for simpler integration with gccgo's runtime library,
// and to simplify the analysis whereby it deduces which stores to globals
// can be lowered to global initializers.
func TestInit(t *testing.T) {
tests := []struct {
mode ssa.BuilderMode
input, want string
}{
{0, `package A; import _ "errors"; var i int = 42`,
`# Name: A.init
# Package: A
# Synthetic: package initializer
func init():
0: entry P:0 S:2
t0 = *init$guard bool
if t0 goto 2 else 1
1: init.start P:1 S:1
*init$guard = true:bool
t1 = errors.init() ()
*i = 42:int
jump 2
2: init.done P:2 S:0
return
`},
{ssa.BareInits, `package B; import _ "errors"; var i int = 42`,
`# Name: B.init
# Package: B
# Synthetic: package initializer
func init():
0: entry P:0 S:0
*i = 42:int
return
`},
}
for _, test := range tests {
// Create a single-file main package.
var conf loader.Config
f, err := conf.ParseFile("<input>", test.input)
if err != nil {
t.Errorf("test %q: %s", test.input[:15], err)
continue
}
conf.CreateFromFiles(f.Name.Name, f)
iprog, err := conf.Load()
if err != nil {
t.Errorf("test 'package %s': Load: %s", f.Name.Name, err)
continue
}
prog := ssa.Create(iprog, test.mode)
mainPkg := prog.Package(iprog.Created[0].Pkg)
prog.BuildAll()
initFunc := mainPkg.Func("init")
if initFunc == nil {
t.Errorf("test 'package %s': no init function", f.Name.Name)
continue
}
var initbuf bytes.Buffer
_, err = initFunc.WriteTo(&initbuf)
if err != nil {
t.Errorf("test 'package %s': WriteTo: %s", f.Name.Name, err)
continue
}
if initbuf.String() != test.want {
t.Errorf("test 'package %s': got %q, want %q", f.Name.Name, initbuf.String(), test.want)
}
}
}
作者:bryanx
项目:go-zh.tool
func run(t *testing.T, dir, input string, success successPredicate) bool {
fmt.Printf("Input: %s\n", input)
start := time.Now()
var inputs []string
for _, i := range strings.Split(input, " ") {
if strings.HasSuffix(i, ".go") {
i = dir + i
}
inputs = append(inputs, i)
}
conf := loader.Config{SourceImports: true}
if _, err := conf.FromArgs(inputs, true); err != nil {
t.Errorf("FromArgs(%s) failed: %s", inputs, err)
return false
}
conf.Import("runtime")
// Print a helpful hint if we don't make it to the end.
var hint string
defer func() {
if hint != "" {
fmt.Println("FAIL")
fmt.Println(hint)
} else {
fmt.Println("PASS")
}
interp.CapturedOutput = nil
}()
hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build code.google.com/p/go.tools/cmd/ssadump && ./ssadump -build=CFP %s\n", input)
iprog, err := conf.Load()
if err != nil {
t.Errorf("conf.Load(%s) failed: %s", inputs, err)
return false
}
prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
prog.BuildAll()
var mainPkg *ssa.Package
var initialPkgs []*ssa.Package
for _, info := range iprog.InitialPackages() {
if info.Pkg.Path() == "runtime" {
continue // not an initial package
}
p := prog.Package(info.Pkg)
initialPkgs = append(initialPkgs, p)
if mainPkg == nil && p.Func("main") != nil {
mainPkg = p
}
}
if mainPkg == nil {
testmainPkg := prog.CreateTestMainPackage(initialPkgs...)
if testmainPkg == nil {
t.Errorf("CreateTestMainPackage(%s) returned nil", mainPkg)
return false
}
if testmainPkg.Func("main") == nil {
t.Errorf("synthetic testmain package has no main")
return false
}
mainPkg = testmainPkg
}
var out bytes.Buffer
interp.CapturedOutput = &out
hint = fmt.Sprintf("To trace execution, run:\n%% go build code.google.com/p/go.tools/cmd/ssadump && ./ssadump -build=C -run --interp=T %s\n", input)
exitCode := interp.Interpret(mainPkg, 0, &types.StdSizes{8, 8}, inputs[0], []string{})
// The definition of success varies with each file.
if err := success(exitCode, out.String()); err != nil {
t.Errorf("interp.Interpret(%s) failed: %s", inputs, err)
return false
}
hint = "" // call off the hounds
if false {
fmt.Println(input, time.Since(start)) // test profiling
}
return true
}
作者:Karthikv
项目:15640_project
// Tests that programs partially loaded from gc object files contain
// functions with no code for the external portions, but are otherwise ok.
func TestExternalPackages(t *testing.T) {
test := `
package main
import (
"bytes"
"io"
"testing"
)
func main() {
var t testing.T
t.Parallel() // static call to external declared method
t.Fail() // static call to promoted external declared method
testing.Short() // static call to external package-level function
var w io.Writer = new(bytes.Buffer)
w.Write(nil) // interface invoke of external declared method
}
`
// Create a single-file main package.
var conf loader.Config
f, err := conf.ParseFile("<input>", test, 0)
if err != nil {
t.Error(err)
return
}
conf.CreateFromFiles("main", f)
iprog, err := conf.Load()
if err != nil {
t.Error(err)
return
}
prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
mainPkg := prog.Package(iprog.Created[0].Pkg)
mainPkg.Build()
// The main package, its direct and indirect dependencies are loaded.
deps := []string{
// directly imported dependencies:
"bytes", "io", "testing",
// indirect dependencies (partial list):
"errors", "fmt", "os", "runtime",
}
all := prog.AllPackages()
if len(all) <= len(deps) {
t.Errorf("unexpected set of loaded packages: %q", all)
}
for _, path := range deps {
pkg := prog.ImportedPackage(path)
if pkg == nil {
t.Errorf("package not loaded: %q", path)
continue
}
// External packages should have no function bodies (except for wrappers).
isExt := pkg != mainPkg
// init()
if isExt && !isEmpty(pkg.Func("init")) {
t.Errorf("external package %s has non-empty init", pkg)
} else if !isExt && isEmpty(pkg.Func("init")) {
t.Errorf("main package %s has empty init", pkg)
}
for _, mem := range pkg.Members {
switch mem := mem.(type) {
case *ssa.Function:
// Functions at package level.
if isExt && !isEmpty(mem) {
t.Errorf("external function %s is non-empty", mem)
} else if !isExt && isEmpty(mem) {
t.Errorf("function %s is empty", mem)
}
case *ssa.Type:
// Methods of named types T.
// (In this test, all exported methods belong to *T not T.)
if !isExt {
t.Fatalf("unexpected name type in main package: %s", mem)
}
mset := prog.MethodSets.MethodSet(types.NewPointer(mem.Type()))
for i, n := 0, mset.Len(); i < n; i++ {
m := prog.Method(mset.At(i))
// For external types, only synthetic wrappers have code.
expExt := !strings.Contains(m.Synthetic, "wrapper")
if expExt && !isEmpty(m) {
t.Errorf("external method %s is non-empty: %s",
m, m.Synthetic)
} else if !expExt && isEmpty(m) {
t.Errorf("method function %s is empty: %s",
m, m.Synthetic)
}
}
//.........这里部分代码省略.........
作者:Karthikv
项目:15640_project
func doMain() error {
flag.Parse()
args := flag.Args()
conf := loader.Config{
Build: &build.Default,
SourceImports: true,
}
// TODO(adonovan): make go/types choose its default Sizes from
// build.Default or a specified *build.Context.
var wordSize int64 = 8
switch conf.Build.GOARCH {
case "386", "arm":
wordSize = 4
}
conf.TypeChecker.Sizes = &types.StdSizes{
MaxAlign: 8,
WordSize: wordSize,
}
var mode ssa.BuilderMode
for _, c := range *buildFlag {
switch c {
case 'D':
mode |= ssa.GlobalDebug
case 'P':
mode |= ssa.LogPackages | ssa.BuildSerially
case 'F':
mode |= ssa.LogFunctions | ssa.BuildSerially
case 'S':
mode |= ssa.LogSource | ssa.BuildSerially
case 'C':
mode |= ssa.SanityCheckFunctions
case 'N':
mode |= ssa.NaiveForm
case 'G':
conf.SourceImports = false
case 'L':
mode |= ssa.BuildSerially
default:
return fmt.Errorf("unknown -build option: '%c'", c)
}
}
var interpMode interp.Mode
for _, c := range *interpFlag {
switch c {
case 'T':
interpMode |= interp.EnableTracing
case 'R':
interpMode |= interp.DisableRecover
default:
fmt.Fprintf(os.Stderr, "ssadump: unknown -interp option: '%c'.", c)
os.Exit(1)
}
}
if len(args) == 0 {
fmt.Fprint(os.Stderr, usage)
os.Exit(1)
}
// Profiling support.
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
// Use the initial packages from the command line.
args, err := conf.FromArgs(args, *testFlag)
if err != nil {
return err
}
// The interpreter needs the runtime package.
if *runFlag {
conf.Import("runtime")
}
// Load, parse and type-check the whole program.
iprog, err := conf.Load()
if err != nil {
return err
}
// Create and build SSA-form program representation.
prog := ssa.Create(iprog, mode)
prog.BuildAll()
// Run the interpreter.
if *runFlag {
var main *ssa.Package
pkgs := prog.AllPackages()
if *testFlag {
// If -test, run all packages' tests.
//.........这里部分代码省略.........
作者:Karthikv
项目:15640_project
func TestEnclosingFunction(t *testing.T) {
tests := []struct {
input string // the input file
substr string // first occurrence of this string denotes interval
fn string // name of expected containing function
}{
// We use distinctive numbers as syntactic landmarks.
// Ordinary function:
{`package main
func f() { println(1003) }`,
"100", "main.f"},
// Methods:
{`package main
type T int
func (t T) f() { println(200) }`,
"200", "(main.T).f"},
// Function literal:
{`package main
func f() { println(func() { print(300) }) }`,
"300", "f$1"},
// Doubly nested
{`package main
func f() { println(func() { print(func() { print(350) })})}`,
"350", "f$1$1"},
// Implicit init for package-level var initializer.
{"package main; var a = 400", "400", "main.init"},
// No code for constants:
{"package main; const a = 500", "500", "(none)"},
// Explicit init()
{"package main; func init() { println(600) }", "600", "main.init$1"},
// Multiple explicit init functions:
{`package main
func init() { println("foo") }
func init() { println(800) }`,
"800", "main.init$2"},
// init() containing FuncLit.
{`package main
func init() { println(func(){print(900)}) }`,
"900", "init$1$1"},
}
for _, test := range tests {
conf := loader.Config{Fset: token.NewFileSet()}
f, start, end := findInterval(t, conf.Fset, test.input, test.substr)
if f == nil {
continue
}
path, exact := astutil.PathEnclosingInterval(f, start, end)
if !exact {
t.Errorf("EnclosingFunction(%q) not exact", test.substr)
continue
}
conf.CreateFromFiles("main", f)
iprog, err := conf.Load()
if err != nil {
t.Error(err)
continue
}
prog := ssa.Create(iprog, 0)
pkg := prog.Package(iprog.Created[0].Pkg)
pkg.Build()
name := "(none)"
fn := ssa.EnclosingFunction(pkg, path)
if fn != nil {
name = fn.String()
}
if name != test.fn {
t.Errorf("EnclosingFunction(%q in %q) got %s, want %s",
test.substr, test.input, name, test.fn)
continue
}
// While we're here: test HasEnclosingFunction.
if has := ssa.HasEnclosingFunction(pkg, path); has != (fn != nil) {
t.Errorf("HasEnclosingFunction(%q in %q) got %v, want %v",
test.substr, test.input, has, fn != nil)
continue
}
}
}
作者:Karthikv
项目:15640_project
// 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
}
`
// Construct a loader.
conf := loader.Config{SourceImports: true}
// Parse the input file.
file, err := conf.ParseFile("myprog.go", myprog, 0)
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 := ssa.Create(iprog, 0)
mainPkg := prog.Package(iprog.Created[0].Pkg)
// Build SSA code for bodies of all functions in the whole program.
prog.BuildAll()
// 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.Object, "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)
}
//.........这里部分代码省略.........
作者:minu
项目:llg
func (compiler *compiler) compile(filenames []string, importpath string) (m *Module, err error) {
buildctx, err := llgobuild.ContextFromTriple(compiler.TargetTriple)
if err != nil {
return nil, err
}
impcfg := &loader.Config{
Fset: token.NewFileSet(),
TypeChecker: types.Config{
Import: llgoimporter.NewImporter(buildctx).Import,
Sizes: compiler.llvmtypes,
},
Build: &buildctx.Context,
}
// Must use parseFiles, so we retain comments;
// this is important for annotation processing.
astFiles, err := parseFiles(impcfg.Fset, filenames)
if err != nil {
return nil, err
}
// If no import path is specified, or the package's
// name (not path) is "main", then set the import
// path to be the same as the package's name.
if pkgname := astFiles[0].Name.String(); importpath == "" || pkgname == "main" {
importpath = pkgname
}
impcfg.CreateFromFiles(importpath, astFiles...)
// Create a "runtime" package too, so we can reference
// its types and functions in the compiler and generated
// code.
if importpath != "runtime" {
astFiles, err := parseRuntime(&buildctx.Context, impcfg.Fset)
if err != nil {
return nil, err
}
impcfg.CreateFromFiles("runtime", astFiles...)
}
iprog, err := impcfg.Load()
if err != nil {
return nil, err
}
program := ssa.Create(iprog, 0)
var mainPkginfo, runtimePkginfo *loader.PackageInfo
if pkgs := iprog.InitialPackages(); len(pkgs) == 1 {
mainPkginfo, runtimePkginfo = pkgs[0], pkgs[0]
} else {
mainPkginfo, runtimePkginfo = pkgs[0], pkgs[1]
}
mainPkg := program.CreatePackage(mainPkginfo)
// Create a Module, which contains the LLVM bitcode.
modulename := importpath
compiler.module = &Module{Module: llvm.NewModule(modulename), Name: modulename}
compiler.module.SetTarget(compiler.TargetTriple)
compiler.module.SetDataLayout(compiler.dataLayout)
// Create a new translation unit.
unit := newUnit(compiler, mainPkg)
// Create the runtime interface.
compiler.runtime, err = newRuntimeInterface(
runtimePkginfo.Pkg,
compiler.module.Module,
compiler.llvmtypes,
FuncResolver(unit),
)
if err != nil {
return nil, err
}
// Create a struct responsible for mapping static types to LLVM types,
// and to runtime/dynamic type values.
compiler.types = NewTypeMap(
importpath,
compiler.llvmtypes,
compiler.module.Module,
compiler.runtime,
MethodResolver(unit),
)
// Create a Builder, for building LLVM instructions.
compiler.builder = llvm.GlobalContext().NewBuilder()
defer compiler.builder.Dispose()
// Initialise debugging.
compiler.debug.module = compiler.module.Module
compiler.debug.Fset = impcfg.Fset
compiler.debug.Sizes = compiler.llvmtypes
mainPkg.Build()
unit.translatePackage(mainPkg)
compiler.processAnnotations(unit, mainPkginfo)
if runtimePkginfo != mainPkginfo {
compiler.processAnnotations(unit, runtimePkginfo)
}
// Finalise debugging.
for _, cu := range compiler.debug.cu {
compiler.module.AddNamedMetadataOperand(
"llvm.dbg.cu",
compiler.debug.MDNode(cu),
//.........这里部分代码省略.........
作者:samuelyao31
项目:myg
// This program demonstrates how to run the SSA builder on a "Hello,
// World!" program and shows the printed representation of packages,
// functions and instructions.
//
// Within the function listing, the name of each BasicBlock such as
// ".0.entry" is printed left-aligned, followed by the block's
// Instructions.
//
// For each instruction that defines an SSA virtual register
// (i.e. implements Value), the type of that value is shown in the
// right column.
//
// Build and run the ssadump.go program if you want a standalone tool
// with similar functionality. It is located at
// code.google.com/p/go.tools/cmd/ssadump.
//
func Example() {
const hello = `
package main
import "fmt"
const message = "Hello, World!"
func main() {
fmt.Println(message)
}
`
var conf loader.Config
// Parse the input file.
file, err := conf.ParseFile("hello.go", hello)
if err != nil {
fmt.Print(err) // parse error
return
}
// Create single-file main package.
conf.CreateFromFiles("main", file)
// Load the main package and its dependencies.
iprog, err := conf.Load()
if err != nil {
fmt.Print(err) // type error in some package
return
}
// Create SSA-form program representation.
prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
mainPkg := prog.Package(iprog.Created[0].Pkg)
// Print out the package.
mainPkg.WriteTo(os.Stdout)
// Build SSA code for bodies of functions in mainPkg.
mainPkg.Build()
// Print out the package-level functions.
mainPkg.Func("init").WriteTo(os.Stdout)
mainPkg.Func("main").WriteTo(os.Stdout)
// Output:
//
// package main:
// func init func()
// var init$guard bool
// func main func()
// const message message = "Hello, World!":untyped string
//
// # Name: main.init
// # Package: main
// # Synthetic: package initializer
// func init():
// .0.entry: P:0 S:2
// t0 = *init$guard bool
// if t0 goto 2.init.done else 1.init.start
// .1.init.start: P:1 S:1
// *init$guard = true:bool
// t1 = fmt.init() ()
// jump 2.init.done
// .2.init.done: P:2 S:0
// return
//
// # Name: main.main
// # Package: main
// # Location: hello.go:8:6
// func main():
// .0.entry: P:0 S:0
// t0 = new [1]interface{} (varargs) *[1]interface{}
// t1 = &t0[0:int] *interface{}
// t2 = make interface{} <- string ("Hello, World!":string) interface{}
// *t1 = t2
// t3 = slice t0[:] []interface{}
// t4 = fmt.Println(t3...) (n int, err error)
// return
}
作者:bryanx
项目:go-zh.tool
func TestStdlib(t *testing.T) {
if !*runStdlibTest {
t.Skip("skipping (slow) stdlib test (use --stdlib)")
}
// Load, parse and type-check the program.
ctxt := build.Default // copy
ctxt.GOPATH = "" // disable GOPATH
conf := loader.Config{
SourceImports: true,
Build: &ctxt,
}
if _, err := conf.FromArgs(buildutil.AllPackages(conf.Build), true); err != nil {
t.Errorf("FromArgs failed: %v", err)
return
}
iprog, err := conf.Load()
if err != nil {
t.Fatalf("Load failed: %v", err)
}
// Create SSA packages.
prog := ssa.Create(iprog, 0)
prog.BuildAll()
numPkgs := len(prog.AllPackages())
if want := 240; numPkgs < want {
t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
}
// Determine the set of packages/tests to analyze.
var testPkgs []*ssa.Package
for _, info := range iprog.InitialPackages() {
testPkgs = append(testPkgs, prog.Package(info.Pkg))
}
testmain := prog.CreateTestMainPackage(testPkgs...)
if testmain == nil {
t.Fatal("analysis scope has tests")
}
// Run the analysis.
config := &Config{
Reflection: false, // TODO(adonovan): fix remaining bug in rVCallConstraint, then enable.
BuildCallGraph: true,
Mains: []*ssa.Package{testmain},
}
// TODO(adonovan): add some query values (affects track bits).
t0 := time.Now()
result, err := Analyze(config)
if err != nil {
t.Fatal(err) // internal error in pointer analysis
}
_ = result // TODO(adonovan): measure something
t1 := time.Now()
// Dump some statistics.
allFuncs := ssautil.AllFunctions(prog)
var numInstrs int
for fn := range allFuncs {
for _, b := range fn.Blocks {
numInstrs += len(b.Instrs)
}
}
// determine line count
var lineCount int
prog.Fset.Iterate(func(f *token.File) bool {
lineCount += f.LineCount()
return true
})
t.Log("#Source lines: ", lineCount)
t.Log("#Instructions: ", numInstrs)
t.Log("Pointer analysis: ", t1.Sub(t0))
}