@@ -13,9 +13,10 @@ import (
1313 "strings"
1414 "unicode"
1515
16- "golang.org/x/tools/go/ast/astutil "
16+ "golang.org/x/tools/go/ast/inspector "
1717 "golang.org/x/tools/gopls/internal/cache/parsego"
1818 "golang.org/x/tools/gopls/internal/util/typesutil"
19+ "golang.org/x/tools/internal/moreiters"
1920 "golang.org/x/tools/internal/typesinternal"
2021)
2122
@@ -31,71 +32,73 @@ type CallStubInfo struct {
3132 After types.Object // decl after which to insert the new decl
3233 pointer bool
3334 info * types.Info
34- path []ast. Node // path enclosing the CallExpr
35+ curCall inspector. Cursor // cursor to the CallExpr
3536}
3637
3738// GetCallStubInfo extracts necessary information to generate a method definition from
3839// a CallExpr.
3940func GetCallStubInfo (fset * token.FileSet , info * types.Info , pgf * parsego.File , start , end token.Pos ) * CallStubInfo {
40- // TODO(adonovan): simplify, using pgf.Cursor.
41- path , _ := astutil .PathEnclosingInterval (pgf .File , start , end )
42- for i , n := range path {
43- switch n := n .(type ) {
44- case * ast.CallExpr :
45- s , ok := n .Fun .(* ast.SelectorExpr )
46- // TODO: support generating stub functions in the same way.
47- if ! ok {
48- return nil
49- }
41+ callCur , _ := pgf .Cursor .FindByPos (start , end )
42+ callCur , ok := moreiters .First (callCur .Enclosing ((* ast .CallExpr )(nil )))
43+ if ! ok {
44+ return nil
45+ }
46+ call := callCur .Node ().(* ast.CallExpr )
47+ s , ok := call .Fun .(* ast.SelectorExpr )
48+ // TODO: support generating stub functions in the same way.
49+ if ! ok {
50+ return nil
51+ }
5052
51- // If recvExpr is a package name, compiler error would be
52- // e.g., "undefined: http.bar", thus will not hit this code path.
53- recvExpr := s .X
54- recvType , pointer := concreteType (recvExpr , info )
53+ // If recvExpr is a package name, compiler error would be
54+ // e.g., "undefined: http.bar", thus will not hit this code path.
55+ recvExpr := s .X
56+ recvType , pointer := concreteType (recvExpr , info )
5557
56- if recvType == nil || recvType .Obj ().Pkg () == nil {
57- return nil
58- }
58+ if recvType == nil || recvType .Obj ().Pkg () == nil {
59+ return nil
60+ }
5961
60- // A method of a function-local type cannot be stubbed
61- // since there's nowhere to put the methods.
62- recv := recvType .Obj ()
63- if recv .Parent () != recv .Pkg ().Scope () {
64- return nil
65- }
62+ // A method of a function-local type cannot be stubbed
63+ // since there's nowhere to put the methods.
64+ recv := recvType .Obj ()
65+ if recv .Parent () != recv .Pkg ().Scope () {
66+ return nil
67+ }
6668
67- after := types .Object (recv )
68- // If the enclosing function declaration is a method declaration,
69- // and matches the receiver type of the diagnostic,
70- // insert after the enclosing method.
71- decl , ok := path [len (path )- 2 ].(* ast.FuncDecl )
72- if ok && decl .Recv != nil {
73- if len (decl .Recv .List ) != 1 {
74- return nil
75- }
76- mrt := info .TypeOf (decl .Recv .List [0 ].Type )
77- if mrt != nil && types .Identical (types .Unalias (typesinternal .Unpointer (mrt )), recv .Type ()) {
78- after = info .ObjectOf (decl .Name )
79- }
80- }
81- return & CallStubInfo {
82- Fset : fset ,
83- Receiver : recvType ,
84- MethodName : s .Sel .Name ,
85- After : after ,
86- pointer : pointer ,
87- path : path [i :],
88- info : info ,
89- }
69+ after := types .Object (recv )
70+ // If the enclosing function declaration is a method declaration,
71+ // and matches the receiver type of the diagnostic,
72+ // insert after the enclosing method.
73+ var decl * ast.FuncDecl
74+ declCur , ok := moreiters .First (callCur .Enclosing ((* ast .FuncDecl )(nil )))
75+ if ok {
76+ decl = declCur .Node ().(* ast.FuncDecl )
77+ }
78+ if decl != nil && decl .Recv != nil {
79+ if len (decl .Recv .List ) != 1 {
80+ return nil
81+ }
82+ mrt := info .TypeOf (decl .Recv .List [0 ].Type )
83+ if mrt != nil && types .Identical (types .Unalias (typesinternal .Unpointer (mrt )), recv .Type ()) {
84+ after = info .ObjectOf (decl .Name )
9085 }
9186 }
92- return nil
87+ return & CallStubInfo {
88+ Fset : fset ,
89+ Receiver : recvType ,
90+ MethodName : s .Sel .Name ,
91+ After : after ,
92+ pointer : pointer ,
93+ curCall : callCur ,
94+ info : info ,
95+ }
9396}
9497
9598// Emit writes to out the missing method based on type info of si.Receiver and CallExpr.
9699func (si * CallStubInfo ) Emit (out * bytes.Buffer , qual types.Qualifier ) error {
97100 params := si .collectParams ()
98- rets := typesutil .TypesFromContext (si .info , si .path , si . path [ 0 ]. Pos () )
101+ rets := typesutil .TypesFromContext (si .info , si .curCall )
99102 recv := si .Receiver .Obj ()
100103 // Pointer receiver?
101104 var star string
@@ -180,7 +183,7 @@ func (si *CallStubInfo) collectParams() []param {
180183 params = append (params , p )
181184 }
182185
183- args := si .path [ 0 ] .(* ast.CallExpr ).Args
186+ args := si .curCall . Node () .(* ast.CallExpr ).Args
184187 for _ , arg := range args {
185188 t := si .info .TypeOf (arg )
186189 switch t := t .(type ) {
0 commit comments