@@ -247,27 +247,73 @@ 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 {
255- panic ("cannot find type info for " + string (ctx .GetRawContent (typ )))
262+ // NOTICE: for unloaded type, we only mock the type name
263+ fmt .Fprintf (os .Stderr , "cannot find type info for %s\n " , ctx .GetRawContent (typ ))
264+ return ctx .mockType (typ )
256265 }
257266}
258267
268+ func (ctx * fileContext ) mockType (typ ast.Expr ) typeInfo {
269+ switch ty := typ .(type ) {
270+ case * ast.StarExpr :
271+ ti := ctx .mockType (ty .X )
272+ ti .IsPointer = true
273+ return ti
274+ case * ast.CallExpr :
275+ // try get func type
276+ ti := ctx .mockType (ty .Fun )
277+ ti .IsPointer = false
278+ return ti
279+ case * ast.SelectorExpr :
280+ // try get import path
281+ switch xx := ty .X .(type ) {
282+ case * ast.Ident :
283+ impt , mod , err := ctx .imports .GetImportPath (xx .Name , "" )
284+ if err != nil {
285+ goto fallback
286+ }
287+ return typeInfo {NewIdentity (mod , PkgPath (impt ), ty .Sel .Name ), false , false , nil }
288+ case * ast.SelectorExpr :
289+ // recurse
290+ ti := ctx .mockType (xx )
291+ ti .Id .Name = ty .Sel .Name
292+ ti .IsPointer = false
293+ return ti
294+ }
295+ }
296+
297+ fallback:
298+ return typeInfo {NewIdentity ("UNLOADED" , ctx .pkgPath , string (ctx .GetRawContent (typ ))), false , true , nil }
299+ }
300+
259301func (ctx * fileContext ) collectFields (fields []* ast.Field , m * []Dependency ) {
260302 for _ , fieldDecl := range fields {
261- id , _ , isStdOrBuiltin := ctx .GetTypeId (fieldDecl .Type )
262- if isStdOrBuiltin || id .PkgPath == "" {
263- 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+ })
264315 }
265- * m = append (* m , Dependency {
266- Identity : id ,
267- FileLine : ctx .FileLine (fieldDecl ),
268- })
269316 }
270- return
271317}
272318
273319type importInfo struct {
@@ -379,74 +425,81 @@ func getTypeName(fset *token.FileSet, file []byte, typ ast.Expr) (ret []Identity
379425}
380426
381427func (p * GoParser ) collectTypes (ctx * fileContext , typ ast.Expr , st * Type , inlined bool ) {
382- id , _ , isGoBuiltins := ctx .GetTypeId (typ )
383- dep := NewDependency (id , ctx .FileLine (typ ))
384- if isGoBuiltins || id .PkgPath == "" {
385- return
386- }
387- if err := p .referCodes (ctx , & id , p .opts .ReferCodeDepth ); err != nil {
388- 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+ }
389439 }
390- if inlined {
391- st .InlineStruct = append (st .InlineStruct , dep )
392- } else {
393- 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+ }
394449 }
395450}
396451
397- var compositeTypePrefixs = []string {"[]" , "map[" , "chan " , "<-chan" , "chan<-" , "func(" }
398-
399452// get type id and tells if it is std or builtin
400- func (ctx * fileContext ) getIdFromType (typ types.Type ) (x Identity , isPointer bool , isStrOrBuiltin bool ) {
401- if tobj , isPointer := getNamedType (typ ); tobj != nil {
402- if isGoBuiltins (tobj .Name ()) {
403- return Identity {Name : tobj .Name ()}, isPointer , true
404- }
405- name := tobj .Name ()
406- // NOTICE: filter composite type (map[] slice func chan ...)
407- // TODO: support extract sub named type
408- for _ , prefix := range compositeTypePrefixs {
409- if strings .HasPrefix (name , prefix ) {
410- 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
411470 }
412- }
413- // get mod and pkg from tobj.Pkg()
414- tp := tobj .Pkg ()
415- if tp == nil {
416- return NewIdentity (ctx .module .Name , ctx .pkgPath , name ), isPointer , false
417- }
418- mod , err := ctx .GetMod (tp .Path ())
419- if err == errSysImport {
420- return Identity {Name : name , PkgPath : tp .Path ()}, isPointer , true
421- } else if err != nil {
422- return Identity {Name : name }, isPointer , false
423- }
424- return NewIdentity (mod , tp .Path (), tobj .Name ()), isPointer , false
425- } else {
426- typStr := typ .String ()
427- isPointer := strings .HasPrefix (typStr , "*" )
428- typStr = strings .TrimPrefix (typStr , "*" )
429- if isGoBuiltins (typStr ) {
430- return Identity {Name : typStr }, isPointer , true
431- }
432- for _ , prefix := range compositeTypePrefixs {
433- if strings .HasPrefix (typStr , prefix ) {
434- 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
435479 }
436480 }
437- if idx := strings .LastIndex (typStr , "." ); idx > 0 {
438- pkg := typStr [:idx ]
439- if isSysPkg (pkg ) {
440- 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
441486 }
442- // FIXME: some types (ex: return type of a func-calling) cannot be found go mod here.
443- // Ignore empty mod for now.
444- mod , _ := ctx .GetMod (pkg )
445- return NewIdentity (mod , pkg , typStr [idx + 1 :]), isPointer , false
446- } else {
447- 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 ()))
448497 }
498+ } else {
499+ ti .Id = Identity {"" , "" , typ .String ()}
500+ ti .IsStdOrBuiltin = true
449501 }
502+ return
450503}
451504
452505func (ctx * fileContext ) IsSysImport (alias string ) bool {
0 commit comments