Пример #1
0
// 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
}
Пример #2
0
// parseFromFlag interprets the "-from" flag value as a renaming specification.
// See FromFlagUsage 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)
	}

	// main is one of:
	//  filename.go
	//  importpath
	//  importpath.member
	//  (importpath.type).fieldormethod

	if strings.HasSuffix(main, ".go") {
		// 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 if a, b := splitAtLastDot(main); b == "" {
		// importpath e.g. "encoding/json"
		if spec.searchFor == "" {
			return nil, fmt.Errorf("-from %q: package import path %q must have a ::name suffix",
				main, a)
		}
		spec.pkg = a

	} else if strings.HasPrefix(a, "(") && strings.HasSuffix(a, ")") {
		// field/method of type e.g. (encoding/json.Decoder).Decode
		c, d := splitAtLastDot(a[1 : len(a)-1])
		if d == "" {
			return nil, fmt.Errorf("-from %q: not a package-level named type: %q", a)
		}
		spec.pkg = c        // e.g. "encoding/json"
		spec.pkgMember = d  // e.g. "Decoder"
		spec.typeMember = b // e.g. "Decode"
		spec.fromName = b

	} else {
		// package member e.g. "encoding/json.HTMLEscape"
		spec.pkg = a       // e.g. "encoding/json"
		spec.pkgMember = b // e.g.  "HTMLEscape"
		spec.fromName = b
	}

	if spec.searchFor != "" {
		spec.fromName = spec.searchFor
	}

	// Sanitize the package.
	// TODO(adonovan): test with relative packages.  May need loader changes.
	bp, err := ctxt.Import(spec.pkg, ".", 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 {
		fmt.Fprintf(os.Stderr, "-from spec: %+v\n", spec)
	}

	return &spec, nil
}
Пример #3
0
// parseFromFlag interprets the "-from" flag value as a renaming specification.
// See FromFlagUsage 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
	}

	// Sanitize the package.
	// TODO(adonovan): test with relative packages.  May need loader changes.
	bp, err := ctxt.Import(spec.pkg, ".", 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 {
		fmt.Fprintf(os.Stderr, "-from spec: %+v\n", spec)
	}

	return &spec, nil
}