Skip to content

Commit 56d8293

Browse files
committed
opt: support collect deps when get type id
1 parent ffa66d8 commit 56d8293

File tree

4 files changed

+184
-106
lines changed

4 files changed

+184
-106
lines changed

lang/golang/parser/ctx.go

Lines changed: 98 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -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

286297
fallback:
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

290301
func (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

304319
type importInfo struct {
@@ -410,74 +425,81 @@ func getTypeName(fset *token.FileSet, file []byte, typ ast.Expr) (ret []Identity
410425
}
411426

412427
func (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

483505
func (ctx *fileContext) IsSysImport(alias string) bool {

lang/golang/parser/file.go

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,19 @@ func (p *GoParser) parseVar(ctx *fileContext, vspec *ast.ValueSpec, isConst bool
101101
v := p.newVar(ctx.module.Name, ctx.pkgPath, name.Name, isConst)
102102
v.FileLine = ctx.FileLine(vspec)
103103
if vspec.Type != nil {
104-
id, isPointer, _ := ctx.GetTypeId(vspec.Type)
105-
v.Type = &id
106-
v.IsPointer = isPointer
104+
ti := ctx.GetTypeInfo(vspec.Type)
105+
v.Type = &ti.Id
106+
v.IsPointer = ti.IsPointer
107+
for _, dep := range ti.Deps {
108+
v.Dependencies = InsertDependency(v.Dependencies, NewDependency(dep, ctx.FileLine(vspec.Type)))
109+
}
107110
} else if val != nil && !isConst {
108-
id, isPointer, _ := ctx.GetTypeId(*val)
109-
v.Type = &id
110-
v.IsPointer = isPointer
111+
ti := ctx.GetTypeInfo(*val)
112+
v.Type = &ti.Id
113+
v.IsPointer = ti.IsPointer
114+
for _, dep := range ti.Deps {
115+
v.Dependencies = InsertDependency(v.Dependencies, NewDependency(dep, ctx.FileLine(*val)))
116+
}
111117
} else {
112118
v.Type = typ
113119
}
@@ -277,19 +283,19 @@ func (p *GoParser) parseSelector(ctx *fileContext, expr *ast.SelectorExpr, infos
277283
}
278284
// callName := string(ctx.GetRawContent(expr))
279285
// get receiver type name
280-
var rname string
281-
rev, _ := getNamedType(sel.Recv())
282-
if rev == nil {
283-
rname = extractName(sel.Recv().String())
284-
} else {
285-
rname = rev.Name()
286-
}
287-
id := NewIdentity(mod, pkg, rname+"."+expr.Sel.Name)
288-
dep := NewDependency(id, ctx.FileLine(expr.Sel))
289-
if err := p.referCodes(ctx, &id, p.opts.ReferCodeDepth); err != nil {
290-
fmt.Fprintf(os.Stderr, "failed to get refer code for %s: %v\n", id.Name, err)
286+
// var rname string
287+
rev := ctx.getTypeinfo(sel.Recv())
288+
// if rev == nil {
289+
// rname = extractName(sel.Recv().String())
290+
// } else {
291+
if !rev.IsStdOrBuiltin && rev.Id.ModPath != "" {
292+
id := NewIdentity(mod, pkg, rev.Id.Name+"."+expr.Sel.Name)
293+
dep := NewDependency(id, ctx.FileLine(expr.Sel))
294+
if err := p.referCodes(ctx, &id, p.opts.ReferCodeDepth); err != nil {
295+
fmt.Fprintf(os.Stderr, "failed to get refer code for %s: %v\n", id.Name, err)
296+
}
297+
*infos.methodCalls = InsertDependency(*infos.methodCalls, dep)
291298
}
292-
*infos.methodCalls = InsertDependency(*infos.methodCalls, dep)
293299
return false
294300
}
295301

@@ -308,14 +314,14 @@ func (p *GoParser) parseFunc(ctx *fileContext, funcDecl *ast.FuncDecl) (*Functio
308314
isMethod := funcDecl.Recv != nil
309315
if isMethod {
310316
// TODO: reserve the pointer message?
311-
id, isPointer, _ := ctx.GetTypeId(funcDecl.Recv.List[0].Type)
317+
ti := ctx.GetTypeInfo(funcDecl.Recv.List[0].Type)
312318
// name := "self"
313319
// if len(funcDecl.Recv.List[0].Names) > 0 {
314320
// name = funcDecl.Recv.List[0].Names[0].Name
315321
// }
316322
receiver = &Receiver{
317-
Type: id,
318-
IsPointer: isPointer,
323+
Type: ti.Id,
324+
IsPointer: ti.IsPointer,
319325
// Name: name,
320326
}
321327
}

lang/golang/parser/utils.go

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -183,15 +183,64 @@ func getTypeKind(n ast.Expr) TypeKind {
183183
}
184184
}
185185

186-
func getNamedType(typ types.Type) (ty types.Object, isPointer bool) {
187-
if pt, ok := typ.(*types.Pointer); ok {
188-
typ = pt.Elem()
186+
func getNamedTypes(typ types.Type) (tys []types.Object, isPointer bool) {
187+
switch t := typ.(type) {
188+
case *types.Pointer:
189189
isPointer = true
190+
typs, _ := getNamedTypes(t.Elem())
191+
tys = append(tys, typs...)
192+
case *types.Slice:
193+
typs, _ := getNamedTypes(t.Elem())
194+
tys = append(tys, typs...)
195+
case *types.Array:
196+
typs, _ := getNamedTypes(t.Elem())
197+
tys = append(tys, typs...)
198+
case *types.Chan:
199+
typs, _ := getNamedTypes(t.Elem())
200+
tys = append(tys, typs...)
201+
case *types.Tuple:
202+
for i := 0; i < t.Len(); i++ {
203+
typs, _ := getNamedTypes(t.At(i).Type())
204+
tys = append(tys, typs...)
205+
}
206+
case *types.Map:
207+
typs2, _ := getNamedTypes(t.Elem())
208+
typs1, _ := getNamedTypes(t.Key())
209+
tys = append(tys, typs1...)
210+
tys = append(tys, typs2...)
211+
case *types.Named:
212+
tys = append(tys, t.Obj())
213+
case *types.Struct:
214+
for i := 0; i < t.NumFields(); i++ {
215+
typs, _ := getNamedTypes(t.Field(i).Type())
216+
tys = append(tys, typs...)
217+
}
218+
case *types.Interface:
219+
for i := 0; i < t.NumEmbeddeds(); i++ {
220+
typs, _ := getNamedTypes(t.EmbeddedType(i))
221+
tys = append(tys, typs...)
222+
}
223+
for i := 0; i < t.NumExplicitMethods(); i++ {
224+
typs, _ := getNamedTypes(t.ExplicitMethod(i).Type())
225+
tys = append(tys, typs...)
226+
}
227+
case *types.TypeParam:
228+
typs, _ := getNamedTypes(t.Constraint())
229+
tys = append(tys, typs...)
230+
case *types.Alias:
231+
typs, _ := getNamedTypes(t.Underlying())
232+
tys = append(tys, typs...)
233+
case *types.Signature:
234+
for i := 0; i < t.Params().Len(); i++ {
235+
typs, _ := getNamedTypes(t.Params().At(i).Type())
236+
tys = append(tys, typs...)
237+
}
238+
for i := 0; i < t.Results().Len(); i++ {
239+
typs, _ := getNamedTypes(t.Results().At(i).Type())
240+
tys = append(tys, typs...)
241+
}
190242
}
191-
if name, ok := typ.(*types.Named); ok {
192-
return name.Obj(), isPointer
193-
}
194-
return nil, isPointer
243+
return
195244
}
196245

197246
func extractName(typ string) string {

lang/uniast/ast.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -544,8 +544,9 @@ type Var struct {
544544
IsPointer bool // if its Type is a pointer type
545545
Identity
546546
FileLine
547-
Type *Identity `json:",omitempty"`
548-
Content string
547+
Type *Identity `json:",omitempty"`
548+
Content string
549+
Dependencies []Dependency `json:",omitempty"`
549550

550551
CompressData *string `json:"compress_data,omitempty"`
551552
}

0 commit comments

Comments
 (0)