@@ -184,13 +184,13 @@ func (p *goParser) parseFunc(ctx *fileContext, funcDecl *ast.FuncDecl) (*Functio
184184 if funcDecl .Body == nil {
185185 goto set_func
186186 }
187+
187188 ast .Inspect (funcDecl .Body , func (node ast.Node ) bool {
188189 call , ok := node .(* ast.CallExpr )
189190 if ok {
190191 var funcName string
191192 switch expr := call .Fun .(type ) {
192193 case * ast.SelectorExpr :
193- funcName := ""
194194 // TODO: not the best but works, optimize it later.
195195 x := expr .X
196196 for {
@@ -204,28 +204,12 @@ func (p *goParser) parseFunc(ctx *fileContext, funcDecl *ast.FuncDecl) (*Functio
204204 }
205205 break
206206 }
207- // fixme: in closure like func(importName StructX) { ... }, importName is not in projectImports
208207 funcName = x .(* ast.Ident ).Name + "." + expr .Sel .Name
209- // internal function calls
210- if impt , ok := ctx .projectImports [x .(* ast.Ident ).Name ]; ok {
211- functionCalls [funcName ] = Identity {impt , expr .Sel .Name }
212- return true
213- }
214- // third-party function calls
215- if impt , ok := ctx .thirdPartyImports [x .(* ast.Ident ).Name ]; ok {
216- thirdPartyFunctionCalls [funcName ] = Identity {PkgPath : impt , Name : expr .Sel .Name }
217- return true
218- }
219- // NOTICE: skip sys imports?
220- if ctx .IsSysImport (x .(* ast.Ident ).Name ) {
221- return true
222- }
223208 // check if it's method calls
224- sel , ok := ctx .pkgTypeInfo .Selections [expr ]
225- if ok && (sel .Kind () == types .MethodExpr || sel .Kind () == types .MethodVal ) {
209+ if sel , ok := ctx .pkgTypeInfo .Selections [expr ]; ok && (sel .Kind () == types .MethodExpr || sel .Kind () == types .MethodVal ) {
226210 // builtin or std libs, just ignore
227- m := sel .Obj ().(* types.Func )
228- if m == nil || m .Pkg () == nil || ctx .IsSysImport (m .Pkg ().Name ()) {
211+ m , ok := sel .Obj ().(* types.Func )
212+ if ! ok || m .Pkg () == nil || ctx .IsSysImport (m .Pkg ().Name ()) {
229213 return true
230214 }
231215 sig := m .Type ().(* types.Signature )
@@ -244,13 +228,61 @@ func (p *goParser) parseFunc(ctx *fileContext, funcDecl *ast.FuncDecl) (*Functio
244228 // external pkg
245229 thirdPartyMethodCalls [funcName ] = Identity {mpkg , mname }
246230 }
231+ return true
232+ }
233+ // check if it's a package reference
234+ if use , ok := ctx .pkgTypeInfo .Uses [x .(* ast.Ident )]; ok {
235+ pkg , ok := use .(* types.PkgName )
236+ if ! ok || pkg .Imported () == nil {
237+ return true
238+ }
239+ // NOTICE: skip sys imports?
240+ if ctx .IsSysImport (pkg .Imported ().Name ()) {
241+ return true
242+ }
243+ typ , ok := ctx .pkgTypeInfo .Types [expr ]
244+ if ! ok {
245+ return true
246+ }
247+ // expr type must be func signature
248+ if _ , ok := typ .Type .(* types.Signature ); ! ok {
249+ return true
250+ }
251+ // internal function calls
252+ if impt , ok := ctx .projectImports [pkg .Imported ().Name ()]; ok {
253+ functionCalls [funcName ] = Identity {impt , expr .Sel .Name }
254+ return true
255+ }
256+ // third-party function calls
257+ if impt , ok := ctx .thirdPartyImports [pkg .Imported ().Name ()]; ok {
258+ thirdPartyFunctionCalls [funcName ] = Identity {PkgPath : impt , Name : expr .Sel .Name }
259+ return true
260+ }
261+ return true
247262 }
248- return true
249263 case * ast.Ident :
250264 funcName = expr .Name
251- if ! isGoBuiltinFunc (funcName ) {
252- functionCalls [funcName ] = Identity {ctx .pkgPath , funcName }
265+ if isGoBuiltinFunc (funcName ) {
266+ return true
267+ }
268+ typ , ok := ctx .pkgTypeInfo .Types [expr ]
269+ if ! ok {
270+ return true
271+ }
272+ // TODO: we can't handle variant func (closure) at present
273+ obj := ctx .pkgTypeInfo .Defs [expr ]
274+ if _ , isVar := obj .(* types.Var ); isVar {
275+ return true
276+ }
277+ obj = ctx .pkgTypeInfo .Uses [expr ]
278+ if _ , isVar := obj .(* types.Var ); isVar {
279+ return true
280+ }
281+ // expr type must be func signature
282+ if _ , ok := typ .Type .(* types.Signature ); ! ok {
283+ return true
253284 }
285+ functionCalls [funcName ] = Identity {ctx .pkgPath , funcName }
254286 return true
255287 }
256288 }
@@ -359,7 +391,6 @@ func (p *goParser) parseStruct(ctx *fileContext, struName string, struDecl *ast.
359391 fieldname = fieldDecl .Names [0 ].Name
360392 }
361393 p .collectTypes (ctx , fieldname , fieldDecl .Type , st , inlined )
362-
363394 return true
364395 })
365396 return st , true
@@ -370,8 +401,17 @@ func (p *goParser) collectTypes(ctx *fileContext, field string, typ ast.Expr, st
370401 isFunc := getTypeName (ctx .fset , ctx .bs , typ , & types )
371402
372403 for _ , ty := range types {
404+ // regard func-typed field as a method on the struct
373405 if isFunc {
374- mname := st .Name + "." + field
406+ // Fix: multiple types use the same mname
407+ // ex: type FuncMap map[func()]func()
408+ if len (types ) > 1 {
409+ continue
410+ }
411+ mname := st .Name
412+ if field != "" {
413+ mname += "." + field
414+ }
375415 f := p .newFunc (ctx .pkgPath , mname )
376416 f .AssociatedStruct = & Identity {ctx .pkgPath , st .Name }
377417 f .IsMethod = true
@@ -424,36 +464,21 @@ func (p *goParser) parseInterface(ctx *fileContext, name string, decl *ast.Inter
424464 st .TypeKind = TypeKindInterface
425465 st .Content = string (ctx .GetRawContent (decl ))
426466
427- methods := map [string ]Identity {}
428467 ast .Inspect (decl .Methods , func (n ast.Node ) bool {
429468 fieldDecl , ok := n .(* ast.Field )
430469 if ! ok {
431470 return true
432471 }
433- fname := ""
434- if len (fieldDecl .Names ) > 0 {
435- // TODO: combine all names
436- fname = fieldDecl .Names [0 ].String ()
437- } else {
438- fname = string (ctx .GetRawContent (fieldDecl .Type ))
439- }
440-
441- types := []Identity {}
442- isFunc := getTypeName (ctx .fset , ctx .bs , fieldDecl .Type , & types )
443- if ! isFunc {
444- return true
472+ inlined := len (fieldDecl .Names ) == 0
473+ fieldname := string (ctx .GetRawContent (fieldDecl .Type ))
474+ if ! inlined {
475+ // Fixme: join names?
476+ fieldname = fieldDecl .Names [0 ].Name
445477 }
446-
447- mname := name + "." + fname
448- f := p .newFunc (ctx .pkgPath , mname )
449- f .IsMethod = true
450- f .AssociatedStruct = & Identity {st .PkgPath , st .Name }
451- f .FilePath = ctx .filePath
452- methods [fname ] = Identity {f .PkgPath , mname }
478+ p .collectTypes (ctx , fieldname , fieldDecl .Type , st , inlined )
453479 return true
454480 })
455481
456- st .Methods = methods
457482 return st , true
458483}
459484
0 commit comments