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) }
func loadProgram(args []string, tests bool) (*ssa.Program, error) { conf := loader.Config{} if len(args) == 0 { fmt.Fprintln(os.Stderr, Usage) os.Exit(1) } // Use the initial packages from the command line. args, err := conf.FromArgs(args, tests) if err != nil { return nil, err } // Load, parse and type-check the whole program. iprog, err := conf.Load() if err != nil { return nil, err } // Create and build SSA-form program representation. prog := ssautil.CreateProgram(iprog, 0) prog.BuildAll() return prog, nil }
// Return count of unused vars func myloader(args []string) (count int) { var conf loader.Config conf.FromArgs(args, false) prog, err := conf.Load() if err != nil { log.Fatal(err) } for _, pi := range prog.Created { fmt.Println(pi) } info := prog.Package(args[0]).Info fset := prog.Fset ssaprog := ssautil.CreateProgram(prog, ssa.GlobalDebug) ssaprog.Build() for expr, object := range info.Defs { unused := checkObj(expr, object, prog, ssaprog, fset) if unused { fmt.Fprintf(os.Stderr, "Unused assignment for '%v' %v\n", expr, fset.Position(expr.Pos())) count++ } } for expr, object := range info.Uses { unused := checkObj(expr, object, prog, ssaprog, fset) if unused { fmt.Fprintf(os.Stderr, "Unused assignment for '%v' %v\n", expr, fset.Position(expr.Pos())) count++ } } return count }
func TestLoad_FromImports_Success(t *testing.T) { var conf loader.Config conf.ImportWithTests("fmt") 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 fmt_test"; got != want { t.Errorf("Created = %q, want %s", got, want) } if got, want := imported(prog), "errors fmt"; got != want { t.Errorf("Imported = %s, want %s", got, want) } // Check set of transitive packages. // There are >30 and the set may grow over time, so only check a few. want := map[string]bool{ "strings": true, "time": true, "runtime": true, "testing": true, "unicode": true, } for _, path := range all(prog) { delete(want, path) } if len(want) > 0 { t.Errorf("AllPackages is missing these keys: %q", keys(want)) } }
func TestLoad_ParseError_AllowErrors(t *testing.T) { var conf loader.Config conf.AllowErrors = true conf.CreateFromFilenames("badpkg", "testdata/badpkgdecl.go") 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), "badpkg"; got != want { t.Errorf("Created = %s, want %s", got, want) } badpkg := prog.Created[0] if len(badpkg.Files) != 1 { t.Errorf("badpkg has %d files, want 1", len(badpkg.Files)) } wantErr := filepath.Join("testdata", "badpkgdecl.go") + ":1:34: expected 'package', found 'EOF'" if !hasError(badpkg.Errors, wantErr) { t.Errorf("badpkg.Errors = %v, want %s", badpkg.Errors, wantErr) } }
// loadWithSoftErrors calls lconf.Load, suppressing "soft" errors. (See Go issue 16530.) // TODO(adonovan): Once the loader has an option to allow soft errors, // replace calls to loadWithSoftErrors with loader calls with that parameter. func loadWithSoftErrors(lconf *loader.Config) (*loader.Program, error) { lconf.AllowErrors = true // Ideally we would just return conf.Load() here, but go/types // reports certain "soft" errors that gc does not (Go issue 14596). // As a workaround, we set AllowErrors=true and then duplicate // the loader's error checking but allow soft errors. // It would be nice if the loader API permitted "AllowErrors: soft". prog, err := lconf.Load() if err != nil { return nil, err } var errpkgs []string // Report hard errors in indirectly imported packages. for _, info := range prog.AllPackages { if containsHardErrors(info.Errors) { errpkgs = append(errpkgs, info.Pkg.Path()) } else { // Enable SSA construction for packages containing only soft errors. info.TransitivelyErrorFree = true } } if errpkgs != nil { var more string if len(errpkgs) > 3 { more = fmt.Sprintf(" and %d more", len(errpkgs)-3) errpkgs = errpkgs[:3] } return nil, fmt.Errorf("couldn't load packages due to errors: %s%s", strings.Join(errpkgs, ", "), more) } return prog, err }
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) } } } }
func TestStdlib(t *testing.T) { defer func(saved func(format string, args ...interface{})) { logf = saved }(logf) logf = t.Errorf ctxt := build.Default // copy // Enumerate $GOROOT packages. saved := ctxt.GOPATH ctxt.GOPATH = "" // disable GOPATH during AllPackages pkgs := buildutil.AllPackages(&ctxt) ctxt.GOPATH = saved // Throw in a number of go.tools packages too. pkgs = append(pkgs, "golang.org/x/tools/cmd/godoc", "golang.org/x/tools/refactor/lexical") // Load, parse and type-check the program. conf := loader.Config{Build: &ctxt} for _, path := range pkgs { conf.ImportWithTests(path) } iprog, err := conf.Load() if err != nil { t.Fatalf("Load failed: %v", err) } // This test ensures that Structure doesn't panic and that // its internal sanity-checks against go/types don't fail. for pkg, info := range iprog.AllPackages { _ = Structure(iprog.Fset, pkg, &info.Info, info.Files) } }
// 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] }
// loadProgram loads the specified set of packages (plus their tests) // and all their dependencies, from source, through the specified build // context. Only packages in pkgs will have their functions bodies typechecked. func loadProgram(ctxt *build.Context, pkgs map[string]bool) (*loader.Program, error) { conf := loader.Config{ Build: ctxt, SourceImports: true, ParserMode: parser.ParseComments, // TODO(adonovan): enable this. Requires making a lot of code more robust! AllowErrors: false, } // Optimization: don't type-check the bodies of functions in our // dependencies, since we only need exported package members. conf.TypeCheckFuncBodies = func(p string) bool { return pkgs[p] || pkgs[strings.TrimSuffix(p, "_test")] } if Verbose { var list []string for pkg := range pkgs { list = append(list, pkg) } sort.Strings(list) for _, pkg := range list { fmt.Fprintf(os.Stderr, "Loading package: %s\n", pkg) } } for pkg := range pkgs { if err := conf.ImportWithTests(pkg); err != nil { return nil, err } } return conf.Load() }
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 }) } } }
// Create unexporter func NewUnexporter(o *Config) (*unexporter, error) { var conf loader.Config for _, package_name := range buildutil.AllPackages(&build.Default) { conf.ImportWithTests(package_name) } program, err := conf.Load() if err != nil { return nil, err } if program.Package(o.Pkg) == nil { return nil, errors.New(fmt.Sprintf("'%s' is not a valid package", o.Pkg)) } if o.Debug { pkg := program.Package(o.Pkg).Pkg fmt.Printf("finding unused identifiers for %s (%s)\n", pkg.Name(), pkg.Path()) } unexporter := &unexporter{ Program: program, MainPackage: program.Package(o.Pkg), Verbose: o.Debug, } unexporter.run() return unexporter, nil }
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) } } }
func (p *Parser) Parse(path string) error { dir := filepath.Dir(path) files, err := ioutil.ReadDir(dir) if err != nil { fmt.Printf("// [ERROR] Parse(%s) -> ioutil.ReadDir(%#v) -> err=<%#v>\n", path, dir, err) return err } var astFiles []*ast.File var conf loader.Config conf.TypeCheckFuncBodies = func(_ string) bool { return false } conf.TypeChecker.DisableUnusedImportCheck = true conf.TypeChecker.Importer = importer.Default() for _, fi := range files { if filepath.Ext(fi.Name()) != ".go" { continue } fpath := filepath.Join(dir, fi.Name()) f, err := conf.ParseFile(fpath, nil) if err != nil { fmt.Printf("// [ERROR] Parse(%s) -> conf.ParseFile(%#v) -> err=<%#v>\n", path, fpath, err) return err } if fi.Name() == filepath.Base(path) { p.file = f } astFiles = append(astFiles, f) } abs, err := filepath.Abs(path) if err != nil { fmt.Printf("// [ERROR] Parse(%s) -> filepath.Abs(%#v) -> err=<%#v>\n", path, path, err) return err } // Type-check a package consisting of this file. // Type information for the imported packages // comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a. conf.CreateFromFiles(abs, astFiles...) prog, err := conf.Load() if err != nil { fmt.Printf("// [ERROR] Parse(%s) -> conf.Load() -> err=<%#v>\n", path, err) return err } else if len(prog.Created) != 1 { panic("expected only one Created package") } p.path = abs p.pkg = prog.Created[0].Pkg return nil }
// createProgram returns a program containing packages specified. func createProgram(packages ...string) (*loader.Program, error) { var conf loader.Config for _, name := range packages { conf.CreateFromFilenames(name, getFileNames(name)...) } return conf.Load() }
// Build constructs the SSA IR using given config, and sets up pointer analysis. func (conf *Config) Build() (*SSAInfo, error) { var lconf = loader.Config{Build: &build.Default} buildLog := log.New(conf.BuildLog, "ssabuild: ", conf.LogFlags) if conf.BuildMode == FromFiles { args, err := lconf.FromArgs(conf.Files, false /* No tests */) if err != nil { return nil, err } if len(args) > 0 { return nil, fmt.Errorf("surplus arguments: %q", args) } } else if conf.BuildMode == FromString { f, err := lconf.ParseFile("", conf.Source) if err != nil { return nil, err } lconf.CreateFromFiles("", f) } else { buildLog.Fatal("Unknown build mode") } // Load, parse and type-check program lprog, err := lconf.Load() if err != nil { return nil, err } buildLog.Print("Program loaded and type checked") prog := ssautil.CreateProgram(lprog, ssa.GlobalDebug|ssa.BareInits) // Prepare Config for whole-program pointer analysis. ptaConf, err := setupPTA(prog, lprog, conf.PtaLog) ignoredPkgs := []string{} if len(conf.BadPkgs) == 0 { prog.Build() } else { for _, info := range lprog.AllPackages { if reason, badPkg := conf.BadPkgs[info.Pkg.Name()]; badPkg { buildLog.Printf("Skip package: %s (%s)", info.Pkg.Name(), reason) ignoredPkgs = append(ignoredPkgs, info.Pkg.Name()) } else { prog.Package(info.Pkg).Build() } } } return &SSAInfo{ BuildConf: conf, IgnoredPkgs: ignoredPkgs, FSet: lprog.Fset, Prog: prog, PtaConf: ptaConf, Logger: buildLog, }, nil }
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) } } }
// Query runs a single oracle query. // // args specify the main package in (*loader.Config).FromArgs syntax. // mode is the query mode ("callers", etc). // ptalog is the (optional) pointer-analysis log file. // buildContext is the go/build configuration for locating packages. // reflection determines whether to model reflection soundly (currently slow). // // Clients that intend to perform multiple queries against the same // analysis scope should use this pattern instead: // // conf := loader.Config{Build: buildContext, SourceImports: true} // ... populate config, e.g. conf.FromArgs(args) ... // iprog, err := conf.Load() // if err != nil { ... } // o, err := oracle.New(iprog, nil, false) // if err != nil { ... } // for ... { // qpos, err := oracle.ParseQueryPos(imp, pos, needExact) // if err != nil { ... } // // res, err := o.Query(mode, qpos) // if err != nil { ... } // // // use res // } // // TODO(adonovan): the ideal 'needsExact' parameter for ParseQueryPos // depends on the query mode; how should we expose this? // func Query(args []string, mode, pos string, ptalog io.Writer, buildContext *build.Context, reflection bool) (*Result, error) { if mode == "what" { // Bypass package loading, type checking, SSA construction. return what(pos, buildContext) } minfo := findMode(mode) if minfo == nil { return nil, fmt.Errorf("invalid mode type: %q", mode) } conf := loader.Config{Build: buildContext, SourceImports: true} // Determine initial packages. args, err := conf.FromArgs(args, true) if err != nil { return nil, err } if len(args) > 0 { return nil, fmt.Errorf("surplus arguments: %q", args) } // For queries needing only a single typed package, // reduce the analysis scope to that package. if minfo.needs&(needSSA|needRetainTypeInfo) == 0 { reduceScope(pos, &conf) } // TODO(adonovan): report type errors to the user via Serial // types, not stderr? // conf.TypeChecker.Error = func(err error) { // E := err.(types.Error) // fmt.Fprintf(os.Stderr, "%s: %s\n", E.Fset.Position(E.Pos), E.Msg) // } // Load/parse/type-check the program. iprog, err := conf.Load() if err != nil { return nil, err } o, err := newOracle(iprog, ptalog, minfo.needs, reflection) if err != nil { return nil, err } qpos, err := ParseQueryPos(iprog, pos, minfo.needs&needExactPos != 0) if err != nil && minfo.needs&(needPos|needExactPos) != 0 { return nil, err } // SSA is built and we have the QueryPos. // Release the other ASTs and type info to the GC. iprog = nil return o.query(minfo, qpos) }
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) } }
func TestSwitches(t *testing.T) { conf := loader.Config{ParserMode: parser.ParseComments} f, err := conf.ParseFile("testdata/switches.go", nil) if err != nil { t.Error(err) return } conf.CreateFromFiles("main", f) iprog, err := conf.Load() if err != nil { t.Error(err) return } prog := ssautil.CreateProgram(iprog, 0) mainPkg := prog.Package(iprog.Created[0].Pkg) mainPkg.Build() for _, mem := range mainPkg.Members { if fn, ok := mem.(*ssa.Function); ok { if fn.Synthetic != "" { continue // e.g. init() } // Each (multi-line) "switch" comment within // this function must match the printed form // of a ConstSwitch. var wantSwitches []string for _, c := range f.Comments { if fn.Syntax().Pos() <= c.Pos() && c.Pos() < fn.Syntax().End() { text := strings.TrimSpace(c.Text()) if strings.HasPrefix(text, "switch ") { wantSwitches = append(wantSwitches, text) } } } switches := ssautil.Switches(fn) if len(switches) != len(wantSwitches) { t.Errorf("in %s, found %d switches, want %d", fn, len(switches), len(wantSwitches)) } for i, sw := range switches { got := sw.String() if i >= len(wantSwitches) { continue } want := wantSwitches[i] if got != want { t.Errorf("in %s, found switch %d: got <<%s>>, want <<%s>>", fn, i, got, want) } } } } }
func TestCreateUnnamedPackage(t *testing.T) { var conf loader.Config conf.CreateFromFilenames("") prog, err := conf.Load() if err != nil { t.Fatalf("Load failed: %v", err) } if got, want := fmt.Sprint(prog.InitialPackages()), "[(unnamed)]"; got != want { t.Errorf("InitialPackages = %s, want %s", got, want) } }
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() }
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 }
func TestLoad_MissingFileInCreatedPackage_AllowErrors(t *testing.T) { conf := loader.Config{AllowErrors: true} conf.CreateFromFilenames("", "missing.go") prog, err := conf.Load() if err != nil { t.Errorf("Load failed: %v", err) } if got, want := fmt.Sprint(prog.InitialPackages()), "[(unnamed)]"; got != want { t.Fatalf("InitialPackages = %s, want %s", got, want) } }
// 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) } }
func genPkg(pkg *build.Package) { if len(pkg.CgoFiles) > 0 { errorf("gobind: cannot use cgo-dependent package as service definition: %s", pkg.CgoFiles[0]) return } files := parseFiles(pkg.Dir, pkg.GoFiles) if len(files) == 0 { return // some error has been reported } conf := loader.Config{ Fset: fset, } conf.TypeChecker.Error = func(err error) { errorf("%v", err) } conf.CreateFromFiles(pkg.ImportPath, files...) program, err := conf.Load() if err != nil { errorf("%v", err) return } p := program.Created[0].Pkg fname := defaultFileName(*lang, p) switch *lang { case "java": w, closer := writer(fname, p) processErr(bind.GenJava(w, fset, p)) closer() case "go": w, closer := writer(fname, p) processErr(bind.GenGo(w, fset, p)) closer() case "objc": if fname == "" { processErr(bind.GenObjc(os.Stdout, fset, p, true)) processErr(bind.GenObjc(os.Stdout, fset, p, false)) } else { hname := fname[:len(fname)-2] + ".h" w, closer := writer(hname, p) processErr(bind.GenObjc(w, fset, p, true)) closer() w, closer = writer(fname, p) processErr(bind.GenObjc(w, fset, p, false)) closer() } default: errorf("unknown target language: %q", *lang) } }
func newBinder(bindPkg *build.Package) (*binder, error) { if bindPkg.Name == "main" { return nil, fmt.Errorf("package %q: can only bind a library package", bindPkg.Name) } if len(bindPkg.CgoFiles) > 0 { return nil, fmt.Errorf("cannot use cgo-dependent package as service definition: %s", bindPkg.CgoFiles[0]) } fset := token.NewFileSet() hasErr := false var files []*ast.File for _, filename := range bindPkg.GoFiles { p := filepath.Join(bindPkg.Dir, filename) file, err := parser.ParseFile(fset, p, nil, parser.AllErrors) if err != nil { hasErr = true if list, _ := err.(scanner.ErrorList); len(list) > 0 { for _, err := range list { fmt.Fprintln(os.Stderr, err) } } else { fmt.Fprintln(os.Stderr, err) } } files = append(files, file) } if hasErr { return nil, errors.New("package parsing failed.") } conf := loader.Config{ Fset: fset, } conf.TypeChecker.Error = func(err error) { fmt.Fprintln(os.Stderr, err) } conf.CreateFromFiles(bindPkg.ImportPath, files...) program, err := conf.Load() if err != nil { return nil, err } b := &binder{ files: files, fset: fset, pkg: program.Created[0].Pkg, } return b, nil }
func classifierProgram() *loader.Program { var ldr loader.Config ldr.ParserMode = goparser.ParseComments ldr.Build = &gobuild.Default ldr.ImportWithTests("github.com/go-swagger/go-swagger/fixtures/goparsing/classification") ldr.ImportWithTests("github.com/go-swagger/go-swagger/fixtures/goparsing/classification/models") ldr.ImportWithTests("github.com/go-swagger/go-swagger/fixtures/goparsing/classification/operations") prog, err := ldr.Load() if err != nil { log.Fatal(err) } return prog }
func petstoreProgram() *loader.Program { var ldr loader.Config ldr.ParserMode = goparser.ParseComments ldr.Build = &gobuild.Default ldr.ImportWithTests("github.com/go-swagger/go-swagger/fixtures/goparsing/petstore") ldr.ImportWithTests("github.com/go-swagger/go-swagger/fixtures/goparsing/petstore/models") ldr.ImportWithTests("github.com/go-swagger/go-swagger/fixtures/goparsing/petstore/rest/handlers") prog, err := ldr.Load() if err != nil { log.Fatal(err) } return prog }