func (b *Builder) addVariable(u types.Universe, useName *types.Name, in *tc.Var) *types.Type { name := tcVarNameToName(in.String()) if useName != nil { name = *useName } out := u.Variable(name) out.Kind = types.DeclarationOf out.Underlying = b.walkType(u, nil, in.Type()) return out }
// findTypesIn finalizes the package import and searches through the package // for types. func (b *Builder) findTypesIn(pkgPath string, u *types.Universe) error { pkg, err := b.makePackage(pkgPath) if err != nil { return err } if !b.userRequested[pkgPath] { // Since walkType is recursive, all types that the // packages they asked for depend on will be included. // But we don't need to include all types in all // *packages* they depend on. return nil } for _, f := range b.parsed[pkgPath] { if strings.HasSuffix(f.name, "/doc.go") { tp := u.Package(pkgPath) for i := range f.file.Comments { tp.Comments = append(tp.Comments, splitLines(f.file.Comments[i].Text())...) } if f.file.Doc != nil { tp.DocComments = splitLines(f.file.Doc.Text()) } } } s := pkg.Scope() for _, n := range s.Names() { obj := s.Lookup(n) tn, ok := obj.(*tc.TypeName) if ok { t := b.walkType(*u, nil, tn.Type()) c1 := b.priorCommentLines(obj.Pos(), 1) t.CommentLines = splitLines(c1.Text()) if c1 == nil { t.SecondClosestCommentLines = splitLines(b.priorCommentLines(obj.Pos(), 2).Text()) } else { t.SecondClosestCommentLines = splitLines(b.priorCommentLines(c1.List[0].Slash, 2).Text()) } } tf, ok := obj.(*tc.Func) // We only care about functions, not concrete/abstract methods. if ok && tf.Type() != nil && tf.Type().(*tc.Signature).Recv() == nil { b.addFunction(*u, nil, tf) } tv, ok := obj.(*tc.Var) if ok && !tv.IsField() { b.addVariable(*u, nil, tv) } } for p := range b.importGraph[pkgPath] { u.AddImports(pkgPath, p) } u.Package(pkgPath).Name = pkg.Name() return nil }
// 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 } }
// findTypesIn finalizes the package import and searches through the package // for types. func (b *Builder) findTypesIn(pkgPath importPathString, u *types.Universe) error { glog.V(5).Infof("findTypesIn %s", pkgPath) pkg := b.typeCheckedPackages[pkgPath] if pkg == nil { return fmt.Errorf("findTypesIn(%s): package is not known", pkgPath) } if !b.userRequested[pkgPath] { // Since walkType is recursive, all types that the // packages they asked for depend on will be included. // But we don't need to include all types in all // *packages* they depend on. glog.V(5).Infof("findTypesIn %s: package is not user requested", pkgPath) return nil } // We're keeping this package. This call will create the record. u.Package(string(pkgPath)).Name = pkg.Name() u.Package(string(pkgPath)).Path = pkg.Path() u.Package(string(pkgPath)).SourcePath = b.absPaths[pkgPath] for _, f := range b.parsed[pkgPath] { if strings.HasSuffix(f.name, "/doc.go") { tp := u.Package(string(pkgPath)) for i := range f.file.Comments { tp.Comments = append(tp.Comments, splitLines(f.file.Comments[i].Text())...) } if f.file.Doc != nil { tp.DocComments = splitLines(f.file.Doc.Text()) } } } s := pkg.Scope() for _, n := range s.Names() { obj := s.Lookup(n) tn, ok := obj.(*tc.TypeName) if ok { t := b.walkType(*u, nil, tn.Type()) c1 := b.priorCommentLines(obj.Pos(), 1) // c1.Text() is safe if c1 is nil t.CommentLines = splitLines(c1.Text()) if c1 == nil { t.SecondClosestCommentLines = splitLines(b.priorCommentLines(obj.Pos(), 2).Text()) } else { t.SecondClosestCommentLines = splitLines(b.priorCommentLines(c1.List[0].Slash, 2).Text()) } } tf, ok := obj.(*tc.Func) // We only care about functions, not concrete/abstract methods. if ok && tf.Type() != nil && tf.Type().(*tc.Signature).Recv() == nil { t := b.addFunction(*u, nil, tf) c1 := b.priorCommentLines(obj.Pos(), 1) // c1.Text() is safe if c1 is nil t.CommentLines = splitLines(c1.Text()) if c1 == nil { t.SecondClosestCommentLines = splitLines(b.priorCommentLines(obj.Pos(), 2).Text()) } else { t.SecondClosestCommentLines = splitLines(b.priorCommentLines(c1.List[0].Slash, 2).Text()) } } tv, ok := obj.(*tc.Var) if ok && !tv.IsField() { b.addVariable(*u, nil, tv) } } for p := range b.importGraph[pkgPath] { u.AddImports(string(pkgPath), p) } return nil }