@@ -763,57 +763,103 @@ func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 }
763
763
764
764
func (t * rtype ) common () * rtype { return t }
765
765
766
+ var methodCache struct {
767
+ sync.RWMutex
768
+ m map [* rtype ][]method
769
+ }
770
+
771
+ // satisfiedMethods returns methods of t that satisfy an interface.
772
+ // This may include unexported methods that satisfy an interface
773
+ // defined with unexported methods in the same package as t.
774
+ func (t * rtype ) satisfiedMethods () []method {
775
+ methodCache .RLock ()
776
+ methods , found := methodCache .m [t ]
777
+ methodCache .RUnlock ()
778
+
779
+ if found {
780
+ return methods
781
+ }
782
+
783
+ ut := t .uncommon ()
784
+ if ut == nil {
785
+ return nil
786
+ }
787
+ allm := ut .methods ()
788
+ allSatisfied := true
789
+ for _ , m := range allm {
790
+ if m .mtyp == 0 {
791
+ allSatisfied = false
792
+ break
793
+ }
794
+ }
795
+ if allSatisfied {
796
+ methods = allm
797
+ } else {
798
+ methods = make ([]method , 0 , len (allm ))
799
+ for _ , m := range allm {
800
+ if m .mtyp != 0 {
801
+ methods = append (methods , m )
802
+ }
803
+ }
804
+ methods = methods [:len (methods ):len (methods )]
805
+ }
806
+
807
+ methodCache .Lock ()
808
+ if methodCache .m == nil {
809
+ methodCache .m = make (map [* rtype ][]method )
810
+ }
811
+ methodCache .m [t ] = methods
812
+ methodCache .Unlock ()
813
+
814
+ return methods
815
+ }
816
+
766
817
func (t * rtype ) NumMethod () int {
767
818
if t .Kind () == Interface {
768
819
tt := (* interfaceType )(unsafe .Pointer (t ))
769
820
return tt .NumMethod ()
770
821
}
771
- ut := t .uncommon ()
772
- if ut == nil {
773
- return 0
774
- }
775
- return int (ut .mcount )
822
+ return len (t .satisfiedMethods ())
776
823
}
777
824
778
825
func (t * rtype ) Method (i int ) (m Method ) {
779
826
if t .Kind () == Interface {
780
827
tt := (* interfaceType )(unsafe .Pointer (t ))
781
828
return tt .Method (i )
782
829
}
783
- ut := t .uncommon ()
784
-
785
- if ut == nil || i < 0 || i >= int (ut .mcount ) {
830
+ methods := t .satisfiedMethods ()
831
+ if i < 0 || i >= len (methods ) {
786
832
panic ("reflect: Method index out of range" )
787
833
}
788
- p := ut . methods () [i ]
834
+ p := methods [i ]
789
835
pname := t .nameOff (p .name )
790
836
m .Name = pname .name ()
791
837
fl := flag (Func )
792
838
if ! pname .isExported () {
793
839
m .PkgPath = pname .pkgPath ()
794
840
if m .PkgPath == "" {
841
+ ut := t .uncommon ()
795
842
m .PkgPath = t .nameOff (ut .pkgPath ).name ()
796
843
}
797
844
fl |= flagStickyRO
798
845
}
799
- if p .mtyp != 0 {
800
- mtyp := t .typeOff (p .mtyp )
801
- ft := (* funcType )(unsafe .Pointer (mtyp ))
802
- in := make ([]Type , 0 , 1 + len (ft .in ()))
803
- in = append (in , t )
804
- for _ , arg := range ft .in () {
805
- in = append (in , arg )
806
- }
807
- out := make ([]Type , 0 , len (ft .out ()))
808
- for _ , ret := range ft .out () {
809
- out = append (out , ret )
810
- }
811
- mt := FuncOf (in , out , ft .IsVariadic ())
812
- m .Type = mt
813
- tfn := t .textOff (p .tfn )
814
- fn := unsafe .Pointer (& tfn )
815
- m .Func = Value {mt .(* rtype ), fn , fl }
846
+ mtyp := t .typeOff (p .mtyp )
847
+ ft := (* funcType )(unsafe .Pointer (mtyp ))
848
+ in := make ([]Type , 0 , 1 + len (ft .in ()))
849
+ in = append (in , t )
850
+ for _ , arg := range ft .in () {
851
+ in = append (in , arg )
816
852
}
853
+ out := make ([]Type , 0 , len (ft .out ()))
854
+ for _ , ret := range ft .out () {
855
+ out = append (out , ret )
856
+ }
857
+ mt := FuncOf (in , out , ft .IsVariadic ())
858
+ m .Type = mt
859
+ tfn := t .textOff (p .tfn )
860
+ fn := unsafe .Pointer (& tfn )
861
+ m .Func = Value {mt .(* rtype ), fn , fl }
862
+
817
863
m .Index = i
818
864
return m
819
865
}
@@ -831,7 +877,7 @@ func (t *rtype) MethodByName(name string) (m Method, ok bool) {
831
877
for i := 0 ; i < int (ut .mcount ); i ++ {
832
878
p := utmethods [i ]
833
879
pname := t .nameOff (p .name )
834
- if pname .name () == name {
880
+ if pname .isExported () && pname . name () == name {
835
881
return t .Method (i ), true
836
882
}
837
883
}
0 commit comments