inner
}
-func (*inner) m() {}
-func (*outer) m() {}
+func (*inner) M() {}
+func (*outer) M() {}
func TestNestedMethods(t *testing.T) {
typ := TypeOf((*outer)(nil))
- if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).m).Pointer() {
- t.Errorf("Wrong method table for outer: (m=%p)", (*outer).m)
+ if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).M).Pointer() {
+ t.Errorf("Wrong method table for outer: (M=%p)", (*outer).M)
for i := 0; i < typ.NumMethod(); i++ {
m := typ.Method(i)
t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
func TestUnexportedMethods(t *testing.T) {
typ := TypeOf(unexpi)
+ if got := typ.NumMethod(); got != 1 {
+ t.Error("NumMethod=%d, want 1 satisfied method", got)
+ }
if typ.Method(0).Type == nil {
t.Error("missing type for satisfied method 'f'")
}
if !typ.Method(0).Func.IsValid() {
t.Error("missing func for satisfied method 'f'")
}
- if typ.Method(1).Type != nil {
- t.Error("found type for unsatisfied method 'g'")
- }
- if typ.Method(1).Func.IsValid() {
- t.Error("found func for unsatisfied method 'g'")
- }
}
type InnerInt struct {
type Impl struct{}
-func (Impl) f() {}
+func (Impl) F() {}
func TestValueString(t *testing.T) {
rv := ValueOf(Impl{})
func (t *rtype) common() *rtype { return t }
+var methodCache struct {
+ sync.RWMutex
+ m map[*rtype][]method
+}
+
+// satisfiedMethods returns methods of t that satisfy an interface.
+// This may include unexported methods that satisfy an interface
+// defined with unexported methods in the same package as t.
+func (t *rtype) satisfiedMethods() []method {
+ methodCache.RLock()
+ methods, found := methodCache.m[t]
+ methodCache.RUnlock()
+
+ if found {
+ return methods
+ }
+
+ ut := t.uncommon()
+ if ut == nil {
+ return nil
+ }
+ allm := ut.methods()
+ allSatisfied := true
+ for _, m := range allm {
+ if m.mtyp == 0 {
+ allSatisfied = false
+ break
+ }
+ }
+ if allSatisfied {
+ methods = allm
+ } else {
+ methods = make([]method, 0, len(allm))
+ for _, m := range allm {
+ if m.mtyp != 0 {
+ methods = append(methods, m)
+ }
+ }
+ methods = methods[:len(methods):len(methods)]
+ }
+
+ methodCache.Lock()
+ if methodCache.m == nil {
+ methodCache.m = make(map[*rtype][]method)
+ }
+ methodCache.m[t] = methods
+ methodCache.Unlock()
+
+ return methods
+}
+
func (t *rtype) NumMethod() int {
if t.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.NumMethod()
}
- ut := t.uncommon()
- if ut == nil {
- return 0
- }
- return int(ut.mcount)
+ return len(t.satisfiedMethods())
}
func (t *rtype) Method(i int) (m Method) {
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.Method(i)
}
- ut := t.uncommon()
-
- if ut == nil || i < 0 || i >= int(ut.mcount) {
+ methods := t.satisfiedMethods()
+ if i < 0 || i >= len(methods) {
panic("reflect: Method index out of range")
}
- p := ut.methods()[i]
+ p := methods[i]
pname := t.nameOff(p.name)
m.Name = pname.name()
fl := flag(Func)
if !pname.isExported() {
m.PkgPath = pname.pkgPath()
if m.PkgPath == "" {
+ ut := t.uncommon()
m.PkgPath = t.nameOff(ut.pkgPath).name()
}
fl |= flagStickyRO
}
- if p.mtyp != 0 {
- mtyp := t.typeOff(p.mtyp)
- ft := (*funcType)(unsafe.Pointer(mtyp))
- in := make([]Type, 0, 1+len(ft.in()))
- in = append(in, t)
- for _, arg := range ft.in() {
- in = append(in, arg)
- }
- out := make([]Type, 0, len(ft.out()))
- for _, ret := range ft.out() {
- out = append(out, ret)
- }
- mt := FuncOf(in, out, ft.IsVariadic())
- m.Type = mt
- tfn := t.textOff(p.tfn)
- fn := unsafe.Pointer(&tfn)
- m.Func = Value{mt.(*rtype), fn, fl}
+ mtyp := t.typeOff(p.mtyp)
+ ft := (*funcType)(unsafe.Pointer(mtyp))
+ in := make([]Type, 0, 1+len(ft.in()))
+ in = append(in, t)
+ for _, arg := range ft.in() {
+ in = append(in, arg)
}
+ out := make([]Type, 0, len(ft.out()))
+ for _, ret := range ft.out() {
+ out = append(out, ret)
+ }
+ mt := FuncOf(in, out, ft.IsVariadic())
+ m.Type = mt
+ tfn := t.textOff(p.tfn)
+ fn := unsafe.Pointer(&tfn)
+ m.Func = Value{mt.(*rtype), fn, fl}
+
m.Index = i
return m
}
for i := 0; i < int(ut.mcount); i++ {
p := utmethods[i]
pname := t.nameOff(p.name)
- if pname.name() == name {
+ if pname.isExported() && pname.name() == name {
return t.Method(i), true
}
}