Example #1
0
// 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
}
Example #2
0
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
}
Example #3
0
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
}
Example #4
0
// 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
}
Example #5
0
// 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
}
Example #6
0
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)
	}
}
Example #7
0
// 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
	}
}