@@ -218,7 +218,7 @@ func fromCallExpr(fset *token.FileSet, info *types.Info, pos token.Pos, call *as
218218 return nil
219219 }
220220
221- concType , pointer := concreteType (arg , info )
221+ concType , pointer := concreteType (info , arg )
222222 if concType == nil || concType .Obj ().Pkg () == nil {
223223 return nil
224224 }
@@ -272,7 +272,7 @@ func fromReturnStmt(fset *token.FileSet, info *types.Info, pos token.Pos, path [
272272 return nil , fmt .Errorf ("pos %d not within return statement bounds: [%d-%d]" , pos , ret .Pos (), ret .End ())
273273 }
274274
275- concType , pointer := concreteType (ret .Results [returnIdx ], info )
275+ concType , pointer := concreteType (info , ret .Results [returnIdx ])
276276 if concType == nil || concType .Obj ().Pkg () == nil {
277277 return nil , nil // result is not a named or *named or alias thereof
278278 }
@@ -330,7 +330,7 @@ func fromValueSpec(fset *token.FileSet, info *types.Info, spec *ast.ValueSpec, p
330330 ifaceNode = call .Fun
331331 rhs = call .Args [0 ]
332332 }
333- concType , pointer := concreteType (rhs , info )
333+ concType , pointer := concreteType (info , rhs )
334334 if concType == nil || concType .Obj ().Pkg () == nil {
335335 return nil
336336 }
@@ -385,7 +385,7 @@ func fromAssignStmt(fset *token.FileSet, info *types.Info, assign *ast.AssignStm
385385 if ifaceObj == nil {
386386 return nil
387387 }
388- concType , pointer := concreteType (rhs , info )
388+ concType , pointer := concreteType (info , rhs )
389389 if concType == nil || concType .Obj ().Pkg () == nil {
390390 return nil
391391 }
@@ -434,7 +434,7 @@ func ifaceObjFromType(t types.Type) *types.TypeName {
434434// method will return a nil *types.Named. The second return parameter
435435// is a boolean that indicates whether the concreteType was defined as a
436436// pointer or value.
437- func concreteType (e ast. Expr , info * types.Info ) (* types.Named , bool ) {
437+ func concreteType (info * types.Info , e ast. Expr ) (* types.Named , bool ) {
438438 tv , ok := info .Types [e ]
439439 if ! ok {
440440 return nil , false
@@ -451,6 +451,7 @@ func concreteType(e ast.Expr, info *types.Info) (*types.Named, bool) {
451451 return named , isPtr
452452}
453453
454+ // GetFieldStubInfo creates a StructFieldInfo instance to generate a struct field in a given SelectorExpr
454455func GetFieldStubInfo (fset * token.FileSet , info * types.Info , path []ast.Node ) * StructFieldInfo {
455456 for _ , node := range path {
456457 s , ok := node .(* ast.SelectorExpr )
@@ -460,43 +461,25 @@ func GetFieldStubInfo(fset *token.FileSet, info *types.Info, path []ast.Node) *S
460461 // If recvExpr is a package name, compiler error would be
461462 // e.g., "undefined: http.bar", thus will not hit this code path.
462463 recvExpr := s .X
463- recvType , _ := concreteType (recvExpr , info )
464+ recvNamed , _ := concreteType (info , recvExpr )
464465
465- if recvType == nil || recvType .Obj ().Pkg () == nil {
466+ if recvNamed == nil || recvNamed .Obj ().Pkg () == nil {
466467 return nil
467468 }
468469
469- // A method of a function-local type cannot be stubbed
470- // since there's nowhere to put the methods.
471- recv := recvType .Obj ()
472- if recv .Parent () != recv .Pkg ().Scope () {
473- return nil
474- }
475-
476- obj := types .Object (recv )
477- tv , ok := info .Types [s .X ]
478- if ! ok {
479- break
480- }
481-
482- named , ok := tv .Type .(* types.Named )
483- if ! ok {
484- break
485- }
486-
487- structType , ok := named .Underlying ().(* types.Struct )
470+ structType , ok := recvNamed .Underlying ().(* types.Struct )
488471 if ! ok {
489472 break
490473 }
491474
475+ // Have: x.f where x has a named struct type.
492476 return & StructFieldInfo {
493- Fset : fset ,
494- Expr : s ,
495- Struct : structType ,
496- Named : named ,
497- Info : info ,
498- Path : path ,
499- Object : obj ,
477+ Fset : fset ,
478+ Expr : s ,
479+ Named : recvNamed ,
480+ info : info ,
481+ path : path ,
482+ structType : structType ,
500483 }
501484 }
502485
@@ -505,13 +488,18 @@ func GetFieldStubInfo(fset *token.FileSet, info *types.Info, path []ast.Node) *S
505488
506489// StructFieldInfo describes f field in x.f where x has a named struct type
507490type StructFieldInfo struct {
508- Fset * token.FileSet
509- Expr * ast.SelectorExpr
510- Struct * types.Struct
511- Named * types.Named
512- Info * types.Info
513- Path []ast.Node
514- Object types.Object
491+ // Fset is a file set to provide a file where the struct field is accessed
492+ Fset * token.FileSet
493+ // Expr is a selector expression
494+ Expr * ast.SelectorExpr
495+ // Named is a selected struct type
496+ Named * types.Named
497+
498+ info * types.Info
499+ // path is a node path to SelectorExpr
500+ path []ast.Node
501+ // structType is an underlying struct type, makes sure the receiver is a struct
502+ structType * types.Struct
515503}
516504
517505// Emit writes to out the missing field based on type info.
@@ -521,22 +509,18 @@ func (si *StructFieldInfo) Emit(out *bytes.Buffer, qual types.Qualifier) error {
521509 }
522510
523511 // Get types from context at the selector expression position
524- typesFromContext := typesutil .TypesFromContext (si .Info , si .Path , si .Expr .Pos ())
512+ typesFromContext := typesutil .TypesFromContext (si .info , si .path , si .Expr .Pos ())
525513
526- // Default to interface{} if we couldn't determine the type from context
514+ // Default to any if we couldn't determine the type from context
527515 var fieldType types.Type
528516 if len (typesFromContext ) > 0 {
529517 fieldType = typesFromContext [0 ]
530518 } else {
531- // Create a new interface{} type
532519 fieldType = types .Universe .Lookup ("any" ).Type ()
533520 }
534521
535- out .Write ([]byte {'\n' , '\t' })
536- out .WriteString (si .Expr .Sel .Name )
537- out .WriteByte (' ' )
538- out .WriteString (types .TypeString (fieldType , qual ))
539- if si .Struct .NumFields () == 0 {
522+ fmt .Fprintf (out , "\n \t %s %s" , si .Expr .Sel .Name , types .TypeString (fieldType , qual ))
523+ if si .structType .NumFields () == 0 {
540524 out .WriteByte ('\n' )
541525 }
542526 return nil
0 commit comments