// walkType adds the type, and any necessary child types. func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *types.Type { // Most of the cases are underlying types of the named type. name := tcNameToName(in.String()) if useName != nil { name = *useName } switch t := in.(type) { case *tc.Struct: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Struct for i := 0; i < t.NumFields(); i++ { f := t.Field(i) m := types.Member{ Name: f.Name(), Embedded: f.Anonymous(), Tags: t.Tag(i), Type: b.walkType(u, nil, f.Type()), CommentLines: splitLines(b.priorCommentLines(f.Pos(), 1).Text()), } out.Members = append(out.Members, m) } return out case *tc.Map: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Map out.Elem = b.walkType(u, nil, t.Elem()) out.Key = b.walkType(u, nil, t.Key()) return out case *tc.Pointer: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Pointer out.Elem = b.walkType(u, nil, t.Elem()) return out case *tc.Slice: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Slice out.Elem = b.walkType(u, nil, t.Elem()) return out case *tc.Array: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Array out.Elem = b.walkType(u, nil, t.Elem()) // TODO: need to store array length, otherwise raw type name // cannot be properly written. return out case *tc.Chan: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Chan out.Elem = b.walkType(u, nil, t.Elem()) // TODO: need to store direction, otherwise raw type name // cannot be properly written. return out case *tc.Basic: out := u.Type(types.Name{ Package: "", Name: t.Name(), }) if out.Kind != types.Unknown { return out } out.Kind = types.Unsupported return out case *tc.Signature: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Func out.Signature = b.convertSignature(u, t) return out case *tc.Interface: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Interface t.Complete() for i := 0; i < t.NumMethods(); i++ { if out.Methods == nil { out.Methods = map[string]*types.Type{} } out.Methods[t.Method(i).Name()] = b.walkType(u, nil, t.Method(i).Type()) } return out case *tc.Named: switch t.Underlying().(type) { case *tc.Named, *tc.Basic, *tc.Map, *tc.Slice: name := tcNameToName(t.String()) out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Alias out.Underlying = b.walkType(u, nil, t.Underlying()) return out default: // tc package makes everything "named" with an // underlying anonymous type--we remove that annoying // "feature" for users. This flattens those types // together. name := tcNameToName(t.String()) if out := u.Type(name); out.Kind != types.Unknown { return out // short circuit if we've already made this. } out := b.walkType(u, &name, t.Underlying()) if len(out.Methods) == 0 { // If the underlying type didn't already add // methods, add them. (Interface types will // have already added methods.) for i := 0; i < t.NumMethods(); i++ { if out.Methods == nil { out.Methods = map[string]*types.Type{} } out.Methods[t.Method(i).Name()] = b.walkType(u, nil, t.Method(i).Type()) } } return out } default: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Unsupported glog.Warningf("Making unsupported type entry %q for: %#v\n", out, t) return out } }