// reduceScope is called for one-shot queries that need only a single // typed package. It attempts to guess the query package from pos and // reduce the analysis scope (set of loaded packages) to just that one // plus (the exported parts of) its dependencies. It leaves its // arguments unchanged on failure. // // TODO(adonovan): this is a real mess... but it's fast. // func reduceScope(pos string, impcfg *importer.Config, args *[]string) { // TODO(adonovan): make the 'args' argument of // (*Importer).LoadInitialPackages part of the // importer.Config, and inline LoadInitialPackages into // NewImporter. Then we won't need the 'args' argument. fqpos, err := fastQueryPos(pos) if err != nil { return // bad query } // TODO(adonovan): fix: this gives the wrong results for files // in non-importable packages such as tests and ad-hoc packages // specified as a list of files (incl. the oracle's tests). _, importPath, err := guessImportPath(fqpos.fset.File(fqpos.start).Name(), impcfg.Build) if err != nil { return // can't find GOPATH dir } if importPath == "" { return } // Check that it's possible to load the queried package. // (e.g. oracle tests contain different 'package' decls in same dir.) // Keep consistent with logic in importer/util.go! ctxt2 := *impcfg.Build ctxt2.CgoEnabled = false bp, err := ctxt2.Import(importPath, "", 0) if err != nil { return // no files for package } _ = bp // TODO(adonovan): fix: also check that the queried file appears in the package. // for _, f := range bp.GoFiles, bp.TestGoFiles, bp.XTestGoFiles { // if sameFile(f, fqpos.filename) { goto found } // } // return // not found // found: impcfg.TypeCheckFuncBodies = func(p string) bool { return p == importPath } *args = []string{importPath} }
func main() { flag.Parse() args := flag.Args() impctx := importer.Config{Build: &build.Default} var debugMode bool var mode ssa.BuilderMode for _, c := range *buildFlag { switch c { case 'D': debugMode = true 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': impctx.Build = nil 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) os.Exit(1) } // Profiling support. if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } // Load, parse and type-check the program. imp := importer.New(&impctx) infos, args, err := imp.LoadInitialPackages(args) if err != nil { log.Fatal(err) } // Create and build SSA-form program representation. prog := ssa.NewProgram(imp.Fset, mode) if err := prog.CreatePackages(imp); err != nil { log.Fatal(err) } if debugMode { for _, pkg := range prog.AllPackages() { pkg.SetDebugMode(true) } } prog.BuildAll() // Run the interpreter on the first package with a main function. if *runFlag { var main *ssa.Package for _, info := range infos { pkg := prog.Package(info.Pkg) if pkg.Func("main") != nil || pkg.CreateTestMainFunction() != nil { main = pkg break } } if main == nil { log.Fatal("No main function") } interp.Interpret(main, interpMode, main.Object.Path(), args) } }