Skip to content

Commit ccbf09c

Browse files
committed
fix: method handler 不能解析
1 parent 7f3ec20 commit ccbf09c

7 files changed

Lines changed: 121 additions & 99 deletions

File tree

context.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strconv"
99

1010
"github.com/gotomicro/eapi/spec"
11+
"github.com/gotomicro/eapi/utils"
1112
"golang.org/x/tools/go/packages"
1213
)
1314

@@ -212,6 +213,23 @@ func (c *Context) MatchCall(n ast.Node, rule *CallRule, callback func(call *ast.
212213
return
213214
}
214215

216+
func (c *Context) GetFuncFromAstNode(n ast.Node) *types.Func {
217+
var obj interface{}
218+
switch handlerArg := n.(type) {
219+
case *ast.Ident:
220+
obj = c.Package().TypesInfo.ObjectOf(handlerArg)
221+
case *ast.SelectorExpr:
222+
obj = c.Package().TypesInfo.ObjectOf(handlerArg.Sel)
223+
default:
224+
return nil
225+
}
226+
fn, ok := obj.(*types.Func)
227+
if !ok {
228+
return nil
229+
}
230+
return fn
231+
}
232+
215233
type CallInfo struct {
216234
Type string
217235
Method string
@@ -298,15 +316,7 @@ func (c *Context) parseCallInfoByIdent(ident *ast.Ident) (info *CallInfo) {
298316
if !ok {
299317
return nil
300318
}
301-
info.Method = fn.Name()
302-
303-
sign := fn.Type().(*types.Signature)
304-
if sign.Recv() != nil {
305-
info.Type = sign.Recv().Type().String()
306-
} else {
307-
info.Type = fn.Pkg().Path()
308-
}
309-
319+
info.Type, info.Method = utils.GetFuncInfo(fn)
310320
return
311321
}
312322

plugins/echo/echo.go

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package echo
22

33
import (
4+
"fmt"
45
"go/ast"
56
"go/token"
67
"go/types"
8+
"os"
79
"path"
810
"regexp"
911
"strings"
1012

1113
"github.com/gotomicro/eapi"
1214
"github.com/gotomicro/eapi/plugins/common"
15+
"github.com/gotomicro/eapi/utils"
1316
"github.com/knadh/koanf"
1417
)
1518

@@ -152,8 +155,12 @@ func (e *Plugin) parseAPI(ctx *eapi.Context, callExpr *ast.CallExpr, comment *ea
152155
if handlerFn == nil {
153156
return
154157
}
155-
156-
handlerDef := ctx.GetDefinition(handlerFn.Pkg().Path(), handlerFn.Name())
158+
typeName, methodName := utils.GetFuncInfo(handlerFn)
159+
handlerDef := ctx.GetDefinition(typeName, methodName)
160+
if handlerDef == nil {
161+
fmt.Fprintf(os.Stderr, "handler function %s.%s not found\n", typeName, methodName)
162+
return
163+
}
157164
handlerFnDef, ok := handlerDef.(*eapi.FuncDefinition)
158165
if !ok {
159166
return
@@ -182,46 +189,14 @@ func (e *Plugin) parseAPI(ctx *eapi.Context, callExpr *ast.CallExpr, comment *ea
182189

183190
func (e *Plugin) getHandlerFn(ctx *eapi.Context, callExpr *ast.CallExpr) (handlerFn *types.Func) {
184191
handlerArg := callExpr.Args[len(callExpr.Args)-1]
185-
186192
if call, ok := handlerArg.(*ast.CallExpr); ok {
187-
nestedCall := e.unwrapCall(call)
193+
nestedCall := utils.UnwrapCall(call)
188194
if len(nestedCall.Args) <= 0 {
189195
return
190196
}
191197
handlerArg = nestedCall.Args[0]
192198
}
193-
194-
var handler interface{}
195-
switch handlerArg := handlerArg.(type) {
196-
case *ast.Ident:
197-
handler = ctx.Package().TypesInfo.Uses[handlerArg]
198-
case *ast.SelectorExpr:
199-
handler = ctx.Package().TypesInfo.Uses[handlerArg.Sel]
200-
default:
201-
return
202-
}
203-
204-
handlerFn, ok := handler.(*types.Func)
205-
if !ok {
206-
return nil
207-
}
208-
return
209-
}
210-
211-
// unwrap and returns the first nested call
212-
// e.g. unwrapCall(`a(b(c(d)), b1(c1))`) return `c(d)`
213-
func (e *Plugin) unwrapCall(callExpr *ast.CallExpr) *ast.CallExpr {
214-
if len(callExpr.Args) == 0 {
215-
return callExpr
216-
}
217-
218-
arg0 := callExpr.Args[0]
219-
arg0Call, ok := arg0.(*ast.CallExpr)
220-
if ok {
221-
return e.unwrapCall(arg0Call)
222-
}
223-
224-
return callExpr
199+
return ctx.GetFuncFromAstNode(handlerArg)
225200
}
226201

227202
var (

plugins/gin/gin.go

Lines changed: 6 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
analyzer "github.com/gotomicro/eapi"
1414
"github.com/gotomicro/eapi/plugins/common"
15+
"github.com/gotomicro/eapi/utils"
1516
"github.com/knadh/koanf"
1617
)
1718

@@ -167,10 +168,10 @@ func (e *Plugin) parseAPI(ctx *analyzer.Context, callExpr *ast.CallExpr, comment
167168
if handlerFn == nil {
168169
return
169170
}
170-
171-
handlerDef := ctx.GetDefinition(handlerFn.Pkg().Path(), handlerFn.Name())
171+
typeName, methodName := utils.GetFuncInfo(handlerFn)
172+
handlerDef := ctx.GetDefinition(typeName, methodName)
172173
if handlerDef == nil {
173-
fmt.Fprintf(os.Stderr, "handler function %s.%s not found\n", handlerFn.Pkg().Path(), handlerFn.Name())
174+
fmt.Fprintf(os.Stderr, "handler function %s.%s not found\n", typeName, methodName)
174175
return
175176
}
176177
handlerFnDef, ok := handlerDef.(*analyzer.FuncDefinition)
@@ -198,49 +199,16 @@ func (e *Plugin) parseAPI(ctx *analyzer.Context, callExpr *ast.CallExpr, comment
198199
return
199200
}
200201

201-
// unwrap and returns the first nested call
202-
// e.g. unwrapCall(`a(b(c(d)), b1(c1))`) return `c(d)`
203-
func (e *Plugin) unwrapCall(callExpr *ast.CallExpr) *ast.CallExpr {
204-
if len(callExpr.Args) == 0 {
205-
return callExpr
206-
}
207-
208-
arg0 := callExpr.Args[0]
209-
arg0Call, ok := arg0.(*ast.CallExpr)
210-
if ok {
211-
return e.unwrapCall(arg0Call)
212-
}
213-
214-
return callExpr
215-
}
216-
217202
func (e *Plugin) getHandlerFn(ctx *analyzer.Context, callExpr *ast.CallExpr) (handlerFn *types.Func) {
218203
handlerArg := callExpr.Args[len(callExpr.Args)-1]
219-
220204
if call, ok := handlerArg.(*ast.CallExpr); ok {
221-
nestedCall := e.unwrapCall(call)
205+
nestedCall := utils.UnwrapCall(call)
222206
if len(nestedCall.Args) <= 0 {
223207
return
224208
}
225209
handlerArg = nestedCall.Args[0]
226210
}
227-
228-
var handler interface{}
229-
switch handlerArg := handlerArg.(type) {
230-
case *ast.Ident:
231-
handler = ctx.Package().TypesInfo.Uses[handlerArg]
232-
case *ast.SelectorExpr:
233-
handler = ctx.Package().TypesInfo.Uses[handlerArg.Sel]
234-
default:
235-
return
236-
}
237-
238-
handlerFn, ok := handler.(*types.Func)
239-
if !ok {
240-
return
241-
}
242-
243-
return
211+
return ctx.GetFuncFromAstNode(handlerArg)
244212
}
245213

246214
var (

test/testdata/gin/docs/openapi.json

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,19 @@
213213
"title": "GormDeletedAt",
214214
"type": "string"
215215
},
216+
"server_pkg_shop.GoodsInfoPathParams": {
217+
"ext": {
218+
"type": "object"
219+
},
220+
"properties": {
221+
"guid": {
222+
"description": "Goods Guid",
223+
"type": "integer"
224+
}
225+
},
226+
"title": "ShopGoodsInfoPathParams",
227+
"type": "object"
228+
},
216229
"server_pkg_view.ErrCode": {
217230
"description": "\u003ctable\u003e\u003ctr\u003e\u003cth\u003eValue\u003c/th\u003e\u003cth\u003eKey\u003c/th\u003e\u003cth\u003eDescription\u003c/th\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003c/td\u003e\u003ctd\u003eCodeNotFound\u003c/td\u003e\u003ctd\u003eResource not found\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003c/td\u003e\u003ctd\u003eCodeCancled\u003c/td\u003e\u003ctd\u003eRequest canceld\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003c/td\u003e\u003ctd\u003eCodeUnknown\u003c/td\u003e\u003ctd\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003c/td\u003e\u003ctd\u003eCodeInvalidArgument\u003c/td\u003e\u003ctd\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e",
218231
"enum": [
@@ -448,19 +461,6 @@
448461
},
449462
"title": "ViewSelfRefType",
450463
"type": "object"
451-
},
452-
"server_pkg_shop.GoodsInfoPathParams": {
453-
"title": "ShopGoodsInfoPathParams",
454-
"type": "object",
455-
"ext": {
456-
"type": "object"
457-
},
458-
"properties": {
459-
"guid": {
460-
"description": "Goods Guid",
461-
"type": "integer"
462-
}
463-
}
464464
}
465465
},
466466
"securitySchemes": {
@@ -485,6 +485,27 @@
485485
},
486486
"openapi": "3.1.0",
487487
"paths": {
488+
"/api/controller/goods/{guid}": {
489+
"delete": {
490+
"operationId": "controller.Delete",
491+
"parameters": [
492+
{
493+
"description": "Goods Guid",
494+
"in": "path",
495+
"name": "guid",
496+
"required": true,
497+
"schema": {
498+
"title": "guid",
499+
"type": "string"
500+
}
501+
}
502+
],
503+
"responses": {},
504+
"tags": [
505+
"Shop"
506+
]
507+
}
508+
},
488509
"/api/goods": {
489510
"post": {
490511
"description": "GoodsCreate 创建商品接口",
@@ -626,10 +647,10 @@
626647
"operationId": "shop.GoodsInfo",
627648
"parameters": [
628649
{
650+
"description": "Goods Guid",
629651
"in": "path",
630652
"name": "guid",
631653
"required": true,
632-
"description": "Goods Guid",
633654
"schema": {
634655
"description": "Goods Guid",
635656
"type": "integer"
@@ -712,4 +733,4 @@
712733
}
713734
}
714735
}
715-
}
736+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package controller
2+
3+
import "github.com/gin-gonic/gin"
4+
5+
type GoodsController struct{}
6+
7+
func NewGoodsController() *GoodsController {
8+
return &GoodsController{}
9+
}
10+
11+
func (s *GoodsController) Delete(c *gin.Context) {
12+
// Goods Guid
13+
_ = c.Param("guid")
14+
}

test/testdata/gin/router.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package router
22

33
import (
4+
"server/pkg/controller"
45
"server/pkg/handler"
56
"server/pkg/shop"
67

@@ -33,9 +34,13 @@ func ServeHttp() *gin.Engine {
3334
g.POST("/goods", handler.Handler(shop.GoodsCreate))
3435
g.POST("/goods/:guid/down", shop.GoodsDown)
3536
}
36-
g = g.Group("/v2")
37+
g := g.Group("/v2")
3738
g.GET("/goods/:guid", shop.GoodsInfo)
3839
}
3940

41+
// controller style
42+
goodsController := controller.NewGoodsController()
43+
g.DELETE("/controller/goods/:guid", goodsController.Delete)
44+
4045
return r
4146
}

utils/utils.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,39 @@
11
package utils
22

33
import (
4+
"go/ast"
5+
"go/types"
46
"os"
57
"strings"
68
)
79

810
func Debug() bool {
911
return os.Getenv("DEBUG") == "true" || strings.HasSuffix(os.Args[0], ".test")
1012
}
13+
14+
// UnwrapCall unwrap and returns the first nested call
15+
// e.g. unwrapCall(`a(b(c(d)), b1(c1))`) return `c(d)`
16+
func UnwrapCall(callExpr *ast.CallExpr) *ast.CallExpr {
17+
if len(callExpr.Args) == 0 {
18+
return callExpr
19+
}
20+
21+
arg0 := callExpr.Args[0]
22+
arg0Call, ok := arg0.(*ast.CallExpr)
23+
if ok {
24+
return UnwrapCall(arg0Call)
25+
}
26+
27+
return callExpr
28+
}
29+
30+
func GetFuncInfo(fn *types.Func) (typeName, methodName string) {
31+
sign := fn.Type().(*types.Signature)
32+
if sign.Recv() != nil {
33+
typeName = sign.Recv().Type().String()
34+
} else {
35+
typeName = fn.Pkg().Path()
36+
}
37+
methodName = fn.Name()
38+
return
39+
}

0 commit comments

Comments
 (0)