// FindTypes finalizes the package imports, and searches through all the // packages for types. func (b *Builder) FindTypes() (types.Universe, error) { if err := b.makePackages(); err != nil { return nil, err } u := types.Universe{} for pkgName, pkg := range b.pkgs { if !b.userRequested[pkgName] { // 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. continue } s := pkg.Scope() for _, n := range s.Names() { obj := s.Lookup(n) tn, ok := obj.(*tc.TypeName) if !ok { continue } t := b.walkType(u, nil, tn.Type()) t.CommentLines = b.priorCommentLines(obj.Pos()) } for p := range b.importGraph[pkgName] { u.AddImports(pkgName, p) } } return u, nil }
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 }
func (b *Builder) addFunc(u types.Universe, useName *types.Name, in *tc.Func) *types.Type { name := tcFuncNameToName(in.String()) if useName != nil { name = *useName } out := u.Get(name) out.Kind = types.Func out.Signature = b.convertSignature(u, in.Type().(*tc.Signature)) return out }
// FindTypes finalizes the package imports, and searches through all the // packages for types. func (b *Builder) FindTypes() (types.Universe, error) { if err := b.makePackages(); err != nil { return nil, err } u := types.Universe{} for pkgPath, pkg := range b.pkgs { 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. continue } 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 = c1.Text() if c1 == nil { t.SecondClosestCommentLines = b.priorCommentLines(obj.Pos(), 2).Text() } else { t.SecondClosestCommentLines = 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 u, nil }
// 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 }
func TestNameStrategy(t *testing.T) { u := types.Universe{} // Add some types. base := u.Type(types.Name{Package: "foo/bar", Name: "Baz"}) base.Kind = types.Struct tmp := u.Type(types.Name{Package: "", Name: "[]bar.Baz"}) tmp.Kind = types.Slice tmp.Elem = base tmp = u.Type(types.Name{Package: "", Name: "map[string]bar.Baz"}) tmp.Kind = types.Map tmp.Key = types.String tmp.Elem = base tmp = u.Type(types.Name{Package: "foo/other", Name: "Baz"}) tmp.Kind = types.Struct tmp.Members = []types.Member{{ Embedded: true, Type: base, }} u.Type(types.Name{Package: "", Name: "string"}) o := Orderer{NewPublicNamer(0)} order := o.OrderUniverse(u) orderedNames := make([]string, len(order)) for i, t := range order { orderedNames[i] = o.Name(t) } expect := []string{"Baz", "Baz", "MapStringToBaz", "SliceBaz", "String"} if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { t.Errorf("Wanted %#v, got %#v", e, a) } o = Orderer{NewRawNamer("my/package", nil)} order = o.OrderUniverse(u) orderedNames = make([]string, len(order)) for i, t := range order { orderedNames[i] = o.Name(t) } expect = []string{"[]bar.Baz", "bar.Baz", "map[string]bar.Baz", "other.Baz", "string"} if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { t.Errorf("Wanted %#v, got %#v", e, a) } o = Orderer{NewRawNamer("foo/bar", nil)} order = o.OrderUniverse(u) orderedNames = make([]string, len(order)) for i, t := range order { orderedNames[i] = o.Name(t) } expect = []string{"Baz", "[]Baz", "map[string]Baz", "other.Baz", "string"} if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { t.Errorf("Wanted %#v, got %#v", e, a) } o = Orderer{NewPublicNamer(1)} order = o.OrderUniverse(u) orderedNames = make([]string, len(order)) for i, t := range order { orderedNames[i] = o.Name(t) } expect = []string{"BarBaz", "MapStringToBarBaz", "OtherBaz", "SliceBarBaz", "String"} if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { t.Errorf("Wanted %#v, got %#v", e, a) } }
// 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: 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++ { out.Methods = append(out.Methods, b.walkType(u, nil, t.Method(i).Type())) } return out case *tc.Named: switch t.Underlying().(type) { case *tc.Named, *tc.Basic: 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++ { out.Methods = append(out.Methods, 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 fmt.Printf("Making unsupported type entry %q for: %#v\n", out, t) return out } }