github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/unused/implements.go (about) 1 package unused 2 3 import "go/types" 4 5 // lookupMethod returns the index of and method with matching package and name, or (-1, nil). 6 func lookupMethod(T *types.Interface, pkg *types.Package, name string) (int, *types.Func) { 7 if name != "_" { 8 for i := 0; i < T.NumMethods(); i++ { 9 m := T.Method(i) 10 if sameId(m, pkg, name) { 11 return i, m 12 } 13 } 14 } 15 return -1, nil 16 } 17 18 func sameId(obj types.Object, pkg *types.Package, name string) bool { 19 // spec: 20 // "Two identifiers are different if they are spelled differently, 21 // or if they appear in different packages and are not exported. 22 // Otherwise, they are the same." 23 if name != obj.Name() { 24 return false 25 } 26 // obj.Name == name 27 if obj.Exported() { 28 return true 29 } 30 // not exported, so packages must be the same (pkg == nil for 31 // fields in Universe scope; this can only happen for types 32 // introduced via Eval) 33 if pkg == nil || obj.Pkg() == nil { 34 return pkg == obj.Pkg() 35 } 36 // pkg != nil && obj.pkg != nil 37 return pkg.Path() == obj.Pkg().Path() 38 } 39 40 func implements(V types.Type, T *types.Interface, msV *types.MethodSet) ([]*types.Selection, bool) { 41 // fast path for common case 42 if T.Empty() { 43 return nil, true 44 } 45 46 if ityp, _ := V.Underlying().(*types.Interface); ityp != nil { 47 // TODO(dh): is this code reachable? 48 for i := 0; i < T.NumMethods(); i++ { 49 m := T.Method(i) 50 _, obj := lookupMethod(ityp, m.Pkg(), m.Name()) 51 switch { 52 case obj == nil: 53 return nil, false 54 case !types.Identical(obj.Type(), m.Type()): 55 return nil, false 56 } 57 } 58 return nil, true 59 } 60 61 // A concrete type implements T if it implements all methods of T. 62 var sels []*types.Selection 63 for i := 0; i < T.NumMethods(); i++ { 64 m := T.Method(i) 65 sel := msV.Lookup(m.Pkg(), m.Name()) 66 if sel == nil { 67 return nil, false 68 } 69 70 f, _ := sel.Obj().(*types.Func) 71 if f == nil { 72 return nil, false 73 } 74 75 if !types.Identical(f.Type(), m.Type()) { 76 return nil, false 77 } 78 79 sels = append(sels, sel) 80 } 81 return sels, true 82 }