// doQuery poses query q to the oracle and writes its response and // error (if any) to out. func doQuery(out io.Writer, q *query, useJson bool) { fmt.Fprintf(out, "-------- @%s %s --------\n", q.verb, q.id) var buildContext = build.Default buildContext.GOPATH = "testdata" query := oracle.Query{ Mode: q.verb, Pos: q.queryPos, Build: &buildContext, Scope: []string{q.filename}, Reflection: true, } if err := oracle.Run(&query); err != nil { fmt.Fprintf(out, "\nError: %s\n", err) return } if useJson { // JSON output b, err := json.MarshalIndent(query.Serial(), "", "\t") if err != nil { fmt.Fprintf(out, "JSON error: %s\n", err.Error()) return } out.Write(b) fmt.Fprintln(out) } else { // "plain" (compiler diagnostic format) output WriteResult(out, &query) } }
func runOracle(cmd *command.Command, args []string) error { if len(args) < 2 { cmd.Usage() return os.ErrInvalid } if os.Getenv("GOMAXPROCS") == "" { n := runtime.NumCPU() if n < 4 { n = 4 } runtime.GOMAXPROCS(n) } mode := args[0] args = args[1:] if args[0] == "." { pkgPath, err := os.Getwd() if err != nil { log.Fatalln(err) } pkg, err := build.Default.ImportDir(pkgPath, 0) if err != nil { log.Fatalln(err) } args = pkg.GoFiles //log.Println(pkg.ImportPath) if pkg.ImportPath != "." && pkg.ImportPath != "" { args = []string{pkg.ImportPath} } } query := oracle.Query{ Mode: mode, Pos: oraclePos, Build: &build.Default, Scope: args, PTALog: nil, Reflection: oracleReflect, } if err := oracle.Run(&query); err != nil { fmt.Fprintf(os.Stderr, "oracle: %s.\n", err) return err } if mode == "referrers" { ref := query.Serial().Referrers if ref != nil { fmt.Fprintln(os.Stdout, ref.Desc) fmt.Fprintln(os.Stdout, ref.ObjPos) for _, v := range ref.Refs { fmt.Fprintln(os.Stdout, v) } } } else { query.WriteTo(os.Stdout) } return nil }
// Find usages for the given candidate symbols in the local system gopath. // Relies on oracle to find referrers. func FindUsages(candidates []UnexportCandidate, dir string) []CandidateWithUsage { data := []CandidateWithUsage{} workCh := make(chan UnexportCandidate, len(candidates)) resultChan := make(chan CandidateWithUsage) quit := make(chan struct{}) // run oracle on 10 symbols at a time in parallel. for i := 0; i < 10; i++ { go func() { for { select { case <-quit: return case c := <-workCh: q := &oracle.Query{} q.Build = &build.Default q.Mode = "referrers" q.Pos = fmt.Sprintf("%s:#%d", c.Pos.Filename, c.Pos.Offset) err := oracle.Run(q) if err != nil { resultChan <- CandidateWithUsage{c, []string{err.Error()}} break } refs := q.Serial().Referrers usage := CandidateWithUsage{c, nil} for _, ref := range refs.Refs { // filter out usages from within the package itself file := ref[:strings.LastIndex(ref, ":")] file = file[:strings.LastIndex(file, ":")] if filepath.Dir(file) != dir { usage.References = append(usage.References, ref) } } resultChan <- usage } } }() } for _, c := range candidates { workCh <- c } for len(data) < len(candidates) { r := <-resultChan data = append(data, r) verbosef("Usages of %s:", r.DisplayName) if len(r.References) == 0 { verbose("", "None Found.") } else { for _, ref := range r.References { verbose("", ref) } } } close(quit) return data }
func main() { // Don't print full help unless -help was requested. // Just gently remind users that it's there. flag.Usage = func() { fmt.Fprint(os.Stderr, useHelp) } flag.CommandLine.Init(os.Args[0], flag.ContinueOnError) // hack if err := flag.CommandLine.Parse(os.Args[1:]); err != nil { // (err has already been printed) if err == flag.ErrHelp { printHelp() } os.Exit(2) } args := flag.Args() if len(args) == 0 || args[0] == "" { fmt.Fprint(os.Stderr, "oracle: a mode argument is required.\n"+useHelp) os.Exit(2) } mode := args[0] args = args[1:] if mode == "help" { printHelp() os.Exit(2) } // Set up points-to analysis log file. var ptalog io.Writer if *ptalogFlag != "" { if f, err := os.Create(*ptalogFlag); err != nil { log.Fatalf("Failed to create PTA log file: %s", err) } else { buf := bufio.NewWriter(f) ptalog = buf defer func() { if err := buf.Flush(); err != nil { log.Printf("flush: %s", err) } if err := f.Close(); err != nil { log.Printf("close: %s", err) } }() } } // Profiling support. if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } // -format flag switch *formatFlag { case "json", "plain", "xml": // ok default: fmt.Fprintf(os.Stderr, "oracle: illegal -format value: %q.\n"+useHelp, *formatFlag) os.Exit(2) } // Ask the oracle. query := oracle.Query{ Mode: mode, Pos: *posFlag, Build: &build.Default, Scope: args, PTALog: ptalog, Reflection: *reflectFlag, } if err := oracle.Run(&query); err != nil { fmt.Fprintf(os.Stderr, "oracle: %s\n", err) os.Exit(1) } // Print the result. switch *formatFlag { case "json": b, err := json.MarshalIndent(query.Serial(), "", "\t") if err != nil { fmt.Fprintf(os.Stderr, "oracle: JSON error: %s\n", err) os.Exit(1) } os.Stdout.Write(b) case "xml": b, err := xml.MarshalIndent(query.Serial(), "", "\t") if err != nil { fmt.Fprintf(os.Stderr, "oracle: XML error: %s\n", err) os.Exit(1) } os.Stdout.Write(b) case "plain": query.WriteTo(os.Stdout) } }