@@ -156,6 +156,10 @@ type Provider struct {
156156 // Name is the name of the Go object.
157157 Name string
158158
159+ // MethodExprRecv is the receiver type for a method expression provider.
160+ // It is nil for package-level function providers.
161+ MethodExprRecv types.Type
162+
159163 // Pos is the source position of the func keyword or type spec
160164 // defining this provider.
161165 Pos token.Pos
@@ -718,6 +722,12 @@ func valueSpecForVar(fset *token.FileSet, files []*ast.File, obj *types.Var) *as
718722func (oc * objectCache ) processExpr (info * types.Info , pkgPath string , expr ast.Expr , varName string ) (interface {}, []error ) {
719723 exprPos := oc .fset .Position (expr .Pos ())
720724 expr = astutil .Unparen (expr )
725+ if sel , ok := expr .(* ast.SelectorExpr ); ok {
726+ if selInfo := info .Selections [sel ]; selInfo != nil && selInfo .Kind () == types .MethodExpr {
727+ p , errs := processMethodExprProvider (oc .fset , info , sel , selInfo )
728+ return p , notePositionAll (exprPos , errs )
729+ }
730+ }
721731 if obj := qualifiedIdentObject (info , expr ); obj != nil {
722732 item , errs := oc .get (obj )
723733 return item , mapErrors (errs , func (err error ) error {
@@ -877,28 +887,45 @@ func qualifiedIdentObject(info *types.Info, expr ast.Expr) types.Object {
877887func processFuncProvider (fset * token.FileSet , fn * types.Func ) (* Provider , []error ) {
878888 sig := fn .Type ().(* types.Signature )
879889 fpos := fn .Pos ()
890+ return processProviderSignature (fset , fn .Pkg (), fn .Name (), nil , fpos , sig )
891+ }
892+
893+ func processMethodExprProvider (fset * token.FileSet , info * types.Info , expr * ast.SelectorExpr , sel * types.Selection ) (* Provider , []error ) {
894+ obj , ok := sel .Obj ().(* types.Func )
895+ if ! ok {
896+ return nil , []error {fmt .Errorf ("%s is not a function" , expr .Sel .Name )}
897+ }
898+ sig , ok := info .TypeOf (expr ).(* types.Signature )
899+ if ! ok {
900+ return nil , []error {fmt .Errorf ("method expression %s does not have a function signature" , expr .Sel .Name )}
901+ }
902+ return processProviderSignature (fset , obj .Pkg (), obj .Name (), sel .Recv (), expr .Pos (), sig )
903+ }
904+
905+ func processProviderSignature (fset * token.FileSet , pkg * types.Package , name string , recv types.Type , pos token.Pos , sig * types.Signature ) (* Provider , []error ) {
880906 providerSig , err := funcOutput (sig )
881907 if err != nil {
882- return nil , []error {notePosition (fset .Position (fpos ), fmt .Errorf ("wrong signature for provider %s: %v" , fn . Name () , err ))}
908+ return nil , []error {notePosition (fset .Position (pos ), fmt .Errorf ("wrong signature for provider %s: %v" , name , err ))}
883909 }
884910 params := sig .Params ()
885911 provider := & Provider {
886- Pkg : fn .Pkg (),
887- Name : fn .Name (),
888- Pos : fn .Pos (),
889- Args : make ([]ProviderInput , params .Len ()),
890- Varargs : sig .Variadic (),
891- Out : []types.Type {providerSig .out },
892- HasCleanup : providerSig .cleanup ,
893- HasErr : providerSig .err ,
912+ Pkg : pkg ,
913+ Name : name ,
914+ MethodExprRecv : recv ,
915+ Pos : pos ,
916+ Args : make ([]ProviderInput , params .Len ()),
917+ Varargs : sig .Variadic (),
918+ Out : []types.Type {providerSig .out },
919+ HasCleanup : providerSig .cleanup ,
920+ HasErr : providerSig .err ,
894921 }
895922 for i := 0 ; i < params .Len (); i ++ {
896923 provider .Args [i ] = ProviderInput {
897924 Type : params .At (i ).Type (),
898925 }
899926 for j := 0 ; j < i ; j ++ {
900927 if types .Identical (provider .Args [i ].Type , provider .Args [j ].Type ) {
901- return nil , []error {notePosition (fset .Position (fpos ), fmt .Errorf ("provider has multiple parameters of type %s" , types .TypeString (provider .Args [j ].Type , nil )))}
928+ return nil , []error {notePosition (fset .Position (pos ), fmt .Errorf ("provider has multiple parameters of type %s" , types .TypeString (provider .Args [j ].Type , nil )))}
902929 }
903930 }
904931 }
0 commit comments