Beispiel #1
0
// 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)
	}
}
Beispiel #2
0
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
}
Beispiel #3
0
// 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
}
Beispiel #4
0
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)
	}
}