func findFromObjects(iprog *loader.Program, spec *spec) ([]types.Object, error) {
	if spec.filename != "" {
		return findFromObjectsInFile(iprog, spec)
	}
	var info *loader.PackageInfo
	var pkg *types.Package
	for pkg, info = range iprog.AllPackages {
		if pkg.Path() == spec.pkg {
			break
		}
	}
	if info == nil {
		return nil, fmt.Errorf("package %q was not loaded", spec.pkg)
	}
	objects, err := findObjects(info, spec)
	if err != nil {
		return nil, err
	}
	if len(objects) > 1 {
		return nil, ambiguityError(iprog.Fset, objects)
	}
	return objects, nil
}
For source trees built with 'go build', the -from or -offset
spec identifies exactly one initial 'from' object to rename ,
but certain proprietary build systems allow a single file to
appear in multiple packages (e.g. the test package contains a
copy of its library), so there may be multiple objects for
the same source entity.
package main
import (
	"bytes"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"go/types"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"golang.org/x/tools/go/buildutil"
	"golang.org/x/tools/go/loader"
)
type spec struct {
	pkg string
	fromName string
	searchFor string
	pkgMember string
	typeMember string
	filename string
	offset int
}
func parseFromFlag(ctxt *build.Context, fromFlag string) (*spec, error) {
	var spec spec
	var main string  
	switch parts := strings.Split(fromFlag, "::"); len(parts) {
	case 1:
		main = parts[0]
	case 2:
		main = parts[0]
		spec.searchFor = parts[1]
		if parts[1] == "" {
		}
	default:
		return nil, fmt.Errorf("-from %q: invalid identifier specification (see -help for formats)", fromFlag)
	}
	if strings.HasSuffix(main, ".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 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
	}
	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
}
func parseObjectSpec(spec *spec, main string) error {
	e, _ := parser.ParseExpr(main)
	if pkg := parseImportPath(e); pkg != "" {
		spec.pkg = pkg
		if spec.searchFor == "" {
			return fmt.Errorf("-from %q: package import path %q must have a ::name suffix",
				main, main)
		}
		return nil
	}
	if e, ok := e.(*ast.SelectorExpr); ok {
		x := unparen(e.X)
		if star, ok := x.(*ast.StarExpr); ok {
			x = star.X
		}
		if pkg := parseImportPath(x); pkg != "" {
			spec.pkg = pkg               
			spec.pkgMember = e.Sel.Name  
			spec.fromName = e.Sel.Name
			return nil
		}
		if x, ok := x.(*ast.SelectorExpr); ok {
			y := unparen(x.X)
			if pkg := parseImportPath(y); pkg != "" {
				spec.pkg = pkg                
				spec.pkgMember = x.Sel.Name   
				spec.typeMember = e.Sel.Name  
				spec.fromName = e.Sel.Name
				return nil
			}
		}
	}
	return fmt.Errorf("-from %q: invalid expression", main)
}
func parseImportPath(e ast.Expr) string {
	switch e := e.(type) {
	case *ast.Ident:
		return e.Name  
	case *ast.BasicLit:
		if e.Kind == token.STRING {
			pkgname, _ := strconv.Unquote(e.Value)
			return pkgname  
		}
	}
	return ""
}
func parseOffsetFlag(ctxt *build.Context, offsetFlag string) (*spec, error) {
	var spec spec
	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)
	}
	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
}
var wd = func() string {
	wd, err := os.Getwd()
	if err != nil {
		panic("cannot get working directory: " + err.Error())
	}
	return wd
}()