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": g.group,
"Group": namer.IC(g.group), "Group": namer.IC(g.group),
"types": g.types, "types": g.types,
"Config": c.Universe.Get(types.Name{Package: pkgUnversioned, Name: "Config"}), "Config": c.Universe.Type(types.Name{Package: pkgUnversioned, Name: "Config"}),
"DefaultKubernetesUserAgent": c.Universe.Get(types.Name{Package: pkgUnversioned, Name: "DefaultKubernetesUserAgent"}), "DefaultKubernetesUserAgent": c.Universe.Function(types.Name{Package: pkgUnversioned, Name: "DefaultKubernetesUserAgent"}),
"RESTClient": c.Universe.Get(types.Name{Package: pkgUnversioned, Name: "RESTClient"}), "RESTClient": c.Universe.Type(types.Name{Package: pkgUnversioned, Name: "RESTClient"}),
"RESTClientFor": c.Universe.Get(types.Name{Package: pkgUnversioned, Name: "RESTClientFor"}), "RESTClientFor": c.Universe.Function(types.Name{Package: pkgUnversioned, Name: "RESTClientFor"}),
"latestGroup": c.Universe.Get(types.Name{Package: pkgLatest, Name: "Group"}), "latestGroup": c.Universe.Variable(types.Name{Package: pkgLatest, Name: "Group"}),
"GroupOrDie": c.Universe.Get(types.Name{Package: pkgLatest, Name: "GroupOrDie"}), "GroupOrDie": c.Universe.Variable(types.Name{Package: pkgLatest, Name: "GroupOrDie"}),
} }
sw.Do(groupInterfaceTemplate, m) sw.Do(groupInterfaceTemplate, m)
sw.Do(groupClientTemplate, 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, "type": t,
"package": pkg, "package": pkg,
"Package": namer.IC(pkg), "Package": namer.IC(pkg),
"watchInterface": c.Universe.Get(types.Name{Package: "k8s.io/kubernetes/pkg/watch", Name: "Interface"}), "watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/watch", Name: "Interface"}),
"apiDeleteOptions": c.Universe.Get(types.Name{Package: "k8s.io/kubernetes/pkg/api", Name: "DeleteOptions"}), "apiDeleteOptions": c.Universe.Type(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"}), "unvListOptions": c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/api/unversioned", Name: "ListOptions"}),
} }
sw.Do(namespacerTemplate, m) sw.Do(namespacerTemplate, m)
sw.Do(interfaceTemplate, m) sw.Do(interfaceTemplate, m)

View File

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

View File

@ -37,6 +37,12 @@ func (o *Orderer) Order(u types.Universe) []*types.Type {
for _, t := range p.Types { for _, t := range p.Types {
list.types = append(list.types, t) 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) sort.Sort(list)
return list.types return list.types

View File

@ -303,8 +303,13 @@ func (b *Builder) FindTypes() (types.Universe, error) {
t.CommentLines = b.priorCommentLines(obj.Pos()) t.CommentLines = b.priorCommentLines(obj.Pos())
} }
tf, ok := obj.(*tc.Func) tf, ok := obj.(*tc.Func)
if ok { // We only care about functions, not concrete/abstract methods.
b.addFunc(u, nil, tf) 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] { for p := range b.importGraph[pkgName] {
@ -330,6 +335,13 @@ func tcFuncNameToName(in string) types.Name {
return tcNameToName(nameParts[0]) 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 { func tcNameToName(in string) types.Name {
// Detect anonymous type names. (These may have '.' characters because // Detect anonymous type names. (These may have '.' characters because
// embedded types may have packages, so we detect them specially.) // 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) { switch t := in.(type) {
case *tc.Struct: case *tc.Struct:
out := u.Get(name) out := u.Type(name)
if out.Kind != types.Unknown { if out.Kind != types.Unknown {
return out return out
} }
@ -395,7 +407,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
} }
return out return out
case *tc.Map: case *tc.Map:
out := u.Get(name) out := u.Type(name)
if out.Kind != types.Unknown { if out.Kind != types.Unknown {
return out 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()) out.Key = b.walkType(u, nil, t.Key())
return out return out
case *tc.Pointer: case *tc.Pointer:
out := u.Get(name) out := u.Type(name)
if out.Kind != types.Unknown { if out.Kind != types.Unknown {
return out 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()) out.Elem = b.walkType(u, nil, t.Elem())
return out return out
case *tc.Slice: case *tc.Slice:
out := u.Get(name) out := u.Type(name)
if out.Kind != types.Unknown { if out.Kind != types.Unknown {
return out 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()) out.Elem = b.walkType(u, nil, t.Elem())
return out return out
case *tc.Array: case *tc.Array:
out := u.Get(name) out := u.Type(name)
if out.Kind != types.Unknown { if out.Kind != types.Unknown {
return out return out
} }
@ -430,7 +442,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
// cannot be properly written. // cannot be properly written.
return out return out
case *tc.Chan: case *tc.Chan:
out := u.Get(name) out := u.Type(name)
if out.Kind != types.Unknown { if out.Kind != types.Unknown {
return out return out
} }
@ -440,7 +452,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
// cannot be properly written. // cannot be properly written.
return out return out
case *tc.Basic: case *tc.Basic:
out := u.Get(types.Name{ out := u.Type(types.Name{
Package: "", Package: "",
Name: t.Name(), 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 out.Kind = types.Unsupported
return out return out
case *tc.Signature: case *tc.Signature:
out := u.Get(name) out := u.Type(name)
if out.Kind != types.Unknown { if out.Kind != types.Unknown {
return out 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) out.Signature = b.convertSignature(u, t)
return out return out
case *tc.Interface: case *tc.Interface:
out := u.Get(name) out := u.Type(name)
if out.Kind != types.Unknown { if out.Kind != types.Unknown {
return out return out
} }
@ -472,7 +484,7 @@ func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *t
switch t.Underlying().(type) { switch t.Underlying().(type) {
case *tc.Named, *tc.Basic: case *tc.Named, *tc.Basic:
name := tcNameToName(t.String()) name := tcNameToName(t.String())
out := u.Get(name) out := u.Type(name)
if out.Kind != types.Unknown { if out.Kind != types.Unknown {
return out 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 // "feature" for users. This flattens those types
// together. // together.
name := tcNameToName(t.String()) 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. return out // short circuit if we've already made this.
} }
out := b.walkType(u, &name, t.Underlying()) 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 return out
} }
default: default:
out := u.Get(name) out := u.Type(name)
if out.Kind != types.Unknown { if out.Kind != types.Unknown {
return out 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()) name := tcFuncNameToName(in.String())
if useName != nil { if useName != nil {
name = *useName name = *useName
} }
out := u.Get(name) out := u.Function(name)
out.Kind = types.Func out.Kind = types.DeclarationOf
out.Signature = b.convertSignature(u, in.Type().(*tc.Signature)) 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 return out
} }

View File

@ -73,6 +73,11 @@ type Object struct {
func AFunc(obj1 common.Object, obj2 Object) Frobber { func AFunc(obj1 common.Object, obj2 Object) Frobber {
} }
var AVar Frobber
var (
AnotherVar = Frobber{}
)
`, `,
"base/common/proto/common.go": ` "base/common/proto/common.go": `
package common package common
@ -91,16 +96,21 @@ package o
} }
{{end}} {{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}} {{end}}
{{range $t := .}}{{if eq $t.Kind "Struct"}}{{template "Struct" $t}}{{end}}{{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 = ` var expect = `
package o package o
type CommonObject interface { type CommonObject interface {
ID() Int64 ID() Int64
SetID(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") 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 { if e, a := expect, buf.String(); e != a {
t.Errorf("Wanted, got:\n%v\n-----\n%v\n", 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") { if p := u.Package("base/foo/proto"); !p.HasImport("base/common/proto") {
t.Errorf("Unexpected lack of import line: %#s", p.Imports) 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)) _, u, o := construct(t, structTest, namer.NewPublicNamer(0))
t.Logf("%#v", o) 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 { if blahT == nil {
t.Fatal("type not found") t.Fatal("type not found")
} }
@ -330,7 +344,7 @@ type Interface interface{Method(a, b string) (c, d string)}
for _, item := range assertions { for _, item := range assertions {
n := types.Name{Package: item.Package, Name: item.Name} n := types.Name{Package: item.Package, Name: item.Name}
thisType := u.Get(n) thisType := u.Type(n)
if thisType == nil { if thisType == nil {
t.Errorf("type %s not found", n) t.Errorf("type %s not found", n)
continue continue
@ -344,11 +358,11 @@ type Interface interface{Method(a, b string) (c, d string)}
} }
// Also do some one-off checks // 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 { if e, a := 1, len(gtest.Methods); e != a {
t.Errorf("expected %v but found %v methods: %#v", e, a, gtest) 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 { if e, a := 1, len(iface.Methods); e != a {
t.Errorf("expected %v but found %v methods: %#v", e, a, iface) 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 // The remaining types are included for completeness, but are not well
// supported. // supported.
Array Kind = "Array" // Array is just like slice, but has a fixed length. Array Kind = "Array" // Array is just like slice, but has a fixed length.
Chan Kind = "Chan" Chan Kind = "Chan"
Func Kind = "Func" Func Kind = "Func"
Unknown Kind = ""
Unsupported Kind = "Unsupported" // 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. // Package holds package-level information.
@ -84,6 +90,14 @@ type Package struct {
// package name). // package name).
Types map[string]*Type 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) // Packages imported by this package, indexed by (canonicalized)
// package path. // package path.
Imports map[string]*Package Imports map[string]*Package
@ -96,7 +110,7 @@ func (p *Package) Has(name string) bool {
} }
// Get (or add) the given type // 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 { if t, ok := p.Types[typeName]; ok {
return t return t
} }
@ -112,6 +126,32 @@ func (p *Package) Get(typeName string) *Type {
return t 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 // HasImport returns true if p imports packageName. Package names include the
// package directory. // package directory.
func (p *Package) HasImport(packageName string) bool { 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 // 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) // the map. If a non-existing type is requested, u will create (a marker for)
// it. // it.
func (u Universe) Get(n Name) *Type { func (u Universe) Type(n Name) *Type {
return u.Package(n.Package).Get(n.Name) 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. // AddImports registers import lines for packageName. May be called multiple times.
@ -146,9 +202,11 @@ func (u Universe) Package(packagePath string) *Package {
return p return p
} }
p := &Package{ p := &Package{
Path: packagePath, Path: packagePath,
Types: map[string]*Type{}, Types: map[string]*Type{},
Imports: map[string]*Package{}, Functions: map[string]*Type{},
Variables: map[string]*Type{},
Imports: map[string]*Package{},
} }
u[packagePath] = p u[packagePath] = p
return p return p
@ -159,6 +217,11 @@ type Type struct {
// There are two general categories of types, those explicitly named // There are two general categories of types, those explicitly named
// and those anonymous. Named ones will have a non-empty package in the // and those anonymous. Named ones will have a non-empty package in the
// name field. // 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 Name Name
// The general kind of this type. // The general kind of this type.
@ -178,6 +241,7 @@ type Type struct {
Key *Type Key *Type
// If Kind == Alias, this is the underlying type. // If Kind == Alias, this is the underlying type.
// If Kind == DeclarationOf, this is the type of the declaration.
Underlying *Type Underlying *Type
// If Kind == Interface, this is the list of all required functions. // 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") { if builtinPkg := u.Package(""); builtinPkg.Has("string") {
t.Errorf("Expected builtin package to not have builtins until they're asked for explicitly. %#v", builtinPkg) 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 { if s != String {
t.Errorf("Expected canonical string type.") t.Errorf("Expected canonical string type.")
} }
@ -40,7 +40,7 @@ func TestGetBuiltin(t *testing.T) {
func TestGetMarker(t *testing.T) { func TestGetMarker(t *testing.T) {
u := Universe{} u := Universe{}
n := Name{Package: "path/to/package", Name: "Foo"} n := Name{Package: "path/to/package", Name: "Foo"}
f := u.Get(n) f := u.Type(n)
if f == nil || f.Name != n { if f == nil || f.Name != n {
t.Errorf("Expected marker type.") t.Errorf("Expected marker type.")
} }