// TODO: use the version from ssa or go/types func intuitiveMethodSet(T types.Type) []*types.Selection { var result []*types.Selection mset := types.NewMethodSet(T) if _, ok := T.Underlying().(*types.Interface); ok { for i, n := 0, mset.Len(); i < n; i++ { result = append(result, mset.At(i)) } } else { pmset := types.NewMethodSet(types.NewPointer(T)) for i, n := 0, pmset.Len(); i < n; i++ { meth := pmset.At(i) if m := mset.Lookup(meth.Obj.GetPkg(), meth.Obj.GetName()); m != nil { meth = m } result = append(result, meth) } } return result }
func (b browser) filteredObjs() (objs objects) { add := func(obj types.Object) { if invisible(obj, b.currentPkg) { return } if _, ok := obj.(*pkgObject); ok || b.options.objFilter == nil || b.options.objFilter(obj) { objs = append(objs, obj) } } addSubPkgs := func(importPath string) { seen := map[string]bool{} for _, srcDir := range build.Default.SrcDirs() { files, err := ioutil.ReadDir(filepath.Join(srcDir, importPath)) if err != nil { continue } for _, f := range files { name := filepath.Base(f.Name()) if !f.IsDir() || !unicode.IsLetter([]rune(name)[0]) || name == "testdata" || seen[name] { continue } if _, ok := b.newObj.(*pkgObject); ok && name == b.oldName { // when editing a package path, it will be added in filteredObjs as newObj, so don't add it here continue } seen[name] = true importPath := path.Join(importPath, name) pkgObj, ok := pkgObjects[importPath] if !ok { if pkg, err := build.Import(importPath, "", build.AllowBinary); err == nil { name = pkg.Name } pkgObj = &pkgObject{nil, path.Base(importPath), srcDir, importPath, name} pkgObjects[importPath] = pkgObj } add(pkgObj) } } } if b.typ != nil { mset := types.NewMethodSet(b.typ) for i := 0; i < mset.Len(); i++ { m := mset.At(i) // m.Type() has the correct receiver for inherited methods (m.Obj does not) add(types.NewFunc(0, m.Obj.GetPkg(), m.Obj.GetName(), m.Type().(*types.Signature))) } fset := types.NewFieldSet(b.typ) for i := 0; i < fset.Len(); i++ { f := fset.At(i) add(field{f.Obj.(*types.Var), f.Recv, f.Indirect}) } } else if len(b.path) > 0 { switch obj := b.path[0].(type) { case *pkgObject: if pkg, err := getPackage(obj.importPath); err == nil { for _, obj := range pkg.Scope().Objects { add(obj) } } else { if _, ok := err.(*build.NoGoError); !ok { fmt.Println(err) } pkgs[obj.importPath] = types.NewPackage(obj.importPath, obj.pkgName, types.NewScope(types.Universe)) } addSubPkgs(obj.importPath) case *types.TypeName: for _, m := range intuitiveMethodSet(obj.Type) { if types.IsIdentical(m.Obj.(*types.Func).Type.(*types.Signature).Recv.Type, m.Recv) { // preserve Object identity for non-inherited methods so that fluxObjs works add(m.Obj) } else { // m.Type() has the correct receiver for inherited methods (m.Obj does not) add(types.NewFunc(0, m.Obj.GetPkg(), m.Obj.GetName(), m.Type().(*types.Signature))) } } } } else { for _, name := range []string{"break", "call", "continue", "convert", "defer", "func", "go", "if", "loop", "return", "select", "typeAssert"} { add(special{newVar(name, nil)}) } for _, name := range []string{"=", "*"} { add(newVar(name, nil)) } pkgs := b.imports if b.currentPkg != nil { pkgs = append(pkgs, b.currentPkg) } for _, p := range pkgs { for _, obj := range p.Scope().Objects { add(obj) } } for _, obj := range types.Universe.Objects { switch obj.GetName() { case "nil", "print", "println": continue } add(obj) } for _, op := range []string{"!", "&&", "||", "+", "-", "*", "/", "%", "&", "|", "^", "&^", "<<", ">>", "==", "!=", "<", "<=", ">", ">=", "[]", "[:]", "<-"} { add(types.NewFunc(0, nil, op, nil)) } for _, t := range []*types.TypeName{protoPointer, protoArray, protoSlice, protoMap, protoChan, protoFunc, protoInterface, protoStruct} { add(t) } addSubPkgs("") } sort.Sort(objs) return }