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  }