diff --git a/cmd/libs/go2idl/client-gen/generators/generator-for-group.go b/cmd/libs/go2idl/client-gen/generators/generator-for-group.go index 20aea8303d209..c446b84fd67a0 100644 --- a/cmd/libs/go2idl/client-gen/generators/generator-for-group.go +++ b/cmd/libs/go2idl/client-gen/generators/generator-for-group.go @@ -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) diff --git a/cmd/libs/go2idl/client-gen/generators/generator-for-type.go b/cmd/libs/go2idl/client-gen/generators/generator-for-type.go index 66d77265b8ce1..c5519b9e26dae 100644 --- a/cmd/libs/go2idl/client-gen/generators/generator-for-type.go +++ b/cmd/libs/go2idl/client-gen/generators/generator-for-type.go @@ -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) diff --git a/cmd/libs/go2idl/namer/namer_test.go b/cmd/libs/go2idl/namer/namer_test.go index 5e7ce3bf66734..a8270164c61bb 100644 --- a/cmd/libs/go2idl/namer/namer_test.go +++ b/cmd/libs/go2idl/namer/namer_test.go @@ -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) diff --git a/cmd/libs/go2idl/namer/order.go b/cmd/libs/go2idl/namer/order.go index 24aa6c2494cef..7b4d231670870 100644 --- a/cmd/libs/go2idl/namer/order.go +++ b/cmd/libs/go2idl/namer/order.go @@ -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 diff --git a/cmd/libs/go2idl/parser/parse.go b/cmd/libs/go2idl/parser/parse.go index dfac95b2b5939..0cc02d6f32642 100644 --- a/cmd/libs/go2idl/parser/parse.go +++ b/cmd/libs/go2idl/parser/parse.go @@ -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 } diff --git a/cmd/libs/go2idl/parser/parse_test.go b/cmd/libs/go2idl/parser/parse_test.go index 4858edf1c7a17..4161d87b85bec 100644 --- a/cmd/libs/go2idl/parser/parse_test.go +++ b/cmd/libs/go2idl/parser/parse_test.go @@ -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) } diff --git a/cmd/libs/go2idl/types/types.go b/cmd/libs/go2idl/types/types.go index 08a318b9691b4..e2420c1027d2d 100644 --- a/cmd/libs/go2idl/types/types.go +++ b/cmd/libs/go2idl/types/types.go @@ -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. diff --git a/cmd/libs/go2idl/types/types_test.go b/cmd/libs/go2idl/types/types_test.go index 4a7e08b499ec3..9ed83aa49f244 100644 --- a/cmd/libs/go2idl/types/types_test.go +++ b/cmd/libs/go2idl/types/types_test.go @@ -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.") }