@@ -247,26 +247,35 @@ func GetRawContent(fset *token.FileSet, file []byte, node ast.Node, collectComme
247247// return ctx.bs[ctx.fset.Position(from).Offset:ctx.fset.Position(to).Offset]
248248// }
249249
250+ type typeInfo struct {
251+ Id Identity
252+ IsPointer bool
253+ IsStdOrBuiltin bool
254+ Deps []Identity
255+ }
256+
250257// FIXME: for complex type like map[XX]YY , we only extract first-meet type here
251- func (ctx * fileContext ) GetTypeId (typ ast.Expr ) ( x Identity , isPointer bool , isStdOrBuiltin bool ) {
258+ func (ctx * fileContext ) GetTypeInfo (typ ast.Expr ) typeInfo {
252259 if tinfo , ok := ctx .pkgTypeInfo .Types [typ ]; ok {
253- return ctx .getIdFromType (tinfo .Type )
260+ return ctx .getTypeinfo (tinfo .Type )
254261 } else {
255262 // NOTICE: for unloaded type, we only mock the type name
256263 fmt .Fprintf (os .Stderr , "cannot find type info for %s\n " , ctx .GetRawContent (typ ))
257264 return ctx .mockType (typ )
258265 }
259266}
260267
261- func (ctx * fileContext ) mockType (typ ast.Expr ) ( x Identity , isPointer bool , isStdOrBuiltin bool ) {
268+ func (ctx * fileContext ) mockType (typ ast.Expr ) typeInfo {
262269 switch ty := typ .(type ) {
263270 case * ast.StarExpr :
264- id , _ , std := ctx .mockType (ty .X )
265- return id , true , std
271+ ti := ctx .mockType (ty .X )
272+ ti .IsPointer = true
273+ return ti
266274 case * ast.CallExpr :
267275 // try get func type
268- id , _ , std := ctx .mockType (ty .Fun )
269- return id , false , std
276+ ti := ctx .mockType (ty .Fun )
277+ ti .IsPointer = false
278+ return ti
270279 case * ast.SelectorExpr :
271280 // try get import path
272281 switch xx := ty .X .(type ) {
@@ -275,30 +284,36 @@ func (ctx *fileContext) mockType(typ ast.Expr) (x Identity, isPointer bool, isSt
275284 if err != nil {
276285 goto fallback
277286 }
278- return NewIdentity (mod , PkgPath (impt ), ty .Sel .Name ), false , false
287+ return typeInfo { NewIdentity (mod , PkgPath (impt ), ty .Sel .Name ), false , false , nil }
279288 case * ast.SelectorExpr :
280289 // recurse
281- id , _ , std := ctx .mockType (xx )
282- return NewIdentity (id .ModPath , id .PkgPath , ty .Sel .Name ), false , std
290+ ti := ctx .mockType (xx )
291+ ti .Id .Name = ty .Sel .Name
292+ ti .IsPointer = false
293+ return ti
283294 }
284295 }
285296
286297fallback:
287- return NewIdentity ("UNLOADED" , ctx .pkgPath , string (ctx .GetRawContent (typ ))), false , true
298+ return typeInfo { NewIdentity ("UNLOADED" , ctx .pkgPath , string (ctx .GetRawContent (typ ))), false , true , nil }
288299}
289300
290301func (ctx * fileContext ) collectFields (fields []* ast.Field , m * []Dependency ) {
291302 for _ , fieldDecl := range fields {
292- id , _ , isStdOrBuiltin := ctx .GetTypeId (fieldDecl .Type )
293- if isStdOrBuiltin || id .PkgPath == "" {
294- continue
303+ ti := ctx .GetTypeInfo (fieldDecl .Type )
304+ if ! ti .IsStdOrBuiltin && ti .Id .ModPath != "" {
305+ * m = InsertDependency (* m , Dependency {
306+ Identity : ti .Id ,
307+ FileLine : ctx .FileLine (fieldDecl ),
308+ })
309+ }
310+ for _ , dep := range ti .Deps {
311+ * m = InsertDependency (* m , Dependency {
312+ Identity : dep ,
313+ FileLine : ctx .FileLine (fieldDecl ),
314+ })
295315 }
296- * m = append (* m , Dependency {
297- Identity : id ,
298- FileLine : ctx .FileLine (fieldDecl ),
299- })
300316 }
301- return
302317}
303318
304319type importInfo struct {
@@ -410,74 +425,81 @@ func getTypeName(fset *token.FileSet, file []byte, typ ast.Expr) (ret []Identity
410425}
411426
412427func (p * GoParser ) collectTypes (ctx * fileContext , typ ast.Expr , st * Type , inlined bool ) {
413- id , _ , isGoBuiltins := ctx .GetTypeId (typ )
414- dep := NewDependency (id , ctx .FileLine (typ ))
415- if isGoBuiltins || id .PkgPath == "" {
416- return
417- }
418- if err := p .referCodes (ctx , & id , p .opts .ReferCodeDepth ); err != nil {
419- fmt .Fprintf (os .Stderr , "failed to get refer code for %s: %v\n " , id .Name , err )
428+ ti := ctx .GetTypeInfo (typ )
429+ if ! ti .IsStdOrBuiltin && ti .Id .ModPath != "" {
430+ dep := NewDependency (ti .Id , ctx .FileLine (typ ))
431+ if err := p .referCodes (ctx , & ti .Id , p .opts .ReferCodeDepth ); err != nil {
432+ fmt .Fprintf (os .Stderr , "failed to get refer code for %s: %v\n " , ti .Id , err )
433+ }
434+ if inlined {
435+ st .InlineStruct = InsertDependency (st .InlineStruct , dep )
436+ } else {
437+ st .SubStruct = InsertDependency (st .SubStruct , dep )
438+ }
420439 }
421- if inlined {
422- st .InlineStruct = append (st .InlineStruct , dep )
423- } else {
424- st .SubStruct = append (st .SubStruct , dep )
440+ for _ , dep := range ti .Deps {
441+ if err := p .referCodes (ctx , & dep , p .opts .ReferCodeDepth ); err != nil {
442+ fmt .Fprintf (os .Stderr , "failed to get refer code for %s: %v\n " , dep , err )
443+ }
444+ if inlined {
445+ st .InlineStruct = InsertDependency (st .InlineStruct , NewDependency (dep , ctx .FileLine (typ )))
446+ } else {
447+ st .SubStruct = InsertDependency (st .SubStruct , NewDependency (dep , ctx .FileLine (typ )))
448+ }
425449 }
426450}
427451
428- var compositeTypePrefixs = []string {"[]" , "map[" , "chan " , "<-chan" , "chan<-" , "func(" }
429-
430452// get type id and tells if it is std or builtin
431- func (ctx * fileContext ) getIdFromType (typ types.Type ) (x Identity , isPointer bool , isStrOrBuiltin bool ) {
432- if tobj , isPointer := getNamedType (typ ); tobj != nil {
433- if isGoBuiltins (tobj .Name ()) {
434- return Identity {Name : tobj .Name ()}, isPointer , true
435- }
436- name := tobj .Name ()
437- // NOTICE: filter composite type (map[] slice func chan ...)
438- // TODO: support extract sub named type
439- for _ , prefix := range compositeTypePrefixs {
440- if strings .HasPrefix (name , prefix ) {
441- return Identity {Name : name }, isPointer , true
453+ func (ctx * fileContext ) getTypeinfo (typ types.Type ) (ti typeInfo ) {
454+ tobjs , isPointer := getNamedTypes (typ )
455+ ti .IsPointer = isPointer
456+ if len (tobjs ) > 0 {
457+ tobj := tobjs [0 ]
458+ if tp := tobj .Pkg (); tp != nil {
459+ mod , err := ctx .GetMod (tp .Path ())
460+ if err == errSysImport {
461+ ti .Id = Identity {"" , tp .Path (), tobj .Name ()}
462+ ti .IsStdOrBuiltin = true
463+ } else if err != nil || mod == "" {
464+ // unloaded type, mark it
465+ ti .Id = Identity {"" , tp .Path (), tobj .Name ()}
466+ ti .IsStdOrBuiltin = false
467+ } else {
468+ ti .Id = NewIdentity (mod , tp .Path (), tobj .Name ())
469+ ti .IsStdOrBuiltin = false
442470 }
443- }
444- // get mod and pkg from tobj.Pkg()
445- tp := tobj .Pkg ()
446- if tp == nil {
447- return NewIdentity (ctx .module .Name , ctx .pkgPath , name ), isPointer , false
448- }
449- mod , err := ctx .GetMod (tp .Path ())
450- if err == errSysImport {
451- return Identity {Name : name , PkgPath : tp .Path ()}, isPointer , true
452- } else if err != nil {
453- return Identity {Name : name }, isPointer , false
454- }
455- return NewIdentity (mod , tp .Path (), tobj .Name ()), isPointer , false
456- } else {
457- typStr := typ .String ()
458- isPointer := strings .HasPrefix (typStr , "*" )
459- typStr = strings .TrimPrefix (typStr , "*" )
460- if isGoBuiltins (typStr ) {
461- return Identity {Name : typStr }, isPointer , true
462- }
463- for _ , prefix := range compositeTypePrefixs {
464- if strings .HasPrefix (typStr , prefix ) {
465- return Identity {Name : typStr }, isPointer , true
471+ } else {
472+ if isGoBuiltins (tobj .Name ()) {
473+ ti .Id = Identity {Name : tobj .Name ()}
474+ ti .IsStdOrBuiltin = true
475+ } else {
476+ // unloaded type, mark it
477+ ti .Id = Identity {"" , ctx .pkgPath , tobj .Name ()}
478+ ti .IsStdOrBuiltin = false
466479 }
467480 }
468- if idx := strings .LastIndex (typStr , "." ); idx > 0 {
469- pkg := typStr [:idx ]
470- if isSysPkg (pkg ) {
471- return Identity {Name : typStr [idx + 1 :], PkgPath : pkg }, isPointer , true
481+ // NOTICE: only extract Named type here
482+ for i := 1 ; i < len (tobjs ); i ++ {
483+ tobj := tobjs [i ]
484+ if isGoBuiltins (tobj .Name ()) {
485+ continue
472486 }
473- // FIXME: some types (ex: return type of a func-calling) cannot be found go mod here.
474- // Ignore empty mod for now.
475- mod , _ := ctx .GetMod (pkg )
476- return NewIdentity (mod , pkg , typStr [idx + 1 :]), isPointer , false
477- } else {
478- return NewIdentity (ctx .module .Name , ctx .pkgPath , typStr ), isPointer , false
487+ // get mod and pkg from tobj.Pkg()
488+ tp := tobj .Pkg ()
489+ if tp == nil {
490+ continue
491+ }
492+ mod , err := ctx .GetMod (tp .Path ())
493+ if err != nil || mod == "" {
494+ continue
495+ }
496+ ti .Deps = append (ti .Deps , NewIdentity (mod , tp .Path (), tobj .Name ()))
479497 }
498+ } else {
499+ ti .Id = Identity {"" , "" , typ .String ()}
500+ ti .IsStdOrBuiltin = true
480501 }
502+ return
481503}
482504
483505func (ctx * fileContext ) IsSysImport (alias string ) bool {
0 commit comments