Beispiel #1
0
func main() {
	flag.Parse()

	importPaths := gotool.ImportPaths(flag.Args())
	if len(importPaths) == 0 {
		return
	}

	var conf loader.Config
	conf.Fset = fset
	for _, importPath := range importPaths {
		conf.Import(importPath)
	}
	prog, err := conf.Load()
	if err != nil {
		log.Fatal(err)
	}

	for _, pkg := range prog.InitialPackages() {
		for _, file := range pkg.Files {
			ast.Inspect(file, func(node ast.Node) bool {
				if s, ok := node.(*ast.StructType); ok {
					malign(node.Pos(), pkg.Types[s].Type.(*types.Struct))
				}
				return true
			})
		}
	}
}
Beispiel #2
0
func TestCwd(t *testing.T) {
	ctxt := fakeContext(map[string]string{"one/two/three": `package three`})
	for _, test := range []struct {
		cwd, arg, want string
	}{
		{cwd: "/go/src/one", arg: "./two/three", want: "one/two/three"},
		{cwd: "/go/src/one", arg: "../one/two/three", want: "one/two/three"},
		{cwd: "/go/src/one", arg: "one/two/three", want: "one/two/three"},
		{cwd: "/go/src/one/two/three", arg: ".", want: "one/two/three"},
		{cwd: "/go/src/one", arg: "two/three", want: ""},
	} {
		conf := loader.Config{
			Cwd:   test.cwd,
			Build: ctxt,
		}
		conf.Import(test.arg)

		var got string
		prog, err := conf.Load()
		if prog != nil {
			got = imported(prog)
		}
		if got != test.want {
			t.Errorf("Load(%s) from %s: Imported = %s, want %s",
				test.arg, test.cwd, got, test.want)
			if err != nil {
				t.Errorf("Load failed: %v", err)
			}
		}
	}
}
Beispiel #3
0
func main() {
	// Loader is a tool for opening Go files, it loads from a Config type
	conf := loader.Config{
		Build: &build.Default,
	}

	path, _ := filepath.Abs("looper")
	file, err := conf.ParseFile(path+"/"+"looper.go", nil)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Creation of a single file main pacakge
	conf.CreateFromFiles("looper", file)
	conf.Import("runtime")

	p, err := conf.Load()
	if err != nil {
		fmt.Println(err)
		return
	}

	// Finally, create SSA representation from the package we've loaded
	program := ssautil.CreateProgram(p, ssa.SanityCheckFunctions)
	looperPkg := program.Package(p.Created[0].Pkg)

	fmt.Println("RIGHT IN THE SINGLE STATIC ASSIGNMENT FORM:")
	looperPkg.WriteTo(os.Stdout)

	fmt.Println("LOOK AT THIS HERE LOOPER FUNC:")
	looperFunc := looperPkg.Func("Looper")
	looperFunc.WriteTo(os.Stdout)
}
Beispiel #4
0
// This example imports three packages, including the tests for one of
// them, and loads all their dependencies.
func ExampleConfig_Import() {
	// ImportWithTest("strconv") causes strconv to include
	// internal_test.go, and creates an external test package,
	// strconv_test.
	// (Compare with the example of CreateFromFiles.)

	var conf loader.Config
	conf.Import("unicode/utf8")
	conf.Import("errors")
	conf.ImportWithTests("strconv")
	prog, err := conf.Load()
	if err != nil {
		log.Fatal(err)
	}

	printProgram(prog)
	printFilenames(prog.Fset, prog.Package("strconv"))
	printFilenames(prog.Fset, prog.Package("strconv_test"))
	// Output:
	// created: [strconv_test]
	// imported: [errors strconv unicode/utf8]
	// initial: [errors strconv strconv_test unicode/utf8]
	// all: [bufio bytes errors flag fmt io log math math/rand os reflect runtime runtime/pprof runtime/trace sort strconv strconv_test strings sync sync/atomic syscall testing text/tabwriter time unicode unicode/utf8]
	// strconv.Files: [atob.go atof.go atoi.go decimal.go doc.go extfloat.go ftoa.go isprint.go itoa.go quote.go internal_test.go]
	// strconv_test.Files: [atob_test.go atof_test.go atoi_test.go decimal_test.go example_test.go fp_test.go ftoa_test.go itoa_test.go quote_test.go strconv_test.go]
}
func TestTransitivelyErrorFreeFlag(t *testing.T) {
	// Create an minimal custom build.Context
	// that fakes the following packages:
	//
	// a --> b --> c!   c has an error
	//   \              d and e are transitively error-free.
	//    e --> d
	//
	// Each package [a-e] consists of one file, x.go.
	pkgs := map[string]string{
		"a": `package a; import (_ "b"; _ "e")`,
		"b": `package b; import _ "c"`,
		"c": `package c; func f() { _ = int(false) }`, // type error within function body
		"d": `package d;`,
		"e": `package e; import _ "d"`,
	}
	conf := loader.Config{
		AllowErrors:   true,
		SourceImports: true,
		Build:         fakeContext(pkgs),
	}
	conf.Import("a")

	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed: %s", err)
	}
	if prog == nil {
		t.Fatalf("Load returned nil *Program")
	}

	for pkg, info := range prog.AllPackages {
		var wantErr, wantTEF bool
		switch pkg.Path() {
		case "a", "b":
		case "c":
			wantErr = true
		case "d", "e":
			wantTEF = true
		default:
			t.Errorf("unexpected package: %q", pkg.Path())
			continue
		}

		if (info.Errors != nil) != wantErr {
			if wantErr {
				t.Errorf("Package %q.Error = nil, want error", pkg.Path())
			} else {
				t.Errorf("Package %q has unexpected Errors: %v",
					pkg.Path(), info.Errors)
			}
		}

		if info.TransitivelyErrorFree != wantTEF {
			t.Errorf("Package %q.TransitivelyErrorFree=%t, want %t",
				pkg.Path(), info.TransitivelyErrorFree, wantTEF)
		}
	}
}
Beispiel #6
0
func TestLoad_BadDependency_AllowErrors(t *testing.T) {
	for _, test := range []struct {
		descr    string
		pkgs     map[string]string
		wantPkgs string
	}{

		{
			descr: "missing dependency",
			pkgs: map[string]string{
				"a": `package a; import _ "b"`,
				"b": `package b; import _ "c"`,
			},
			wantPkgs: "a b",
		},
		{
			descr: "bad package decl in dependency",
			pkgs: map[string]string{
				"a": `package a; import _ "b"`,
				"b": `package b; import _ "c"`,
				"c": `package`,
			},
			wantPkgs: "a b",
		},
		{
			descr: "parse error in dependency",
			pkgs: map[string]string{
				"a": `package a; import _ "b"`,
				"b": `package b; import _ "c"`,
				"c": `package c; var x = `,
			},
			wantPkgs: "a b c",
		},
	} {
		conf := loader.Config{
			AllowErrors:   true,
			SourceImports: true,
			Build:         fakeContext(test.pkgs),
		}
		conf.Import("a")

		prog, err := conf.Load()
		if err != nil {
			t.Errorf("%s: Load failed unexpectedly: %v", test.descr, err)
		}
		if prog == nil {
			t.Fatalf("%s: Load returned a nil Program", test.descr)
		}

		if got, want := imported(prog), "a"; got != want {
			t.Errorf("%s: Imported = %s, want %s", test.descr, got, want)
		}
		if got := all(prog); strings.Join(got, " ") != test.wantPkgs {
			t.Errorf("%s: AllPackages = %s, want %s", test.descr, got, test.wantPkgs)
		}
	}
}
Beispiel #7
0
func invalidProgram(name string) *loader.Program {
	var ldr loader.Config
	ldr.ParserMode = goparser.ParseComments
	ldr.Import("../fixtures/goparsing/" + name)
	prog, err := ldr.Load()
	if err != nil {
		log.Fatal(err)
	}
	return prog
}
// Test that both syntax (scan/parse) and type errors are both recorded
// (in PackageInfo.Errors) and reported (via Config.TypeChecker.Error).
func TestErrorReporting(t *testing.T) {
	pkgs := map[string]string{
		"a": `package a; import _ "b"; var x int = false`,
		"b": `package b; 'syntax error!`,
	}
	conf := loader.Config{
		AllowErrors:   true,
		SourceImports: true,
		Build:         fakeContext(pkgs),
	}
	var allErrors []error
	conf.TypeChecker.Error = func(err error) {
		allErrors = append(allErrors, err)
	}
	conf.Import("a")

	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed: %s", err)
	}
	if prog == nil {
		t.Fatalf("Load returned nil *Program")
	}

	hasError := func(errors []error, substr string) bool {
		for _, err := range errors {
			if strings.Contains(err.Error(), substr) {
				return true
			}
		}
		return false
	}

	// TODO(adonovan): test keys of ImportMap.

	// Check errors recorded in each PackageInfo.
	for pkg, info := range prog.AllPackages {
		switch pkg.Path() {
		case "a":
			if !hasError(info.Errors, "cannot convert false") {
				t.Errorf("a.Errors = %v, want bool conversion (type) error", info.Errors)
			}
		case "b":
			if !hasError(info.Errors, "rune literal not terminated") {
				t.Errorf("b.Errors = %v, want unterminated literal (syntax) error", info.Errors)
			}
		}
	}

	// Check errors reported via error handler.
	if !hasError(allErrors, "cannot convert false") ||
		!hasError(allErrors, "rune literal not terminated") {
		t.Errorf("allErrors = %v, want both syntax and type errors", allErrors)
	}
}
Beispiel #9
0
func loadProgram(ctx *build.Context, pkgs []string) (*loader.Program, error) {
	conf := loader.Config{
		Build:       ctx,
		ParserMode:  parser.ParseComments,
		AllowErrors: false,
	}
	for _, pkg := range pkgs {
		conf.Import(pkg)
	}
	return conf.Load()
}
Beispiel #10
0
// Test that syntax (scan/parse), type, and loader errors are recorded
// (in PackageInfo.Errors) and reported (via Config.TypeChecker.Error).
func TestErrorReporting(t *testing.T) {
	pkgs := map[string]string{
		"a": `package a; import (_ "b"; _ "c"); var x int = false`,
		"b": `package b; 'syntax error!`,
	}
	conf := loader.Config{
		AllowErrors: true,
		Build:       fakeContext(pkgs),
	}
	var mu sync.Mutex
	var allErrors []error
	conf.TypeChecker.Error = func(err error) {
		mu.Lock()
		allErrors = append(allErrors, err)
		mu.Unlock()
	}
	conf.Import("a")

	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed: %s", err)
	}
	if prog == nil {
		t.Fatalf("Load returned nil *Program")
	}

	// TODO(adonovan): test keys of ImportMap.

	// Check errors recorded in each PackageInfo.
	for pkg, info := range prog.AllPackages {
		switch pkg.Path() {
		case "a":
			if !hasError(info.Errors, "cannot convert false") {
				t.Errorf("a.Errors = %v, want bool conversion (type) error", info.Errors)
			}
			if !hasError(info.Errors, "could not import c") {
				t.Errorf("a.Errors = %v, want import (loader) error", info.Errors)
			}
		case "b":
			if !hasError(info.Errors, "rune literal not terminated") {
				t.Errorf("b.Errors = %v, want unterminated literal (syntax) error", info.Errors)
			}
		}
	}

	// Check errors reported via error handler.
	if !hasError(allErrors, "cannot convert false") ||
		!hasError(allErrors, "rune literal not terminated") ||
		!hasError(allErrors, "could not import c") {
		t.Errorf("allErrors = %v, want syntax, type and loader errors", allErrors)
	}
}
Beispiel #11
0
// InlineDotImports displays Go package source code with dot imports inlined.
func InlineDotImports(w io.Writer, importPath string) {
	/*imp2 := importer.New()
	imp2.Config.UseGcFallback = true
	cfg := types.Config{Import: imp2.Import}
	_ = cfg*/

	conf := loader.Config{
	//TypeChecker:   cfg,
	}

	conf.Import(importPath)

	prog, err := conf.Load()
	if err != nil {
		panic(err)
	}

	/*pi, err := imp.ImportPackage(importPath)
	if err != nil {
		panic(err)
	}
	_ = pi*/

	pi := prog.Imported[importPath]

	findDotImports(prog, pi)

	files := make(map[string]*ast.File)
	{
		// This package
		for _, file := range pi.Files {
			filename := prog.Fset.File(file.Package).Name()
			files[filename] = file
		}

		// All dot imports
		for _, pi := range dotImports {
			for _, file := range pi.Files {
				filename := prog.Fset.File(file.Package).Name()
				files[filename] = file
			}
		}
	}

	apkg := &ast.Package{Name: pi.Pkg.Name(), Files: files}

	merged := ast.MergePackageFiles(apkg, astMergeMode)

	WriteMergedPackage(w, prog.Fset, merged)
}
Beispiel #12
0
func TestLoad_MissingInitialPackage(t *testing.T) {
	var conf loader.Config
	conf.Import("nosuchpkg")
	conf.Import("errors")

	const wantErr = "couldn't load packages due to errors: nosuchpkg"

	prog, err := conf.Load()
	if err == nil {
		t.Errorf("Load succeeded unexpectedly, want %q", wantErr)
	} else if err.Error() != wantErr {
		t.Errorf("Load failed with wrong error %q, want %q", err, wantErr)
	}
	if prog != nil {
		t.Errorf("Load unexpectedly returned a Program")
	}
}
Beispiel #13
0
func main() {
	if len(os.Args) != 3 {
		log.Fatal("Usage: doc <package> <object>")
	}
	//!+part1
	pkgpath, name := os.Args[1], os.Args[2]

	// The loader loads a complete Go program from source code.
	conf := loader.Config{ParserMode: parser.ParseComments}
	conf.Import(pkgpath)
	lprog, err := conf.Load()
	if err != nil {
		log.Fatal(err) // load error
	}

	// Find the package and package-level object.
	pkg := lprog.Package(pkgpath).Pkg
	obj := pkg.Scope().Lookup(name)
	if obj == nil {
		log.Fatalf("%s.%s not found", pkg.Path(), name)
	}
	//!-part1
	//!+part2

	// Print the object and its methods (incl. location of definition).
	fmt.Println(obj)
	for _, sel := range typeutil.IntuitiveMethodSet(obj.Type(), nil) {
		fmt.Printf("%s: %s\n", lprog.Fset.Position(sel.Obj().Pos()), sel)
	}

	// Find the path from the root of the AST to the object's position.
	// Walk up to the enclosing ast.Decl for the doc comment.
	_, path, _ := lprog.PathEnclosingInterval(obj.Pos(), obj.Pos())
	for _, n := range path {
		switch n := n.(type) {
		case *ast.GenDecl:
			fmt.Println("\n", n.Doc.Text())
			return
		case *ast.FuncDecl:
			fmt.Println("\n", n.Doc.Text())
			return
		}
	}
	//!-part2
}
Beispiel #14
0
// importQueryPackage finds the package P containing the
// query position and tells conf to import it.
// It returns the package's path.
func importQueryPackage(pos string, conf *loader.Config) (string, error) {
	fqpos, err := fastQueryPos(pos)
	if err != nil {
		return "", err // bad query
	}
	filename := fqpos.fset.File(fqpos.start).Name()

	// This will not work for ad-hoc packages
	// such as $GOROOT/src/net/http/triv.go.
	// TODO(adonovan): ensure we report a clear error.
	_, importPath, err := guessImportPath(filename, conf.Build)
	if err != nil {
		return "", err // can't find GOPATH dir
	}
	if importPath == "" {
		return "", fmt.Errorf("can't guess import path from %s", filename)
	}

	// 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 loader/util.go!
	cfg2 := *conf.Build
	cfg2.CgoEnabled = false
	bp, err := cfg2.Import(importPath, "", 0)
	if err != nil {
		return "", err // no files for package
	}

	switch pkgContainsFile(bp, filename) {
	case 'T':
		conf.ImportWithTests(importPath)
	case 'X':
		conf.ImportWithTests(importPath)
		importPath += "_test" // for TypeCheckFuncBodies
	case 'G':
		conf.Import(importPath)
	default:
		return "", fmt.Errorf("package %q doesn't contain file %s",
			importPath, filename)
	}

	conf.TypeCheckFuncBodies = func(p string) bool { return p == importPath }

	return importPath, nil
}
Beispiel #15
0
// This program shows how to load a main package (cmd/cover) and all its
// dependencies from source, using the loader, and then build SSA code
// for the entire program.  This is what you'd typically use for a
// whole-program analysis.
//
func ExampleLoadProgram() {
	// Load cmd/cover and its dependencies.
	var conf loader.Config
	conf.Import("cmd/cover")
	lprog, err := conf.Load()
	if err != nil {
		fmt.Print(err) // type error in some package
		return
	}

	// Create SSA-form program representation.
	prog := ssautil.CreateProgram(lprog, ssa.SanityCheckFunctions)

	// Build SSA code for the entire cmd/cover program.
	prog.Build()

	// Output:
}
Beispiel #16
0
func main() {
	if len(os.Args) != 4 {
		log.Fatal(usage)
	}
	pkgpath, ifacename, concname := os.Args[1], os.Args[2], os.Args[3]

	// The loader loads a complete Go program from source code.
	var conf loader.Config
	conf.Import(pkgpath)
	lprog, err := conf.Load()
	if err != nil {
		log.Fatal(err) // load error
	}
	pkg := lprog.Package(pkgpath).Pkg
	if err := PrintSkeleton(pkg, ifacename, concname); err != nil {
		log.Fatal(err)
	}
}
Beispiel #17
0
// importQueryPackage finds the package P containing the
// query position and tells conf to import it.
// It returns the package's path.
func importQueryPackage(pos string, conf *loader.Config) (string, error) {
	fqpos, err := fastQueryPos(conf.Build, pos)
	if err != nil {
		return "", err // bad query
	}
	filename := fqpos.fset.File(fqpos.start).Name()

	_, importPath, err := guessImportPath(filename, conf.Build)
	if err != nil {
		// Can't find GOPATH dir.
		// Treat the query file as its own package.
		importPath = "command-line-arguments"
		conf.CreateFromFilenames(importPath, filename)
	} else {
		// Check that it's possible to load the queried package.
		// (e.g. guru tests contain different 'package' decls in same dir.)
		// Keep consistent with logic in loader/util.go!
		cfg2 := *conf.Build
		cfg2.CgoEnabled = false
		bp, err := cfg2.Import(importPath, "", 0)
		if err != nil {
			return "", err // no files for package
		}

		switch pkgContainsFile(bp, filename) {
		case 'T':
			conf.ImportWithTests(importPath)
		case 'X':
			conf.ImportWithTests(importPath)
			importPath += "_test" // for TypeCheckFuncBodies
		case 'G':
			conf.Import(importPath)
		default:
			// This happens for ad-hoc packages like
			// $GOROOT/src/net/http/triv.go.
			return "", fmt.Errorf("package %q doesn't contain file %s",
				importPath, filename)
		}
	}

	conf.TypeCheckFuncBodies = func(p string) bool { return p == importPath }

	return importPath, nil
}
Beispiel #18
0
func Grapher(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	repo := ps.ByName("importpath")
	repo = strings.TrimLeft(repo, "/")
	log.Println(repo)
	_, err := exec.Command("go", "get", "-u", "-f", repo).Output()
	if err != nil {
		w.Write([]byte("couldn't get repo [" + repo + "]:" + err.Error()))
		return
	}

	var conf loader.Config
	conf.Import(repo)
	prog, err := conf.Load()
	if err != nil {
		log.Fatal(err)
	}

	ssaProg := ssautil.CreateProgram(prog, 0)
	ssaProg.Build()

	var nodes []node.Node
	nodes, err = rta.GetNodes(ssaProg)
	if err != nil {
		nodes, err = cha.GetNodes(ssaProg)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}

	by, err := json.Marshal(nodes)
	if err != nil {
		panic(err)
	}

	var data = struct {
		Graph string
	}{
		Graph: string(by),
	}

	tmpl, _ := template.New("foo").Parse(nt)
	tmpl.Execute(w, data)
}
Beispiel #19
0
func TestVendorCwd(t *testing.T) {
	if buildutil.AllowVendor == 0 {
		// Vendoring requires Go 1.6.
		// TODO(adonovan): delete in due course.
		t.Skip()
	}
	// Test the interaction of cwd and vendor directories.
	ctxt := fakeContext(map[string]string{
		"net":          ``, // mkdir net
		"net/http":     `package http; import _ "hpack"`,
		"vendor":       ``, // mkdir vendor
		"vendor/hpack": `package vendorhpack`,
		"hpack":        `package hpack`,
	})
	for i, test := range []struct {
		cwd, arg, want string
	}{
		{cwd: "/go/src/net", arg: "http"}, // not found
		{cwd: "/go/src/net", arg: "./http", want: "net/http vendor/hpack"},
		{cwd: "/go/src/net", arg: "hpack", want: "hpack"},
		{cwd: "/go/src/vendor", arg: "hpack", want: "hpack"},
		{cwd: "/go/src/vendor", arg: "./hpack", want: "vendor/hpack"},
	} {
		conf := loader.Config{
			Cwd:   test.cwd,
			Build: ctxt,
		}
		conf.Import(test.arg)

		var got string
		prog, err := conf.Load()
		if prog != nil {
			got = strings.Join(all(prog), " ")
		}
		if got != test.want {
			t.Errorf("#%d: Load(%s) from %s: got %s, want %s",
				i, test.arg, test.cwd, got, test.want)
			if err != nil {
				t.Errorf("Load failed: %v", err)
			}
		}
	}
}
Beispiel #20
0
func TestLoad_MissingInitialPackage_AllowErrors(t *testing.T) {
	var conf loader.Config
	conf.AllowErrors = true
	conf.Import("nosuchpkg")
	conf.ImportWithTests("errors")

	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed unexpectedly: %v", err)
	}
	if prog == nil {
		t.Fatalf("Load returned a nil Program")
	}
	if got, want := created(prog), "errors_test"; got != want {
		t.Errorf("Created = %s, want %s", got, want)
	}
	if got, want := imported(prog), "errors"; got != want {
		t.Errorf("Imported = %s, want %s", got, want)
	}
}
Beispiel #21
0
func TestLoad_MissingIndirectImport(t *testing.T) {
	pkgs := map[string]string{
		"a": `package a; import _ "b"`,
		"b": `package b; import _ "c"`,
	}
	conf := loader.Config{Build: fakeContext(pkgs)}
	conf.Import("a")

	const wantErr = "couldn't load packages due to errors: b"

	prog, err := conf.Load()
	if err == nil {
		t.Errorf("Load succeeded unexpectedly, want %q", wantErr)
	} else if err.Error() != wantErr {
		t.Errorf("Load failed with wrong error %q, want %q", err, wantErr)
	}
	if prog != nil {
		t.Errorf("Load unexpectedly returned a Program")
	}
}
Beispiel #22
0
func main() {
	flag.Parse()

	var conf loader.Config
	conf.Fset = fset
	for _, arg := range flag.Args() {
		conf.Import(arg)
	}
	prog, err := conf.Load()
	if err != nil {
		log.Fatal(err)
	}

	var v visitor
	for _, pkg := range prog.InitialPackages() {
		v.pkg = pkg
		for _, file := range pkg.Files {
			ast.Walk(&v, file)
		}
	}
}
Beispiel #23
0
func importPackage(dir string) *importData {
	installPackage()

	buildPkg, err := build.ImportDir(dir, 0)
	if err != nil {
		log.Fatalf(`build.ImportDir(%q, 0): %s`, dir, err)
	}

	// load package
	var conf loader.Config
	conf.Import(buildPkg.ImportPath)
	prog, err := conf.Load()
	if err != nil {
		log.Fatalf("conf.Load(): %s", err)
	}

	// get our single package
	packages := make([]string, 0, len(prog.Imported))
	for p := range prog.Imported {
		packages = append(packages, p)
	}
	if len(packages) != 1 {
		log.Fatalf("expected 1 package, got %d: %v", len(packages), packages)
	}
	pack := prog.Imported[packages[0]].Pkg

	// TODO compare pack and buildPkg

	tests := extractTestFunctions(pack.Scope())

	return &importData{
		PackageName:       pack.Name(),
		PackageImportPath: buildPkg.ImportPath,
		PackageDir:        buildPkg.Dir,
		Tests:             tests,
	}
}
Beispiel #24
0
// newAppScanner creates a new api parser
func newAppScanner(bp string, input *spec.Swagger, includes, excludes packageFilters) (*appScanner, error) {
	var ldr loader.Config
	ldr.ParserMode = goparser.ParseComments
	ldr.Import(bp)
	prog, err := ldr.Load()
	if err != nil {
		return nil, err
	}
	if input == nil {
		input = new(spec.Swagger)
		input.Swagger = "2.0"
	}

	if input.Paths == nil {
		input.Paths = new(spec.Paths)
	}
	if input.Definitions == nil {
		input.Definitions = make(map[string]spec.Schema)
	}
	if input.Responses == nil {
		input.Responses = make(map[string]spec.Response)
	}

	return &appScanner{
		MainPackage: bp,
		prog:        prog,
		input:       input,
		loader:      &ldr,
		operations:  collectOperationsFromInput(input),
		definitions: input.Definitions,
		responses:   input.Responses,
		classifier: &programClassifier{
			Includes: includes,
			Excludes: excludes,
		},
	}, nil
}
Beispiel #25
0
func TestLoad_vendor(t *testing.T) {
	if buildutil.AllowVendor == 0 {
		// Vendoring requires Go 1.6.
		// TODO(adonovan): delete in due course.
		t.Skip()
	}
	pkgs := map[string]string{
		"a":          `package a; import _ "x"`,
		"a/vendor":   ``, // mkdir a/vendor
		"a/vendor/x": `package xa`,
		"b":          `package b; import _ "x"`,
		"b/vendor":   ``, // mkdir b/vendor
		"b/vendor/x": `package xb`,
		"c":          `package c; import _ "x"`,
		"x":          `package xc`,
	}
	conf := loader.Config{Build: fakeContext(pkgs)}
	conf.Import("a")
	conf.Import("b")
	conf.Import("c")

	prog, err := conf.Load()
	if err != nil {
		t.Fatal(err)
	}

	// Check that a, b, and c see different versions of x.
	for _, r := range "abc" {
		name := string(r)
		got := prog.Package(name).Pkg.Imports()[0]
		want := "x" + name
		if got.Name() != want {
			t.Errorf("package %s import %q = %s, want %s",
				name, "x", got.Name(), want)
		}
	}
}
Beispiel #26
0
func classifierProgram() *loader.Program {
	var ldr loader.Config
	ldr.ParserMode = goparser.ParseComments
	ldr.Import("../fixtures/goparsing/classification")
	ldr.Import("../fixtures/goparsing/classification/models")
	ldr.Import("../fixtures/goparsing/classification/operations")
	prog, err := ldr.Load()
	if err != nil {
		log.Fatal(err)
	}
	return prog
}
Beispiel #27
0
func bundle(w io.Writer, initialPkg, dest, prefix string) error {
	// Load the initial package.
	conf := loader.Config{ParserMode: parser.ParseComments, Build: ctxt}
	conf.TypeCheckFuncBodies = func(p string) bool { return p == initialPkg }
	conf.Import(initialPkg)

	lprog, err := conf.Load()
	if err != nil {
		log.Fatal(err)
	}

	info := lprog.Package(initialPkg)

	objsToUpdate := make(map[types.Object]bool)
	var rename func(from types.Object)
	rename = func(from types.Object) {
		if !objsToUpdate[from] {
			objsToUpdate[from] = true

			// Renaming a type that is used as an embedded field
			// requires renaming the field too. e.g.
			// 	type T int // if we rename this to U..
			// 	var s struct {T}
			// 	print(s.T) // ...this must change too
			if _, ok := from.(*types.TypeName); ok {
				for id, obj := range info.Uses {
					if obj == from {
						if field := info.Defs[id]; field != nil {
							rename(field)
						}
					}
				}
			}
		}
	}

	// Rename each package-level object.
	scope := info.Pkg.Scope()
	for _, name := range scope.Names() {
		rename(scope.Lookup(name))
	}

	var out bytes.Buffer

	fmt.Fprintf(&out, "// Code generated by golang.org/x/tools/cmd/bundle command:\n")
	fmt.Fprintf(&out, "//   $ bundle %s %s %s\n\n", initialPkg, dest, prefix)

	// Concatenate package comments from of all files.
	for _, f := range info.Files {
		if doc := f.Doc.Text(); strings.TrimSpace(doc) != "" {
			for _, line := range strings.Split(doc, "\n") {
				fmt.Fprintf(&out, "// %s\n", line)
			}
		}
	}

	// TODO(adonovan): don't assume pkg.name == basename(pkg.path).
	fmt.Fprintf(&out, "package %s\n\n", filepath.Base(dest))

	// Print a single declaration that imports all necessary packages.
	// TODO(adonovan):
	// - support renaming imports.
	// - preserve comments from the original import declarations.
	for _, f := range info.Files {
		for _, imp := range f.Imports {
			if imp.Name != nil {
				log.Fatalf("%s: renaming imports not supported",
					lprog.Fset.Position(imp.Pos()))
			}
		}
	}
	fmt.Fprintln(&out, "import (")
	for _, p := range info.Pkg.Imports() {
		if p.Path() == dest {
			continue
		}
		fmt.Fprintf(&out, "\t%q\n", p.Path())
	}
	fmt.Fprintln(&out, ")\n")

	// Modify and print each file.
	for _, f := range info.Files {
		// Update renamed identifiers.
		for id, obj := range info.Defs {
			if objsToUpdate[obj] {
				id.Name = prefix + obj.Name()
			}
		}
		for id, obj := range info.Uses {
			if objsToUpdate[obj] {
				id.Name = prefix + obj.Name()
			}
		}

		// For each qualified identifier that refers to the
		// destination package, remove the qualifier.
		// The "@@@." strings are removed in postprocessing.
		ast.Inspect(f, func(n ast.Node) bool {
			if sel, ok := n.(*ast.SelectorExpr); ok {
				if id, ok := sel.X.(*ast.Ident); ok {
					if obj, ok := info.Uses[id].(*types.PkgName); ok {
						if obj.Imported().Path() == dest {
							id.Name = "@@@"
						}
					}
				}
			}
			return true
		})

		// Pretty-print package-level declarations.
		// but no package or import declarations.
		//
		// TODO(adonovan): this may cause loss of comments
		// preceding or associated with the package or import
		// declarations or not associated with any declaration.
		// Check.
		var buf bytes.Buffer
		for _, decl := range f.Decls {
			if decl, ok := decl.(*ast.GenDecl); ok && decl.Tok == token.IMPORT {
				continue
			}
			buf.Reset()
			format.Node(&buf, lprog.Fset, decl)
			// Remove each "@@@." in the output.
			// TODO(adonovan): not hygienic.
			out.Write(bytes.Replace(buf.Bytes(), []byte("@@@."), nil, -1))
			out.WriteString("\n\n")
		}
	}

	// Now format the entire thing.
	result, err := format.Source(out.Bytes())
	if err != nil {
		log.Fatalf("formatting failed: %v", err)
	}

	_, err = w.Write(result)
	return err
}
Beispiel #28
0
func TestBExportData_stdlib(t *testing.T) {
	if runtime.GOOS == "android" {
		t.Skipf("incomplete std lib on %s", runtime.GOOS)
	}

	// Load, parse and type-check the program.
	ctxt := build.Default // copy
	ctxt.GOPATH = ""      // disable GOPATH
	conf := loader.Config{
		Build:       &ctxt,
		AllowErrors: true,
	}
	for _, path := range buildutil.AllPackages(conf.Build) {
		conf.Import(path)
	}

	// Create a package containing type and value errors to ensure
	// they are properly encoded/decoded.
	f, err := conf.ParseFile("haserrors/haserrors.go", `package haserrors
const UnknownValue = "" + 0
type UnknownType undefined
`)
	if err != nil {
		t.Fatal(err)
	}
	conf.CreateFromFiles("haserrors", f)

	prog, err := conf.Load()
	if err != nil {
		t.Fatalf("Load failed: %v", err)
	}

	numPkgs := len(prog.AllPackages)
	if want := 248; numPkgs < want {
		t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
	}

	for pkg, info := range prog.AllPackages {
		if info.Files == nil {
			continue // empty directory
		}
		exportdata := gcimporter.BExportData(conf.Fset, pkg)

		imports := make(map[string]*types.Package)
		fset2 := token.NewFileSet()
		n, pkg2, err := gcimporter.BImportData(fset2, imports, exportdata, pkg.Path())
		if err != nil {
			t.Errorf("BImportData(%s): %v", pkg.Path(), err)
			continue
		}
		if n != len(exportdata) {
			t.Errorf("BImportData(%s) decoded %d bytes, want %d",
				pkg.Path(), n, len(exportdata))
		}

		// Compare the packages' corresponding members.
		for _, name := range pkg.Scope().Names() {
			if !ast.IsExported(name) {
				continue
			}
			obj1 := pkg.Scope().Lookup(name)
			obj2 := pkg2.Scope().Lookup(name)
			if obj2 == nil {
				t.Errorf("%s.%s not found, want %s", pkg.Path(), name, obj1)
				continue
			}

			fl1 := fileLine(conf.Fset, obj1)
			fl2 := fileLine(fset2, obj2)
			if fl1 != fl2 {
				t.Errorf("%s.%s: got posn %s, want %s",
					pkg.Path(), name, fl2, fl1)
			}

			if err := equalObj(obj1, obj2); err != nil {
				t.Errorf("%s.%s: %s\ngot:  %s\nwant: %s",
					pkg.Path(), name, err, obj2, obj1)
			}
		}
	}
}
Beispiel #29
0
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)
	}

	var conf loader.Config
	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 golang.org/x/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 := ssautil.CreateProgram(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 golang.org/x/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
}
Beispiel #30
0
func doMain() error {
	flag.Parse()
	args := flag.Args()

	conf := loader.Config{Build: &build.Default}

	// Choose types.Sizes from conf.Build.
	var wordSize int64 = 8
	switch conf.Build.GOARCH {
	case "386", "arm":
		wordSize = 4
	}
	conf.TypeChecker.Sizes = &types.StdSizes{
		MaxAlign: 8,
		WordSize: wordSize,
	}

	var interpMode interp.Mode
	for _, c := range *interpFlag {
		switch c {
		case 'T':
			interpMode |= interp.EnableTracing
		case 'R':
			interpMode |= interp.DisableRecover
		default:
			return fmt.Errorf("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 {
			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 := ssautil.CreateProgram(iprog, *modeFlag)

	// Build and display only the initial packages
	// (and synthetic wrappers), unless -run is specified.
	for _, info := range iprog.InitialPackages() {
		prog.Package(info.Pkg).Build()
	}

	// Run the interpreter.
	if *runFlag {
		prog.Build()

		var main *ssa.Package
		pkgs := prog.AllPackages()
		if *testFlag {
			// If -test, run all packages' tests.
			if len(pkgs) > 0 {
				main = prog.CreateTestMainPackage(pkgs...)
			}
			if main == nil {
				return fmt.Errorf("no tests")
			}
		} else {
			// Otherwise, run main.main.
			for _, pkg := range pkgs {
				if pkg.Pkg.Name() == "main" {
					main = pkg
					if main.Func("main") == nil {
						return fmt.Errorf("no func main() in main package")
					}
					break
				}
			}
			if main == nil {
				return fmt.Errorf("no main package")
			}
		}

		if runtime.GOARCH != build.Default.GOARCH {
			return fmt.Errorf("cross-interpretation is not supported (target has GOARCH %s, interpreter has %s)",
				build.Default.GOARCH, runtime.GOARCH)
		}

		interp.Interpret(main, interpMode, conf.TypeChecker.Sizes, main.Pkg.Path(), args)
	}
	return nil
}