func TestContainingPackage(t *testing.T) { // unvirtualized: goroot := runtime.GOROOT() gopath := filepath.SplitList(os.Getenv("GOPATH"))[0] for _, test := range [][2]string{ {goroot + "/src/fmt/print.go", "fmt"}, {goroot + "/src/encoding/json/foo.go", "encoding/json"}, {goroot + "/src/encoding/missing/foo.go", "(not found)"}, {gopath + "/src/golang.org/x/tools/go/buildutil/util_test.go", "golang.org/x/tools/go/buildutil"}, } { file, want := test[0], test[1] bp, err := buildutil.ContainingPackage(&build.Default, ".", file) got := bp.ImportPath if err != nil { got = "(not found)" } if got != want { t.Errorf("ContainingPackage(%q) = %s, want %s", file, got, want) } } // TODO(adonovan): test on virtualized GOPATH too. }
// Run is a wrapper for the gogetdoc command. It is broken out of main for easier testing. func Run(ctx *build.Context, filename string, offset int64) (*Doc, error) { wd, err := os.Getwd() if err != nil { return nil, errors.New("gogetdoc: couldn't get working directory") } bp, err := buildutil.ContainingPackage(ctx, wd, filename) if err != nil { return nil, fmt.Errorf("gogetdoc: couldn't get package for %s: %s", filename, err.Error()) } conf := &loader.Config{ Build: ctx, ParserMode: parser.ParseComments, TypeCheckFuncBodies: func(pkg string) bool { return pkg == bp.ImportPath }, AllowErrors: true, } var parseError error conf.TypeChecker.Error = func(err error) { if parseError != nil { return } parseError = err } conf.ImportWithTests(bp.ImportPath) lprog, err := conf.Load() if err != nil { return nil, fmt.Errorf("gogetdoc: error loading program: %s", err.Error()) } doc, err := DocForPos(ctx, lprog, filename, offset) if err != nil && parseError != nil { fmt.Fprintln(os.Stderr, parseError) } return doc, err }
func TestContainingPackage(t *testing.T) { // unvirtualized: goroot := runtime.GOROOT() gopath := filepath.SplitList(os.Getenv("GOPATH"))[0] tests := [][2]string{ {goroot + "/src/fmt/print.go", "fmt"}, {goroot + "/src/encoding/json/foo.go", "encoding/json"}, {goroot + "/src/encoding/missing/foo.go", "(not found)"}, {gopath + "/src/golang.org/x/tools/go/buildutil/util_test.go", "golang.org/x/tools/go/buildutil"}, } // TODO(adonovan): simplify after Go 1.6. if buildutil.AllowVendor != 0 { tests = append(tests, [2]string{ gopath + "/src/vendor/golang.org/x/net/http2/hpack/hpack.go", "vendor/golang.org/x/net/http2/hpack", }) } for _, test := range tests { file, want := test[0], test[1] bp, err := buildutil.ContainingPackage(&build.Default, ".", file) got := bp.ImportPath if err != nil { got = "(not found)" } if got != want { t.Errorf("ContainingPackage(%q) = %s, want %s", file, got, want) } } // TODO(adonovan): test on virtualized GOPATH too. }
func testContainingPackageCaseFold(file, want string) error { bp, err := buildutil.ContainingPackage(&build.Default, ".", file) if err != nil { return err } if got := bp.ImportPath; got != want { return fmt.Errorf("ContainingPackage(%q) = %s, want %s", file, got, want) } return nil }
// parseOffsetFlag interprets the "-offset" flag value as a renaming specification. func parseOffsetFlag(ctxt *build.Context, offsetFlag string) (*spec, error) { var spec spec // Validate -offset, e.g. file.go:#123 parts := strings.Split(offsetFlag, ":#") if len(parts) != 2 { return nil, fmt.Errorf("-offset %q: invalid offset specification", offsetFlag) } spec.filename = parts[0] if !buildutil.FileExists(ctxt, spec.filename) { return nil, fmt.Errorf("no such file: %s", spec.filename) } bp, err := buildutil.ContainingPackage(ctxt, wd, spec.filename) if err != nil { return nil, err } spec.pkg = bp.ImportPath for _, r := range parts[1] { if !isDigit(r) { return nil, fmt.Errorf("-offset %q: non-numeric offset", offsetFlag) } } spec.offset, err = strconv.Atoi(parts[1]) if err != nil { return nil, fmt.Errorf("-offset %q: non-numeric offset", offsetFlag) } // Parse the file and check there's an identifier at that offset. fset := token.NewFileSet() f, err := buildutil.ParseFile(fset, ctxt, nil, wd, spec.filename, parser.ParseComments) if err != nil { return nil, fmt.Errorf("-offset %q: cannot parse file: %s", offsetFlag, err) } id := identAtOffset(fset, f, spec.offset) if id == nil { return nil, fmt.Errorf("-offset %q: no identifier at this position", offsetFlag) } spec.fromName = id.Name return &spec, nil }
// parseFromFlag interprets the "-from" flag value as a renaming specification. // See Usage in rename.go for valid formats. func parseFromFlag(ctxt *build.Context, fromFlag string) (*spec, error) { var spec spec var main string // sans "::x" suffix switch parts := strings.Split(fromFlag, "::"); len(parts) { case 1: main = parts[0] case 2: main = parts[0] spec.searchFor = parts[1] if parts[1] == "" { // error } default: return nil, fmt.Errorf("-from %q: invalid identifier specification (see -help for formats)", fromFlag) } if strings.HasSuffix(main, ".go") { // main is "filename.go" if spec.searchFor == "" { return nil, fmt.Errorf("-from: filename %q must have a ::name suffix", main) } spec.filename = main if !buildutil.FileExists(ctxt, spec.filename) { return nil, fmt.Errorf("no such file: %s", spec.filename) } bp, err := buildutil.ContainingPackage(ctxt, wd, spec.filename) if err != nil { return nil, err } spec.pkg = bp.ImportPath } else { // main is one of: // "importpath" // "importpath".member // (*"importpath".type).fieldormethod (parens and star optional) if err := parseObjectSpec(&spec, main); err != nil { return nil, err } } if spec.searchFor != "" { spec.fromName = spec.searchFor } cwd, err := os.Getwd() if err != nil { return nil, err } // Sanitize the package. bp, err := ctxt.Import(spec.pkg, cwd, build.FindOnly) if err != nil { return nil, fmt.Errorf("can't find package %q", spec.pkg) } spec.pkg = bp.ImportPath if !isValidIdentifier(spec.fromName) { return nil, fmt.Errorf("-from: invalid identifier %q", spec.fromName) } if Verbose { log.Printf("-from spec: %+v", spec) } return &spec, nil }