@@ -78,14 +78,19 @@ func (p *goParser) inspectFile(ctx *fileContext, f *ast.File) (map[string]*Funct
7878 fileFuncs [f .Name ] = f
7979 cont = ct
8080 } else if typDecl , ok := node .(* ast.TypeSpec ); ok {
81- // parse structs
8281 struName := typDecl .Name .Name
83- struDecl , ok := typDecl .Type .(* ast.StructType )
84- if ok {
85- st , ct := p .parseStruct (ctx , struName , struDecl )
86- fileStructs [struName ] = st
87- cont = ct
82+ var st * Struct
83+ var ct bool
84+ // parse structs
85+ if struDecl , ok := typDecl .Type .(* ast.StructType ); ok {
86+ st , ct = p .parseStruct (ctx , struName , struDecl )
87+ // parse interface
88+ } else if interDecl , ok := typDecl .Type .(* ast.InterfaceType ); ok {
89+ struName := typDecl .Name .Name
90+ st , ct = p .parseInterface (ctx , struName , interDecl )
8891 }
92+ fileStructs [struName ] = st
93+ cont = ct
8994 }
9095 return cont
9196 })
@@ -175,6 +180,9 @@ func (p *goParser) parseFunc(ctx *fileContext, funcDecl *ast.FuncDecl) (*Functio
175180 var thirdPartyMethodCalls , thirdPartyFunctionCalls = map [string ]* ThirdPartyIdentity {}, map [string ]* ThirdPartyIdentity {}
176181 var functionCalls , methodCalls = map [string ]* Function {}, map [string ]* Function {}
177182
183+ if funcDecl .Body == nil {
184+ goto set_func
185+ }
178186 ast .Inspect (funcDecl .Body , func (node ast.Node ) bool {
179187 // scope := ctx.pkgTypeInfo.Scopes[node]
180188 call , ok := node .(* ast.CallExpr )
@@ -230,12 +238,9 @@ func (p *goParser) parseFunc(ctx *fileContext, funcDecl *ast.FuncDecl) (*Functio
230238 mpkg := m .Pkg ().Path ()
231239 //NOTICE: use {structName.methodName} as method key
232240 mname := obj .Name () + "." + m .Name ()
233- f := p .getOrSetFunc (mpkg , mname )
234- f .AssociatedStruct = p .getOrSetStruct (mpkg , obj .Name ())
235- f .IsMethod = true
236-
237241 if strings .HasPrefix (mpkg , p .modName ) {
238242 // internal pkg
243+ f := p .getOrSetFunc (mpkg , mname )
239244 methodCalls [funcName ] = f
240245 } else {
241246 // external pkg
@@ -253,6 +258,8 @@ func (p *goParser) parseFunc(ctx *fileContext, funcDecl *ast.FuncDecl) (*Functio
253258 }
254259 return true
255260 })
261+
262+ set_func:
256263 name := funcDecl .Name .Name
257264 if isMethod {
258265 name = associatedStruct .Name + "." + name
@@ -292,10 +299,11 @@ func (ctx *fileContext) IsSysImport(alias string) bool {
292299
293300// Struct holds the information about a struct
294301type Struct struct {
295- Name string // Name of the struct
296- PkgPath // Path to the package where the struct is defined
297- FilePath string // File where the struct is defined
298- Content string // struct declaration content
302+ IsInterface bool //maybe a interface type decl
303+ Name string // Name of the struct
304+ PkgPath // Path to the package where the struct is defined
305+ FilePath string // File where the struct is defined
306+ Content string // struct declaration content
299307
300308 // related local structs in fields, key is {{pkgName.typName}} or {{typeName}}, val is declaration of the struct
301309 InternalStructs map [string ]* Struct
@@ -325,8 +333,7 @@ type fileContext struct {
325333
326334// parse a ast.StructType node and renturn allocated *Struct
327335func (p * goParser ) parseStruct (ctx * fileContext , struName string , struDecl * ast.StructType ) (* Struct , bool ) {
328- pkgPath := p .pkgPathFromABS (filepath .Dir (ctx .filePath ))
329- st := p .getOrSetStruct (pkgPath , struName )
336+ st := p .getOrSetStruct (ctx .pkgPath , struName )
330337 st .FilePath = ctx .filePath
331338
332339 pos := ctx .fset .PositionFor (struDecl .Pos (), false ).Offset
@@ -347,7 +354,7 @@ func (p *goParser) parseStruct(ctx *fileContext, struName string, struDecl *ast.
347354 // TODO: combine all names
348355 name = fieldDecl .Names [0 ].String ()
349356 } else {
350- name = string (ctx .bs [ fieldDecl . Type . Pos (): fieldDecl . Type . End ()] )
357+ name = string (ctx .GetRawContent ( fieldDecl ) )
351358 }
352359
353360 types := []ThirdPartyIdentity {}
@@ -374,7 +381,7 @@ func (p *goParser) parseStruct(ctx *fileContext, struName string, struDecl *ast.
374381 }
375382 } else {
376383 // local package
377- sub := p .getOrSetStruct (pkgPath , ty .Identity )
384+ sub := p .getOrSetStruct (ctx . pkgPath , ty .Identity )
378385 inStructs [name ] = sub
379386 }
380387
@@ -390,6 +397,52 @@ func (p *goParser) parseStruct(ctx *fileContext, struName string, struDecl *ast.
390397 return st , true
391398}
392399
400+ func (ctx * fileContext ) GetRawContent (node ast.Node ) []byte {
401+ return ctx .bs [ctx .fset .Position (node .Pos ()).Offset :ctx .fset .Position (node .End ()).Offset ]
402+ }
403+
404+ func (p * goParser ) parseInterface (ctx * fileContext , name string , decl * ast.InterfaceType ) (* Struct , bool ) {
405+ if decl == nil || decl .Incomplete {
406+ return nil , true
407+ }
408+
409+ st := p .getOrSetStruct (ctx .pkgPath , name )
410+ st .FilePath = ctx .filePath
411+ st .IsInterface = true
412+ st .Content = string (ctx .GetRawContent (decl ))
413+
414+ methods := map [string ]* Function {}
415+ ast .Inspect (decl .Methods , func (n ast.Node ) bool {
416+ fieldDecl , ok := n .(* ast.Field )
417+ if ! ok {
418+ return true
419+ }
420+ fname := ""
421+ if len (fieldDecl .Names ) > 0 {
422+ // TODO: combine all names
423+ fname = fieldDecl .Names [0 ].String ()
424+ } else {
425+ fname = string (ctx .GetRawContent (fieldDecl .Type ))
426+ }
427+
428+ types := []ThirdPartyIdentity {}
429+ isFunc := getTypeName (ctx .fset , ctx .bs , fieldDecl .Type , & types )
430+ if ! isFunc {
431+ return true
432+ }
433+
434+ f := p .getOrSetFunc (ctx .pkgPath , name + "." + fname )
435+ f .IsMethod = true
436+ f .AssociatedStruct = st
437+ f .FilePath = ctx .filePath
438+ methods [fname ] = f
439+ return true
440+ })
441+
442+ st .Methods = methods
443+ return st , true
444+ }
445+
393446// handle typ expr and return not-builtin type identity and return if the type if a func signature.
394447// ret is used to store results.
395448func getTypeName (fset * token.FileSet , file []byte , typ ast.Expr , ret * []ThirdPartyIdentity ) bool {
0 commit comments