func (c *funcContext) makeReceiver(x ast.Expr, sel *types.Selection) *expression { if !sel.Obj().Exported() { c.p.dependencies[sel.Obj()] = true } recvType := sel.Recv() _, isPointer := recvType.Underlying().(*types.Pointer) methodsRecvType := sel.Obj().Type().(*types.Signature).Recv().Type() _, pointerExpected := methodsRecvType.(*types.Pointer) var recv *expression switch { case !isPointer && pointerExpected: recv = c.translateExpr(c.setType(&ast.UnaryExpr{Op: token.AND, X: x}, types.NewPointer(recvType))) default: recv = c.translateExpr(x) } for _, index := range sel.Index()[:len(sel.Index())-1] { if ptr, isPtr := recvType.(*types.Pointer); isPtr { recvType = ptr.Elem() } s := recvType.Underlying().(*types.Struct) recv = c.formatExpr("%s.%s", recv, fieldName(s, index)) recvType = s.Field(index).Type() } if isWrapped(methodsRecvType) { recv = c.formatExpr("new %s(%s)", c.typeName(methodsRecvType), recv) } return recv }
// makeThunk returns a thunk, a synthetic function that delegates to a // concrete or interface method denoted by sel.Obj(). The resulting // function has no receiver, but has an additional (first) regular // parameter. // // Precondition: sel.Kind() == types.MethodExpr. // // type T int or: type T interface { meth() } // func (t T) meth() // f := T.meth // var t T // f(t) // calls t.meth() // // f is a synthetic wrapper defined as if by: // // f := func(t T) { return t.meth() } // // TODO(adonovan): opt: currently the stub is created even when used // directly in a function call: C.f(i, 0). This is less efficient // than inlining the stub. // // EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu) // func makeThunk(prog *Program, sel *types.Selection) *Function { if sel.Kind() != types.MethodExpr { panic(sel) } key := selectionKey{ kind: sel.Kind(), recv: sel.Recv(), obj: sel.Obj(), index: fmt.Sprint(sel.Index()), indirect: sel.Indirect(), } prog.methodsMu.Lock() defer prog.methodsMu.Unlock() // Canonicalize key.recv to avoid constructing duplicate thunks. canonRecv, ok := prog.canon.At(key.recv).(types.Type) if !ok { canonRecv = key.recv prog.canon.Set(key.recv, canonRecv) } key.recv = canonRecv fn, ok := prog.thunks[key] if !ok { fn = makeWrapper(prog, sel) if fn.Signature.Recv() != nil { panic(fn) // unexpected receiver } prog.thunks[key] = fn } return fn }
func (c *funcContext) translateSelection(sel *types.Selection, pos token.Pos) ([]string, string) { var fields []string t := sel.Recv() for _, index := range sel.Index() { if ptr, isPtr := t.(*types.Pointer); isPtr { t = ptr.Elem() } s := t.Underlying().(*types.Struct) if jsTag := getJsTag(s.Tag(index)); jsTag != "" { jsFieldName := s.Field(index).Name() for { fields = append(fields, fieldName(s, 0)) ft := s.Field(0).Type() if typesutil.IsJsObject(ft) { return fields, jsTag } ft = ft.Underlying() if ptr, ok := ft.(*types.Pointer); ok { ft = ptr.Elem().Underlying() } var ok bool s, ok = ft.(*types.Struct) if !ok || s.NumFields() == 0 { c.p.errList = append(c.p.errList, types.Error{Fset: c.p.fileSet, Pos: pos, Msg: fmt.Sprintf("could not find field with type *js.Object for 'js' tag of field '%s'", jsFieldName), Soft: true}) return nil, "" } } } fields = append(fields, fieldName(s, index)) t = s.Field(index).Type() } return fields, "" }
func newSelector(sel *types.Selection) (*Object, error) { if sel.Obj() == nil { return nil, errors.New("nil Selection object") } o := &Object{ Name: sel.Obj().Name(), pos: sel.Obj().Pos(), } o.setPkg(sel.Obj().Pkg()) switch t := derefType(sel.Recv()).(type) { case *types.Named: o.setParent(t.Obj()) default: // TODO: log type // Locally declared type, maybe an anonymous struct. return nil, fmt.Errorf("unexpected Recv type: %#v for object: %#v", t, sel.Obj()) } switch sel.Kind() { case types.FieldVal: o.IsField = true o.ObjType = Var case types.MethodVal: o.ObjType = Method case types.MethodExpr: // TODO: Fix o.ObjType = Method } return o, nil }
// makeThunk returns a thunk, a synthetic function that delegates to a // concrete or interface method denoted by sel.Obj(). The resulting // function has no receiver, but has an additional (first) regular // parameter. // // Precondition: sel.Kind() == types.MethodExpr. // // type T int or: type T interface { meth() } // func (t T) meth() // f := T.meth // var t T // f(t) // calls t.meth() // // f is a synthetic wrapper defined as if by: // // f := func(t T) { return t.meth() } // // TODO(adonovan): opt: currently the stub is created even when used // directly in a function call: C.f(i, 0). This is less efficient // than inlining the stub. // // EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu) // func makeThunk(prog *Program, sel *types.Selection) *Function { if sel.Kind() != types.MethodExpr { panic(sel) } // TODO(adonovan): opt: canonicalize the recv Type to avoid // construct unnecessary duplicate thunks. key := selectionKey{ kind: sel.Kind(), recv: sel.Recv(), obj: sel.Obj(), index: fmt.Sprint(sel.Index()), indirect: sel.Indirect(), } prog.methodsMu.Lock() defer prog.methodsMu.Unlock() fn, ok := prog.thunks[key] if !ok { fn = makeWrapper(prog, sel) if fn.Signature.Recv() != nil { panic(fn) // unexpected receiver } prog.thunks[key] = fn } return fn }
// Method returns the Function implementing method sel, building // wrapper methods on demand. It returns nil if sel denotes an // abstract (interface) method. // // Precondition: sel.Kind() == MethodVal. // // TODO(adonovan): rename this to MethodValue because of the // precondition, and for consistency with functions in source.go. // // Thread-safe. // // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) // func (prog *Program) Method(sel *types.Selection) *Function { if sel.Kind() != types.MethodVal { panic(fmt.Sprintf("Method(%s) kind != MethodVal", sel)) } T := sel.Recv() if isInterface(T) { return nil // abstract method } if prog.mode&LogSource != 0 { defer logStack("Method %s %v", T, sel)() } prog.methodsMu.Lock() defer prog.methodsMu.Unlock() return prog.addMethod(prog.createMethodSet(T), sel) }
// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) func (prog *Program) addMethod(mset *methodSet, sel *types.Selection) *Function { if sel.Kind() == types.MethodExpr { panic(sel) } id := sel.Obj().Id() fn := mset.mapping[id] if fn == nil { obj := sel.Obj().(*types.Func) needsPromotion := len(sel.Index()) > 1 needsIndirection := !isPointer(recvType(obj)) && isPointer(sel.Recv()) if needsPromotion || needsIndirection { fn = makeWrapper(prog, sel) } else { fn = prog.declaredFunc(obj) } if fn.Signature.Recv() == nil { panic(fn) // missing receiver } mset.mapping[id] = fn } return fn }
// makeWrapper returns a synthetic method that delegates to the // declared method denoted by meth.Obj(), first performing any // necessary pointer indirections or field selections implied by meth. // // The resulting method's receiver type is meth.Recv(). // // This function is versatile but quite subtle! Consider the // following axes of variation when making changes: // - optional receiver indirection // - optional implicit field selections // - meth.Obj() may denote a concrete or an interface method // - the result may be a thunk or a wrapper. // // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) // func makeWrapper(prog *Program, sel *types.Selection) *Function { obj := sel.Obj().(*types.Func) // the declared function sig := sel.Type().(*types.Signature) // type of this wrapper var recv *types.Var // wrapper's receiver or thunk's params[0] name := obj.Name() var description string var start int // first regular param if sel.Kind() == types.MethodExpr { name += "$thunk" description = "thunk" recv = sig.Params().At(0) start = 1 } else { description = "wrapper" recv = sig.Recv() } description = fmt.Sprintf("%s for %s", description, sel.Obj()) if prog.mode&LogSource != 0 { defer logStack("make %s to (%s)", description, recv.Type())() } fn := &Function{ name: name, method: sel, object: obj, Signature: sig, Synthetic: description, Prog: prog, pos: obj.Pos(), } fn.startBody() fn.addSpilledParam(recv) createParams(fn, start) indices := sel.Index() var v Value = fn.Locals[0] // spilled receiver if isPointer(sel.Recv()) { v = emitLoad(fn, v) // For simple indirection wrappers, perform an informative nil-check: // "value method (T).f called using nil *T pointer" if len(indices) == 1 && !isPointer(recvType(obj)) { var c Call c.Call.Value = &Builtin{ name: "ssa:wrapnilchk", sig: types.NewSignature(nil, types.NewTuple(anonVar(sel.Recv()), anonVar(tString), anonVar(tString)), types.NewTuple(anonVar(sel.Recv())), false), } c.Call.Args = []Value{ v, stringConst(deref(sel.Recv()).String()), stringConst(sel.Obj().Name()), } c.setType(v.Type()) v = fn.emit(&c) } } // Invariant: v is a pointer, either // value of *A receiver param, or // address of A spilled receiver. // We use pointer arithmetic (FieldAddr possibly followed by // Load) in preference to value extraction (Field possibly // preceded by Load). v = emitImplicitSelections(fn, v, indices[:len(indices)-1]) // Invariant: v is a pointer, either // value of implicit *C field, or // address of implicit C field. var c Call if r := recvType(obj); !isInterface(r) { // concrete method if !isPointer(r) { v = emitLoad(fn, v) } c.Call.Value = prog.declaredFunc(obj) c.Call.Args = append(c.Call.Args, v) } else { c.Call.Method = obj c.Call.Value = emitLoad(fn, v) } for _, arg := range fn.Params[1:] { c.Call.Args = append(c.Call.Args, arg) } emitTailCall(fn, &c) fn.finishBody() return fn }
func (w *PkgWalker) LookupObjects(conf *PkgConfig, cursor *FileCursor) { var cursorObj types.Object var cursorSelection *types.Selection var cursorObjIsDef bool //lookup defs var pkg *types.Package var pkgInfo *types.Info if cursor.xtest { pkgInfo = conf.XInfo pkg = conf.XPkg } else { pkgInfo = conf.Info pkg = conf.Pkg } _ = cursorObjIsDef if cursorObj == nil { for sel, obj := range pkgInfo.Selections { if cursor.pos >= sel.Sel.Pos() && cursor.pos <= sel.Sel.End() { cursorObj = obj.Obj() cursorSelection = obj break } } } if cursorObj == nil { for id, obj := range pkgInfo.Defs { if cursor.pos >= id.Pos() && cursor.pos <= id.End() { cursorObj = obj cursorObjIsDef = true break } } } _ = cursorSelection if cursorObj == nil { for id, obj := range pkgInfo.Uses { if cursor.pos >= id.Pos() && cursor.pos <= id.End() { cursorObj = obj break } } } if cursorObj == nil { return } kind, err := parserObjKind(cursorObj) if err != nil { log.Fatalln(err) } if kind == ObjField { if cursorObj.(*types.Var).Anonymous() { typ := orgType(cursorObj.Type()) if named, ok := typ.(*types.Named); ok { cursorObj = named.Obj() } } } cursorPkg := cursorObj.Pkg() cursorPos := cursorObj.Pos() //var fieldTypeInfo *types.Info var fieldTypeObj types.Object // if cursorPkg == pkg { // fieldTypeInfo = pkgInfo // } cursorIsInterfaceMethod := false var cursorInterfaceTypeName string if kind == ObjMethod && cursorSelection != nil && cursorSelection.Recv() != nil { sig := cursorObj.(*types.Func).Type().Underlying().(*types.Signature) if _, ok := sig.Recv().Type().Underlying().(*types.Interface); ok { if named, ok := cursorSelection.Recv().(*types.Named); ok { obj, typ := w.lookupNamedMethod(named, cursorObj.Name()) if obj != nil { cursorObj = obj } if typ != nil { cursorPkg = typ.Obj().Pkg() cursorInterfaceTypeName = typ.Obj().Name() } cursorIsInterfaceMethod = true } } } else if kind == ObjField && cursorSelection != nil { if recv := cursorSelection.Recv(); recv != nil { typ := orgType(recv) if typ != nil { if name, ok := typ.(*types.Named); ok { fieldTypeObj = name.Obj() na := w.lookupNamedField(name, cursorObj.Name()) if na != nil { fieldTypeObj = na.Obj() } } } } } if cursorPkg != nil && cursorPkg != pkg && kind != ObjPkgName && w.isBinaryPkg(cursorPkg.Path()) { conf := &PkgConfig{ IgnoreFuncBodies: true, AllowBinary: true, WithTestFiles: true, Info: &types.Info{ Defs: make(map[*ast.Ident]types.Object), }, } pkg, _ := w.Import("", cursorPkg.Path(), conf) if pkg != nil { if cursorIsInterfaceMethod { for _, obj := range conf.Info.Defs { if obj == nil { continue } if fn, ok := obj.(*types.Func); ok { if fn.Name() == cursorObj.Name() { if sig, ok := fn.Type().Underlying().(*types.Signature); ok { if named, ok := sig.Recv().Type().(*types.Named); ok { if named.Obj() != nil && named.Obj().Name() == cursorInterfaceTypeName { cursorPos = obj.Pos() break } } } } } } } else if kind == ObjField && fieldTypeObj != nil { for _, obj := range conf.Info.Defs { if obj == nil { continue } if _, ok := obj.(*types.TypeName); ok { if IsSameObject(fieldTypeObj, obj) { if t, ok := obj.Type().Underlying().(*types.Struct); ok { for i := 0; i < t.NumFields(); i++ { if t.Field(i).Id() == cursorObj.Id() { cursorPos = t.Field(i).Pos() break } } } break } } } } else { for k, v := range conf.Info.Defs { if k != nil && v != nil && IsSameObject(v, cursorObj) { cursorPos = k.Pos() break } } } } // if kind == ObjField || cursorIsInterfaceMethod { // fieldTypeInfo = conf.Info // } } // if kind == ObjField { // fieldTypeObj = w.LookupStructFromField(fieldTypeInfo, cursorPkg, cursorObj, cursorPos) // } if typesFindDef { fmt.Println(w.fset.Position(cursorPos)) } if typesFindInfo { if kind == ObjField && fieldTypeObj != nil { typeName := fieldTypeObj.Name() if fieldTypeObj.Pkg() != nil && fieldTypeObj.Pkg() != pkg { typeName = fieldTypeObj.Pkg().Name() + "." + fieldTypeObj.Name() } fmt.Println(typeName, simpleObjInfo(cursorObj)) } else if kind == ObjBuiltin { fmt.Println(builtinInfo(cursorObj.Name())) } else if kind == ObjPkgName { fmt.Println(cursorObj.String()) } else if cursorIsInterfaceMethod { fmt.Println(strings.Replace(simpleObjInfo(cursorObj), "(interface)", cursorPkg.Name()+"."+cursorInterfaceTypeName, 1)) } else { fmt.Println(simpleObjInfo(cursorObj)) } } if typesFindDoc && typesFindDef { pos := w.fset.Position(cursorPos) file := w.parsedFileCache[pos.Filename] if file != nil { line := pos.Line var group *ast.CommentGroup for _, v := range file.Comments { lastLine := w.fset.Position(v.End()).Line if lastLine == line || lastLine == line-1 { group = v } else if lastLine > line { break } } if group != nil { fmt.Println(group.Text()) } } } if !typesFindUse { return } var usages []int if kind == ObjPkgName { for id, obj := range pkgInfo.Uses { if obj != nil && obj.Id() == cursorObj.Id() { //!= nil && cursorObj.Pos() == obj.Pos() { usages = append(usages, int(id.Pos())) } } } else { // for id, obj := range pkgInfo.Defs { // if obj == cursorObj { //!= nil && cursorObj.Pos() == obj.Pos() { // usages = append(usages, int(id.Pos())) // } // } for id, obj := range pkgInfo.Uses { if obj == cursorObj { //!= nil && cursorObj.Pos() == obj.Pos() { usages = append(usages, int(id.Pos())) } } } var pkg_path string var xpkg_path string if conf.Pkg != nil { pkg_path = conf.Pkg.Path() } if conf.XPkg != nil { xpkg_path = conf.XPkg.Path() } if cursorPkg != nil && (cursorPkg.Path() == pkg_path || cursorPkg.Path() == xpkg_path) && kind != ObjPkgName { usages = append(usages, int(cursorPos)) } (sort.IntSlice(usages)).Sort() for _, pos := range usages { fmt.Println(w.fset.Position(token.Pos(pos))) } //check look for current pkg.object on pkg_test if typesFindUseAll || IsSamePkg(cursorPkg, conf.Pkg) { var addInfo *types.Info if conf.Cursor.xtest { addInfo = conf.Info } else { addInfo = conf.XInfo } if addInfo != nil && cursorPkg != nil { var usages []int // for id, obj := range addInfo.Defs { // if id != nil && obj != nil && obj.Id() == cursorObj.Id() { // usages = append(usages, int(id.Pos())) // } // } for k, v := range addInfo.Uses { if k != nil && v != nil && IsSameObject(v, cursorObj) { usages = append(usages, int(k.Pos())) } } (sort.IntSlice(usages)).Sort() for _, pos := range usages { fmt.Println(w.fset.Position(token.Pos(pos))) } } } if !typesFindUseAll { return } if cursorPkg == nil { return } var find_def_pkg string var uses_paths []string if cursorPkg.Path() != pkg_path && cursorPkg.Path() != xpkg_path { find_def_pkg = cursorPkg.Path() uses_paths = append(uses_paths, cursorPkg.Path()) } buildutil.ForEachPackage(&build.Default, func(importPath string, err error) { if err != nil { return } if importPath == conf.Pkg.Path() { return } bp, err := w.importPath(importPath, 0) if err != nil { return } find := false if bp.ImportPath == cursorPkg.Path() { find = true } else { for _, v := range bp.Imports { if v == cursorObj.Pkg().Path() { find = true break } } } if find { for _, v := range uses_paths { if v == bp.ImportPath { return } } uses_paths = append(uses_paths, bp.ImportPath) } }) w.imported = make(map[string]*types.Package) for _, v := range uses_paths { conf := &PkgConfig{ IgnoreFuncBodies: false, AllowBinary: true, WithTestFiles: true, Info: &types.Info{ Uses: make(map[*ast.Ident]types.Object), }, XInfo: &types.Info{ Uses: make(map[*ast.Ident]types.Object), }, } w.imported[v] = nil var usages []int vpkg, _ := w.Import("", v, conf) if vpkg != nil && vpkg != pkg { if conf.Info != nil { for k, v := range conf.Info.Uses { if k != nil && v != nil && IsSameObject(v, cursorObj) { usages = append(usages, int(k.Pos())) } } } if conf.XInfo != nil { for k, v := range conf.XInfo.Uses { if k != nil && v != nil && IsSameObject(v, cursorObj) { usages = append(usages, int(k.Pos())) } } } } if v == find_def_pkg { usages = append(usages, int(cursorPos)) } (sort.IntSlice(usages)).Sort() for _, pos := range usages { fmt.Println(w.fset.Position(token.Pos(pos))) } } }
func (w *PkgWalker) LookupObjects(pkg *types.Package, pkgInfo *types.Info, cursor *FileCursor) { var cursorObj types.Object var cursorSelection *types.Selection var cursorObjIsDef bool //lookup defs _ = cursorObjIsDef if cursorObj == nil { for sel, obj := range pkgInfo.Selections { if cursor.pos >= sel.Sel.Pos() && cursor.pos <= sel.Sel.End() { cursorObj = obj.Obj() cursorSelection = obj break } } } if cursorObj == nil { for id, obj := range pkgInfo.Defs { if cursor.pos >= id.Pos() && cursor.pos <= id.End() { cursorObj = obj cursorObjIsDef = true break } } } _ = cursorSelection if cursorObj == nil { for id, obj := range pkgInfo.Uses { if cursor.pos >= id.Pos() && cursor.pos <= id.End() { cursorObj = obj break } } } if cursorObj == nil { return } kind, err := parserObjKind(cursorObj) if err != nil { log.Fatalln(err) } if kind == ObjField { if cursorObj.(*types.Var).Anonymous() { if named, ok := cursorObj.Type().(*types.Named); ok { cursorObj = named.Obj() } } } cursorPkg := cursorObj.Pkg() cursorPos := cursorObj.Pos() var fieldTypeInfo *types.Info var fieldTypeObj types.Object if cursorPkg == pkg { fieldTypeInfo = pkgInfo } cursorIsInterfaceMethod := false var cursorInterfaceTypeName string if kind == ObjMethod && cursorSelection != nil && cursorSelection.Recv() != nil { sig := cursorObj.(*types.Func).Type().Underlying().(*types.Signature) if _, ok := sig.Recv().Type().Underlying().(*types.Interface); ok { named := cursorSelection.Recv().(*types.Named) obj, typ := w.lookupNamedMethod(named, cursorObj.Name()) if obj != nil { cursorObj = obj } if typ != nil { cursorPkg = typ.Obj().Pkg() cursorInterfaceTypeName = typ.Obj().Name() } cursorIsInterfaceMethod = true } } if cursorPkg != nil && cursorPkg != pkg && kind != ObjPkgName && w.isBinaryPkg(cursorPkg.Path()) { conf := &PkgConfig{ IgnoreFuncBodies: true, AllowBinary: true, WithTestFiles: true, Info: &types.Info{ Defs: make(map[*ast.Ident]types.Object), }, } pkg, _ := w.Import("", cursorPkg.Path(), conf) if pkg != nil { if cursorIsInterfaceMethod { for _, obj := range conf.Info.Defs { if obj == nil { continue } if fn, ok := obj.(*types.Func); ok { if fn.Name() == cursorObj.Name() { if sig, ok := fn.Type().Underlying().(*types.Signature); ok { if named, ok := sig.Recv().Type().(*types.Named); ok { if named.Obj() != nil && named.Obj().Name() == cursorInterfaceTypeName { cursorPos = obj.Pos() break } } } } } } } else { for _, obj := range conf.Info.Defs { if obj != nil && obj.String() == cursorObj.String() { cursorPos = obj.Pos() break } } } } if kind == ObjField || cursorIsInterfaceMethod { fieldTypeInfo = conf.Info } } if kind == ObjField { fieldTypeObj = w.LookupStructFromField(fieldTypeInfo, cursorPkg, cursorObj, cursorPos) } if typeFindDef { fmt.Println(w.fset.Position(cursorPos)) } if typeFindInfo { if kind == ObjField && fieldTypeObj != nil { typeName := fieldTypeObj.Name() if fieldTypeObj.Pkg() != nil && fieldTypeObj.Pkg() != pkg { typeName = fieldTypeObj.Pkg().Name() + "." + fieldTypeObj.Name() } fmt.Println(typeName, simpleType(cursorObj.String())) } else if kind == ObjBuiltin { fmt.Println(builtinInfo(cursorObj.Name())) } else if kind == ObjPkgName { fmt.Println(cursorObj.String()) } else if cursorIsInterfaceMethod { fmt.Println(strings.Replace(simpleType(cursorObj.String()), "(interface)", cursorPkg.Name()+"."+cursorInterfaceTypeName, 1)) } else { fmt.Println(simpleType(cursorObj.String())) } } //if f, ok := w.parsedFileCache[w.fset.Position(cursorPos).Filename]; ok { // for _, d := range f.Decls { // if inRange(d, cursorPos) { // if fd, ok := d.(*ast.FuncDecl); ok { // fd.Body = nil // } // commentMap := ast.NewCommentMap(w.fset, f, f.Comments) // commentedNode := printer.CommentedNode{Node: d} // if comments := commentMap.Filter(d).Comments(); comments != nil { // commentedNode.Comments = comments // } // var b bytes.Buffer // printer.Fprint(&b, w.fset, &commentedNode) // b.Write([]byte("\n\n")) // Add a blank line between entries if we print documentation. // log.Println(w.nodeString(d)) // } // } //} if !typeFindUse { return } var usages []int if kind == ObjPkgName { for id, obj := range pkgInfo.Uses { if obj != nil && obj.Id() == cursorObj.Id() { //!= nil && cursorObj.Pos() == obj.Pos() { usages = append(usages, int(id.Pos())) } } } else { for id, obj := range pkgInfo.Defs { if obj == cursorObj { //!= nil && cursorObj.Pos() == obj.Pos() { usages = append(usages, int(id.Pos())) } } for id, obj := range pkgInfo.Uses { if obj == cursorObj { //!= nil && cursorObj.Pos() == obj.Pos() { usages = append(usages, int(id.Pos())) } } } (sort.IntSlice(usages)).Sort() for _, pos := range usages { fmt.Println(w.fset.Position(token.Pos(pos))) } }