Exemple #1
0
// Oracle annotates `pkg` using go.tools/oracle interface implements detector.
// It uses `scopes` as analysis scope.
// If `scopes` is none of one of `scopes` is zero string, it uses unit tests as scope.
func Oracle(pkg *ast.Package, scopes ...string) error {
	settings := build.Default
	settings.BuildTags = []string{} // TODO
	conf := loader.Config{Build: &settings, SourceImports: true}

	withTests := false
	if len(scopes) == 0 {
		withTests = true
	}
	for _, scope := range scopes {
		if scope == "" {
			withTests = true
		} else {
			conf.Import(scope)
		}
	}
	if withTests {
		conf.ImportWithTests(pkg.Name)
	} else {
		conf.Import(pkg.Name)
	}

	iprog, err := conf.Load()
	if err != nil {
		return fmt.Errorf("oracle annotator: conf load error: %+v", err)
	}
	o, err := oracle.New(iprog, nil, false)
	if err != nil {
		return fmt.Errorf("oracle annotator: create error: %+v", err)
	}
	for _, class := range pkg.Classes {
		qpos, err := oracle.ParseQueryPos(iprog, string(class.Pos), false)
		if err != nil {
			log.Printf("oracle annotator: parse query pos error: %+v, %+v", err, class.Pos)
			continue
		}

		res, err := o.Query("implements", qpos)
		if err != nil {
			return fmt.Errorf("oracle annotator: query error: %+v, %v", err, class.Pos)
		}
		impls := res.Serial().Implements
		for _, target := range impls.AssignableFromPtr {
			addImplements(class, target)
		}
		for _, target := range impls.AssignableFrom {
			addImplements(class, target)
		}
	}
	return nil
}
func TestMultipleQueries(t *testing.T) {
	// Loader
	var buildContext = build.Default
	buildContext.GOPATH = "testdata"
	conf := loader.Config{Build: &buildContext, SourceImports: true}
	filename := "testdata/src/main/multi.go"
	conf.CreateFromFilenames("", filename)
	iprog, err := conf.Load()
	if err != nil {
		t.Fatalf("Load failed: %s", err)
	}

	// Oracle
	o, err := oracle.New(iprog, nil, true)
	if err != nil {
		t.Fatalf("oracle.New failed: %s", err)
	}

	// QueryPos
	pos := filename + ":#54,#58"
	qpos, err := oracle.ParseQueryPos(iprog, pos, true)
	if err != nil {
		t.Fatalf("oracle.ParseQueryPos(%q) failed: %s", pos, err)
	}
	// SSA is built and we have the QueryPos.
	// Release the other ASTs and type info to the GC.
	iprog = nil

	// Run different query modes on same scope and selection.
	out := new(bytes.Buffer)
	for _, mode := range [...]string{"callers", "describe", "freevars"} {
		res, err := o.Query(mode, qpos)
		if err != nil {
			t.Errorf("(*oracle.Oracle).Query(%q) failed: %s", pos, err)
		}
		WriteResult(out, res)
	}
	want := `multi.f is called from these 1 sites:
	static function call from multi.main

function call (or conversion) of type ()

Free identifiers:
var x int

`
	if got := out.String(); got != want {
		t.Errorf("Query output differs; want <<%s>>, got <<%s>>\n", want, got)
	}
}
func TestMultipleQueries(t *testing.T) {
	// Importer
	var buildContext = build.Default
	buildContext.GOPATH = "testdata"
	imp := importer.New(&importer.Config{Build: &buildContext})

	// Oracle
	filename := "testdata/src/main/multi.go"
	o, err := oracle.New(imp, []string{filename}, nil, true)
	if err != nil {
		t.Fatalf("oracle.New failed: %s", err)
	}

	// QueryPos
	pos := filename + ":#54,#58"
	qpos, err := oracle.ParseQueryPos(imp, pos, true)
	if err != nil {
		t.Fatalf("oracle.ParseQueryPos(%q) failed: %s", pos, err)
	}
	// SSA is built and we have the QueryPos.
	// Release the other ASTs and type info to the GC.
	imp = nil

	// Run different query moes on same scope and selection.
	out := new(bytes.Buffer)
	for _, mode := range [...]string{"callers", "describe", "freevars"} {
		res, err := o.Query(mode, qpos)
		if err != nil {
			t.Errorf("(*oracle.Oracle).Query(%q) failed: %s", pos, err)
		}
		capture := new(bytes.Buffer) // capture standard output
		res.WriteTo(capture)
		for _, line := range strings.Split(capture.String(), "\n") {
			fmt.Fprintf(out, "%s\n", stripLocation(line))
		}
	}
	want := `multi.f is called from these 1 sites:
	static function call from multi.main

function call (or conversion) of type ()

Free identifiers:
var x int

`
	if got := out.String(); got != want {
		t.Errorf("Query output differs; want <<%s>>, got <<%s>>\n", want, got)
	}
}
Exemple #4
0
func main() {
	flag.Usage = func() { fmt.Fprint(os.Stderr, useHelp) }
	flag.CommandLine.Init(os.Args[0], flag.ContinueOnError)
	if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
		if err == flag.ErrHelp {
			fmt.Println(helpMessage)
			fmt.Println("Flags:")
			flag.PrintDefaults()
		}
		os.Exit(2)
	}
	args = flag.Args()
	if len(args) == 0 {
		fmt.Fprint(os.Stderr, "Error: no package arguments.\n"+useHelp)
		os.Exit(2)
	}

	var err error
	imp = importer.New(&importer.Config{Build: &build.Default})
	ora, err = oracle.New(imp, args, nil, false)
	if err != nil {
		log.Fatal(err)
	}
	files = scopeFiles(imp)
	packages = imp.AllPackages()
	sort.Sort(byPath(packages))

	registerHandlers()

	srv := &http.Server{Addr: *httpAddr}
	l, err := net.Listen("tcp", srv.Addr)
	if err != nil {
		log.Fatal(err)
	}
	if *open {
		url := fmt.Sprintf("http://localhost%s/", *httpAddr)
		if !startBrowser(url) {
			fmt.Println(url)
		}
	}
	log.Fatal(srv.Serve(l))
}
Exemple #5
0
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")
			}
		}
	}
}