split Package.Types to Types, Variables and Functions;

add DeclarationOf Kind.
This commit is contained in:
Chao Xu 2015-12-01 14:59:25 -08:00
parent 611770778f
commit 0d7d4c04a2
8 changed files with 160 additions and 53 deletions

View File

@ -57,12 +57,12 @@ func (g *genGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer
"group": g.group,
"Group": namer.IC(g.group),
"types": g.types,
"Config": c.Universe.Get(types.Name{Package: pkgUnversioned, Name: "Config"}),
"DefaultKubernetesUserAgent": c.Universe.Get(types.Name{Package: pkgUnversioned, Name: "DefaultKubernetesUserAgent"}),
"RESTClient": c.Universe.Get(types.Name{Package: pkgUnversioned, Name: "RESTClient"}),
"RESTClientFor": c.Universe.Get(types.Name{Package: pkgUnversioned, Name: "RESTClientFor"}),
"latestGroup": c.Universe.Get(types.Name{Package: pkgLatest, Name: "Group"}),
"GroupOrDie": c.Universe.Get(types.Name{Package: pkgLatest, Name: "GroupOrDie"}),
"Config": c.Universe.Type(types.Name{Package: pkgUnversioned, Name: "Config"}),
"DefaultKubernetesUserAgent": c.Universe.Function(types.Name{Package: pkgUnversioned, Name: "DefaultKubernetesUserAgent"}),
"RESTClient": c.Universe.Type(types.Name{Package: pkgUnversioned, Name: "RESTClient"}),
"RESTClientFor": c.Universe.Function(types.Name{Package: pkgUnversioned, Name: "RESTClientFor"}),
"latestGroup": c.Universe.Variable(types.Name{Package: pkgLatest, Name: "Group"}),
"GroupOrDie": c.Universe.Variable(types.Name{Package: pkgLatest, Name: "GroupOrDie"}),
}
sw.Do(groupInterfaceTemplate, m)
sw.Do(groupClientTemplate, m)

View File

@ -54,9 +54,9 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i
"type": t,
"package": pkg,
"Package": namer.IC(pkg),
"watchInterface": c.Universe.Get(types.Name{Package: "k8s.io/kubernetes/pkg/watch", Name: "Interface"}),
"apiDeleteOptions": c.Universe.Get(types.Name{Package: "k8s.io/kubernetes/pkg/api", Name: "DeleteOptions"}),
"unvListOptions": c.Universe.Get(types.Name{Package: "k8s.io/kubernetes/pkg/api/unversioned", Name: "ListOptions"}),
"watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/watch", Name: "Interface"}),
"apiDeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/api", Name: "DeleteOptions"}),
"unvListOptions": c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/api/unversioned", Name: "ListOptions"}),
}
sw.Do(namespacerTemplate, m)
sw.Do(interfaceTemplate, m)

View File

@ -27,26 +27,26 @@ func TestNameStrategy(t *testing.T) {
u := types.Universe{}
// Add some types.
base := u.Get(types.Name{Package: "foo/bar", Name: "Baz"})
base := u.Type(types.Name{Package: "foo/bar", Name: "Baz"})
base.Kind = types.Struct
tmp := u.Get(types.Name{Package: "", Name: "[]bar.Baz"})
tmp := u.Type(types.Name{Package: "", Name: "[]bar.Baz"})
tmp.Kind = types.Slice
tmp.Elem = base
tmp = u.Get(types.Name{Package: "", Name: "map[string]bar.Baz"})
tmp = u.Type(types.Name{Package: "", Name: "map[string]bar.Baz"})
tmp.Kind = types.Map
tmp.Key = types.String
tmp.Elem = base
tmp = u.Get(types.Name{Package: "foo/other", Name: "Baz"})
tmp = u.Type(types.Name{Package: "foo/other", Name: "Baz"})
tmp.Kind = types.Struct
tmp.Members = []types.Member{{
Embedded: true,
Type: base,
}}
u.Get(types.Name{Package: "", Name: "string"})
u.Type(types.Name{Package: "", Name: "string"})
o := Orderer{NewPublicNamer(0)}
order := o.Order(u)

View File

@ -37,6 +37,12 @@ func (o *Orderer) Order(u types.Universe) []*types.Type {
for _, t := range p.Types {
list.types = append(list.types, t)
}
for _, f := range p.Functions {
list.types = append(list.types, f)
}
for _, v := range p.Variables {
list.types = append(list.types, v)
}
}
sort.Sort(list)
return list.types

View File

@ -303,8 +303,13 @@ func (b *Builder) FindTypes() (types.Universe, error) {
t.CommentLines = b.priorCommentLines(obj.Pos())
}
tf, ok := obj.(*tc.Func)
if ok {
b.addFunc(u, nil, tf)
// 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[pkgName] {
@ -330,6 +335,13 @@ func tcFuncNameToName(in string) types.Name {
return tcNameToName(nameParts[0])
}
func tcVarNameToName(in string) types.Name {
nameParts := strings.Split(in, " ")
// nameParts[0] is "var".
// nameParts[2:] is the type of the variable, we ignore it for now.
return tcNameToName(nameParts[1])
}
func tcNameToName(in string) types.Name {
// Detect anonymous type names. (These may have '.' characters because
// embedded types may have packages, so we detect them specially.)
@ -377,7 +389,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
switch t := in.(type) {
case *tc.Struct:
out := u.Get(name)
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
@ -395,7 +407,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
}
return out
case *tc.Map:
out := u.Get(name)
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
@ -404,7 +416,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
out.Key = b.walkType(u, nil, t.Key())
return out
case *tc.Pointer:
out := u.Get(name)
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
@ -412,7 +424,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
out.Elem = b.walkType(u, nil, t.Elem())
return out
case *tc.Slice:
out := u.Get(name)
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
@ -420,7 +432,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
out.Elem = b.walkType(u, nil, t.Elem())
return out
case *tc.Array:
out := u.Get(name)
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
@ -430,7 +442,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
// cannot be properly written.
return out
case *tc.Chan:
out := u.Get(name)
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
@ -440,7 +452,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
// cannot be properly written.
return out
case *tc.Basic:
out := u.Get(types.Name{
out := u.Type(types.Name{
Package: "",
Name: t.Name(),
})
@ -450,7 +462,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
out.Kind = types.Unsupported
return out
case *tc.Signature:
out := u.Get(name)
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
@ -458,7 +470,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
out.Signature = b.convertSignature(u, t)
return out
case *tc.Interface:
out := u.Get(name)
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
@ -472,7 +484,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
switch t.Underlying().(type) {
case *tc.Named, *tc.Basic:
name := tcNameToName(t.String())
out := u.Get(name)
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
@ -485,7 +497,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
// "feature" for users. This flattens those types
// together.
name := tcNameToName(t.String())
if out := u.Get(name); out.Kind != types.Unknown {
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())
@ -500,7 +512,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
return out
}
default:
out := u.Get(name)
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
@ -510,13 +522,24 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
}
}
func (b *Builder) addFunc(u types.Universe, useName *types.Name, in *tc.Func) *types.Type {
func (b *Builder) addFunction(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))
out := u.Function(name)
out.Kind = types.DeclarationOf
out.Underlying = b.walkType(u, nil, in.Type())
return out
}
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
}

View File

@ -73,6 +73,11 @@ type Object struct {
func AFunc(obj1 common.Object, obj2 Object) Frobber {
}
var AVar Frobber
var (
AnotherVar = Frobber{}
)
`,
"base/common/proto/common.go": `
package common
@ -91,16 +96,21 @@ package o
}
{{end}}
{{define "Func"}}{{$s := .Signature}}func {{Raw .}}( {{range $s.Parameters}}{{Raw .}} {{end}}) {{range $s.Results}}{{Raw .}} {{end}}{}
{{define "Func"}}{{$s := .Underlying.Signature}}var {{Name .}} func({{range $index,$elem := $s.Parameters}}{{if $index}}, {{end}}{{Raw $elem}}{{end}}) {{if $s.Results|len |gt 1}}({{end}}{{range $index,$elem := $s.Results}}{{if $index}}, {{end}}{{Raw .}}{{end}}{{if $s.Results|len |gt 1}}){{end}} = {{Raw .}}
{{end}}
{{define "Var"}}{{$t := .Underlying}}var {{Name .}} {{Raw $t}} = {{Raw .}}
{{end}}
{{range $t := .}}{{if eq $t.Kind "Struct"}}{{template "Struct" $t}}{{end}}{{end}}
{{range $t := .}}{{if eq $t.Kind "Func"}}{{template "Func" $t}}{{end}}{{end}}`
{{range $t := .}}{{if eq $t.Kind "DeclarationOf"}}{{if eq $t.Underlying.Kind "Func"}}{{template "Func" $t}}{{end}}{{end}}{{end}}
{{range $t := .}}{{if eq $t.Kind "DeclarationOf"}}{{if ne $t.Underlying.Kind "Func"}}{{template "Var" $t}}{{end}}{{end}}{{end}}`
var expect = `
package o
type CommonObject interface {
ID() Int64
SetID(Int64)
@ -128,7 +138,12 @@ type FooObject interface {
}
func proto.AFunc( proto.Object proto.Object ) proto.Frobber {}
var FooAFunc func(proto.Object, proto.Object) proto.Frobber = proto.AFunc
var FooAVar proto.Frobber = proto.AVar
var FooAnotherVar proto.Frobber = proto.AnotherVar
`
testNamer := namer.NewPublicNamer(1, "proto")
@ -149,7 +164,6 @@ func proto.AFunc( proto.Object proto.Object ) proto.Frobber {}
if e, a := expect, buf.String(); e != a {
t.Errorf("Wanted, got:\n%v\n-----\n%v\n", e, a)
}
if p := u.Package("base/foo/proto"); !p.HasImport("base/common/proto") {
t.Errorf("Unexpected lack of import line: %#s", p.Imports)
}
@ -175,7 +189,7 @@ type Blah struct {
_, u, o := construct(t, structTest, namer.NewPublicNamer(0))
t.Logf("%#v", o)
blahT := u.Get(types.Name{Package: "base/foo/proto", Name: "Blah"})
blahT := u.Type(types.Name{Package: "base/foo/proto", Name: "Blah"})
if blahT == nil {
t.Fatal("type not found")
}
@ -330,7 +344,7 @@ type Interface interface{Method(a, b string) (c, d string)}
for _, item := range assertions {
n := types.Name{Package: item.Package, Name: item.Name}
thisType := u.Get(n)
thisType := u.Type(n)
if thisType == nil {
t.Errorf("type %s not found", n)
continue
@ -344,11 +358,11 @@ type Interface interface{Method(a, b string) (c, d string)}
}
// Also do some one-off checks
gtest := u.Get(types.Name{Package: "g", Name: "Test"})
gtest := u.Type(types.Name{Package: "g", Name: "Test"})
if e, a := 1, len(gtest.Methods); e != a {
t.Errorf("expected %v but found %v methods: %#v", e, a, gtest)
}
iface := u.Get(types.Name{Package: "g", Name: "Interface"})
iface := u.Type(types.Name{Package: "g", Name: "Interface"})
if e, a := 1, len(iface.Methods); e != a {
t.Errorf("expected %v but found %v methods: %#v", e, a, iface)
}

View File

@ -61,11 +61,17 @@ const (
// The remaining types are included for completeness, but are not well
// supported.
Array Kind = "Array" // Array is just like slice, but has a fixed length.
Chan Kind = "Chan"
Func Kind = "Func"
Unknown Kind = ""
Unsupported Kind = "Unsupported"
Array Kind = "Array" // Array is just like slice, but has a fixed length.
Chan Kind = "Chan"
Func Kind = "Func"
// DeclarationOf is different from other Kinds; it indicates that instead of
// representing an actual Type, the type is a declaration of an instance of
// a type. E.g., a top-level function, variable, or constant. See the
// comment for Type.Name for more detail.
DeclarationOf Kind = "DeclarationOf"
Unknown Kind = ""
Unsupported Kind = "Unsupported"
)
// Package holds package-level information.
@ -84,6 +90,14 @@ type Package struct {
// package name).
Types map[string]*Type
// Functions within this package, indexed by their name (*not* including
// package name).
Functions map[string]*Type
// Global variables within this package, indexed by their name (*not* including
// package name).
Variables map[string]*Type
// Packages imported by this package, indexed by (canonicalized)
// package path.
Imports map[string]*Package
@ -96,7 +110,7 @@ func (p *Package) Has(name string) bool {
}
// Get (or add) the given type
func (p *Package) Get(typeName string) *Type {
func (p *Package) Type(typeName string) *Type {
if t, ok := p.Types[typeName]; ok {
return t
}
@ -112,6 +126,32 @@ func (p *Package) Get(typeName string) *Type {
return t
}
// Get (or add) the given function. If a function is added, it's the caller's
// responsibility to finish construction of the function by setting Underlying
// to the correct type.
func (p *Package) Function(funcName string) *Type {
if t, ok := p.Functions[funcName]; ok {
return t
}
t := &Type{Name: Name{Package: p.Path, Name: funcName}}
t.Kind = DeclarationOf
p.Functions[funcName] = t
return t
}
// Get (or add) the given varaible. If a variable is added, it's the caller's
// responsibility to finish construction of the variable by setting Underlying
// to the correct type.
func (p *Package) Variable(varName string) *Type {
if t, ok := p.Variables[varName]; ok {
return t
}
t := &Type{Name: Name{Package: p.Path, Name: varName}}
t.Kind = DeclarationOf
p.Variables[varName] = t
return t
}
// HasImport returns true if p imports packageName. Package names include the
// package directory.
func (p *Package) HasImport(packageName string) bool {
@ -127,8 +167,24 @@ type Universe map[string]*Package
// types will always be found, even if they haven't been explicitly added to
// the map. If a non-existing type is requested, u will create (a marker for)
// it.
func (u Universe) Get(n Name) *Type {
return u.Package(n.Package).Get(n.Name)
func (u Universe) Type(n Name) *Type {
return u.Package(n.Package).Type(n.Name)
}
// Function returns the canonical function for the given fully-qualified name.
// If a non-existing function is requested, u will create (a marker for) it.
// If a marker is created, it's the caller's responsibility to finish
// construction of the function by setting Underlying to the correct type.
func (u Universe) Function(n Name) *Type {
return u.Package(n.Package).Function(n.Name)
}
// Variable returns the canonical variable for the given fully-qualified name.
// If a non-existing variable is requested, u will create (a marker for) it.
// If a marker is created, it's the caller's responsibility to finish
// construction of the variable by setting Underlying to the correct type.
func (u Universe) Variable(n Name) *Type {
return u.Package(n.Package).Variable(n.Name)
}
// AddImports registers import lines for packageName. May be called multiple times.
@ -146,9 +202,11 @@ func (u Universe) Package(packagePath string) *Package {
return p
}
p := &Package{
Path: packagePath,
Types: map[string]*Type{},
Imports: map[string]*Package{},
Path: packagePath,
Types: map[string]*Type{},
Functions: map[string]*Type{},
Variables: map[string]*Type{},
Imports: map[string]*Package{},
}
u[packagePath] = p
return p
@ -159,6 +217,11 @@ type Type struct {
// There are two general categories of types, those explicitly named
// and those anonymous. Named ones will have a non-empty package in the
// name field.
//
// An exception: If Kind == DeclarationOf, then this name is the name of a
// top-level function, variable, or const, and the type can be found in Underlying.
// We do this to allow the naming system to work against these objects, even
// though they aren't strictly speaking types.
Name Name
// The general kind of this type.
@ -178,6 +241,7 @@ type Type struct {
Key *Type
// If Kind == Alias, this is the underlying type.
// If Kind == DeclarationOf, this is the type of the declaration.
Underlying *Type
// If Kind == Interface, this is the list of all required functions.

View File

@ -25,7 +25,7 @@ func TestGetBuiltin(t *testing.T) {
if builtinPkg := u.Package(""); builtinPkg.Has("string") {
t.Errorf("Expected builtin package to not have builtins until they're asked for explicitly. %#v", builtinPkg)
}
s := u.Get(Name{Package: "", Name: "string"})
s := u.Type(Name{Package: "", Name: "string"})
if s != String {
t.Errorf("Expected canonical string type.")
}
@ -40,7 +40,7 @@ func TestGetBuiltin(t *testing.T) {
func TestGetMarker(t *testing.T) {
u := Universe{}
n := Name{Package: "path/to/package", Name: "Foo"}
f := u.Get(n)
f := u.Type(n)
if f == nil || f.Name != n {
t.Errorf("Expected marker type.")
}