// lockPath returns a typePath describing the location of a lock value // contained in typ. If there is no contained lock, it returns nil. func lockPath(tpkg *types.Package, typ types.Type) typePath { if typ == nil { return nil } // We're only interested in the case in which the underlying // type is a struct. (Interfaces and pointers are safe to copy.) styp, ok := typ.Underlying().(*types.Struct) if !ok { return nil } // We're looking for cases in which a reference to this type // can be locked, but a value cannot. This differentiates // embedded interfaces from embedded values. if plock := types.NewPointer(typ).MethodSet().Lookup(tpkg, "Lock"); plock != nil { if lock := typ.MethodSet().Lookup(tpkg, "Lock"); lock == nil { return []types.Type{typ} } } nfields := styp.NumFields() for i := 0; i < nfields; i++ { ftyp := styp.Field(i).Type() subpath := lockPath(tpkg, ftyp) if subpath != nil { return append(subpath, typ) } } return nil }
func (visit *visitor) methodSet(typ types.Type) { mset := typ.MethodSet() for i, n := 0, mset.Len(); i < n; i++ { // Side-effect: creates all wrapper methods. visit.function(visit.prog.Method(mset.At(i))) } }
// lookupMethod returns the method set for type typ, which may be one // of the interpreter's fake types. func lookupMethod(i *interpreter, typ types.Type, meth *types.Func) *ssa.Function { switch typ { case rtypeType: return i.rtypeMethods[meth.Id()] case errorType: return i.errorMethods[meth.Id()] } return i.prog.Method(typ.MethodSet().Lookup(meth.Pkg(), meth.Name())) }
// hasMethod reports whether the type contains a method with the given name. // It is part of the workaround for Formatters and should be deleted when // that workaround is no longer necessary. TODO: delete when fixed. func hasMethod(typ types.Type, name string) bool { set := typ.MethodSet() for i := 0; i < set.Len(); i++ { if set.At(i).Obj().Name() == name { return true } } return false }
// IntuitiveMethodSet returns the intuitive method set of a type, T. // // The result contains MethodSet(T) and additionally, if T is a // concrete type, methods belonging to *T if there is no similarly // named method on T itself. This corresponds to user intuition about // method sets; this function is intended only for user interfaces. // // The order of the result is as for types.MethodSet(T). // // TODO(gri): move this to go/types? // func IntuitiveMethodSet(T types.Type) []*types.Selection { var result []*types.Selection mset := T.MethodSet() 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.NewPointer(T).MethodSet() for i, n := 0, pmset.Len(); i < n; i++ { meth := pmset.At(i) if m := mset.Lookup(meth.Obj().Pkg(), meth.Obj().Name()); m != nil { meth = m } result = append(result, meth) } } return result }
// makeMethods ensures that all wrappers in the complete method set of // T are generated. It is equivalent to calling prog.Method() on all // members of T.methodSet(), but acquires fewer locks. // // It reports whether the type's method set is non-empty. // // Thread-safe. // // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) // func (prog *Program) makeMethods(T types.Type) bool { tmset := T.MethodSet() n := tmset.Len() if n == 0 { return false // empty (common case) } if prog.mode&LogSource != 0 { defer logStack("makeMethods %s", T)() } prog.methodsMu.Lock() defer prog.methodsMu.Unlock() mset := prog.createMethodSet(T) if !mset.complete { mset.complete = true for i := 0; i < n; i++ { prog.addMethod(mset, tmset.At(i)) } } return true }
// genMethodsOf generates nodes and constraints for all methods of type T. func (a *analysis) genMethodsOf(T types.Type) { mset := T.MethodSet() for i, n := 0, mset.Len(); i < n; i++ { a.valueNode(a.prog.Method(mset.At(i))) } }