blob: aa3b7128e946ab77f2f6befa72a92207dec78324 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001/*
2Copyright 2015 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package types
18
19import "strings"
20
21// Ref makes a reference to the given type. It can only be used for e.g.
22// passing to namers.
23func Ref(packageName, typeName string) *Type {
24 return &Type{Name: Name{
25 Name: typeName,
26 Package: packageName,
27 }}
28}
29
30// A type name may have a package qualifier.
31type Name struct {
32 // Empty if embedded or builtin. This is the package path unless Path is specified.
33 Package string
34 // The type name.
35 Name string
36 // An optional location of the type definition for languages that can have disjoint
37 // packages and paths.
38 Path string
39}
40
41// String returns the name formatted as a string.
42func (n Name) String() string {
43 if n.Package == "" {
44 return n.Name
45 }
46 return n.Package + "." + n.Name
47}
48
49// ParseFullyQualifiedName parses a name like k8s.io/kubernetes/pkg/api.Pod into a Name.
50func ParseFullyQualifiedName(fqn string) Name {
51 cs := strings.Split(fqn, ".")
52 pkg := ""
53 if len(cs) > 1 {
54 pkg = strings.Join(cs[0:len(cs) - 1], ".")
55 }
56 return Name{
57 Name: cs[len(cs) - 1],
58 Package: pkg,
59 }
60}
61
62// The possible classes of types.
63type Kind string
64
65const (
66 // Builtin is a primitive, like bool, string, int.
67 Builtin Kind = "Builtin"
68 Struct Kind = "Struct"
69 Map Kind = "Map"
70 Slice Kind = "Slice"
71 Pointer Kind = "Pointer"
72
73 // Alias is an alias of another type, e.g. in:
74 // type Foo string
75 // type Bar Foo
76 // Bar is an alias of Foo.
77 //
78 // In the real go type system, Foo is a "Named" string; but to simplify
79 // generation, this type system will just say that Foo *is* a builtin.
80 // We then need "Alias" as a way for us to say that Bar *is* a Foo.
81 Alias Kind = "Alias"
82
83 // Interface is any type that could have differing types at run time.
84 Interface Kind = "Interface"
85
86 // The remaining types are included for completeness, but are not well
87 // supported.
88 Array Kind = "Array" // Array is just like slice, but has a fixed length.
89 Chan Kind = "Chan"
90 Func Kind = "Func"
91
92 // DeclarationOf is different from other Kinds; it indicates that instead of
93 // representing an actual Type, the type is a declaration of an instance of
94 // a type. E.g., a top-level function, variable, or constant. See the
95 // comment for Type.Name for more detail.
96 DeclarationOf Kind = "DeclarationOf"
97 Unknown Kind = ""
98 Unsupported Kind = "Unsupported"
99
100 // Protobuf is protobuf type.
101 Protobuf Kind = "Protobuf"
102)
103
104// Package holds package-level information.
105// Fields are public, as everything in this package, to enable consumption by
106// templates (for example). But it is strongly encouraged for code to build by
107// using the provided functions.
108type Package struct {
109 // Canonical name of this package-- its path.
110 Path string
111
112 // The location this package was loaded from
113 SourcePath string
114
115 // Short name of this package; the name that appears in the
116 // 'package x' line.
117 Name string
118
119 // The comment right above the package declaration in doc.go, if any.
120 DocComments []string
121
122 // All comments from doc.go, if any.
123 // TODO: remove Comments and use DocComments everywhere.
124 Comments []string
125
126 // Types within this package, indexed by their name (*not* including
127 // package name).
128 Types map[string]*Type
129
130 // Functions within this package, indexed by their name (*not* including
131 // package name).
132 Functions map[string]*Type
133
134 // Global variables within this package, indexed by their name (*not* including
135 // package name).
136 Variables map[string]*Type
137
138 // Packages imported by this package, indexed by (canonicalized)
139 // package path.
140 Imports map[string]*Package
141}
142
143// Has returns true if the given name references a type known to this package.
144func (p *Package) Has(name string) bool {
145 _, has := p.Types[name]
146 return has
147}
148
149// Type gets the given Type in this Package. If the Type is not already
150// defined, this will add it and return the new Type value. The caller is
151// expected to finish initialization.
152func (p *Package) Type(typeName string) *Type {
153 if t, ok := p.Types[typeName]; ok {
154 return t
155 }
156 if p.Path == "" {
157 // Import the standard builtin types!
158 if t, ok := builtins.Types[typeName]; ok {
159 p.Types[typeName] = t
160 return t
161 }
162 }
163 t := &Type{Name: Name{Package: p.Path, Name: typeName}}
164 p.Types[typeName] = t
165 return t
166}
167
168// Function gets the given function Type in this Package. If the function is
169// not already defined, this will add it. If a function is added, it's the
170// caller's responsibility to finish construction of the function by setting
171// Underlying to the correct type.
172func (p *Package) Function(funcName string) *Type {
173 if t, ok := p.Functions[funcName]; ok {
174 return t
175 }
176 t := &Type{Name: Name{Package: p.Path, Name: funcName}}
177 t.Kind = DeclarationOf
178 p.Functions[funcName] = t
179 return t
180}
181
182// Variable gets the given variable Type in this Package. If the variable is
183// not already defined, this will add it. If a variable is added, it's the caller's
184// responsibility to finish construction of the variable by setting Underlying
185// to the correct type.
186func (p *Package) Variable(varName string) *Type {
187 if t, ok := p.Variables[varName]; ok {
188 return t
189 }
190 t := &Type{Name: Name{Package: p.Path, Name: varName}}
191 t.Kind = DeclarationOf
192 p.Variables[varName] = t
193 return t
194}
195
196// HasImport returns true if p imports packageName. Package names include the
197// package directory.
198func (p *Package) HasImport(packageName string) bool {
199 _, has := p.Imports[packageName]
200 return has
201}
202
203// Universe is a map of all packages. The key is the package name, but you
204// should use Package(), Type(), Function(), or Variable() instead of direct
205// access.
206type Universe map[string]*Package
207
208// Type returns the canonical type for the given fully-qualified name. Builtin
209// types will always be found, even if they haven't been explicitly added to
210// the map. If a non-existing type is requested, this will create (a marker for)
211// it.
212func (u Universe) Type(n Name) *Type {
213 return u.Package(n.Package).Type(n.Name)
214}
215
216// Function returns the canonical function for the given fully-qualified name.
217// If a non-existing function is requested, this will create (a marker for) it.
218// If a marker is created, it's the caller's responsibility to finish
219// construction of the function by setting Underlying to the correct type.
220func (u Universe) Function(n Name) *Type {
221 return u.Package(n.Package).Function(n.Name)
222}
223
224// Variable returns the canonical variable for the given fully-qualified name.
225// If a non-existing variable is requested, this will create (a marker for) it.
226// If a marker is created, it's the caller's responsibility to finish
227// construction of the variable by setting Underlying to the correct type.
228func (u Universe) Variable(n Name) *Type {
229 return u.Package(n.Package).Variable(n.Name)
230}
231
232// AddImports registers import lines for packageName. May be called multiple times.
233// You are responsible for canonicalizing all package paths.
234func (u Universe) AddImports(packagePath string, importPaths ...string) {
235 p := u.Package(packagePath)
236 for _, i := range importPaths {
237 p.Imports[i] = u.Package(i)
238 }
239}
240
241// Package returns the Package for the given path.
242// If a non-existing package is requested, this will create (a marker for) it.
243// If a marker is created, it's the caller's responsibility to finish
244// construction of the package.
245func (u Universe) Package(packagePath string) *Package {
246 if p, ok := u[packagePath]; ok {
247 return p
248 }
249 p := &Package{
250 Path: packagePath,
251 Types: map[string]*Type{},
252 Functions: map[string]*Type{},
253 Variables: map[string]*Type{},
254 Imports: map[string]*Package{},
255 }
256 u[packagePath] = p
257 return p
258}
259
260// Type represents a subset of possible go types.
261type Type struct {
262 // There are two general categories of types, those explicitly named
263 // and those anonymous. Named ones will have a non-empty package in the
264 // name field.
265 //
266 // An exception: If Kind == DeclarationOf, then this name is the name of a
267 // top-level function, variable, or const, and the type can be found in Underlying.
268 // We do this to allow the naming system to work against these objects, even
269 // though they aren't strictly speaking types.
270 Name Name
271
272 // The general kind of this type.
273 Kind Kind
274
275 // If there are comment lines immediately before the type definition,
276 // they will be recorded here.
277 CommentLines []string
278
279 // If there are comment lines preceding the `CommentLines`, they will be
280 // recorded here. There are two cases:
281 // ---
282 // SecondClosestCommentLines
283 // a blank line
284 // CommentLines
285 // type definition
286 // ---
287 //
288 // or
289 // ---
290 // SecondClosestCommentLines
291 // a blank line
292 // type definition
293 // ---
294 SecondClosestCommentLines []string
295
296 // If Kind == Struct
297 Members []Member
298
299 // If Kind == Map, Slice, Pointer, or Chan
300 Elem *Type
301
302 // If Kind == Map, this is the map's key type.
303 Key *Type
304
305 // If Kind == Alias, this is the underlying type.
306 // If Kind == DeclarationOf, this is the type of the declaration.
307 Underlying *Type
308
309 // If Kind == Interface, this is the set of all required functions.
310 // Otherwise, if this is a named type, this is the list of methods that
311 // type has. (All elements will have Kind=="Func")
312 Methods map[string]*Type
313
314 // If Kind == func, this is the signature of the function.
315 Signature *Signature
316
317 // TODO: Add:
318 // * channel direction
319 // * array length
320}
321
322// String returns the name of the type.
323func (t *Type) String() string {
324 return t.Name.String()
325}
326
327// IsPrimitive returns whether the type is a built-in type or is an alias to a
328// built-in type. For example: strings and aliases of strings are primitives,
329// structs are not.
330func (t *Type) IsPrimitive() bool {
331 if t.Kind == Builtin || (t.Kind == Alias && t.Underlying.Kind == Builtin) {
332 return true
333 }
334 return false
335}
336
337// IsAssignable returns whether the type is deep-assignable. For example,
338// slices and maps and pointers are shallow copies, but ints and strings are
339// complete.
340func (t *Type) IsAssignable() bool {
341 if t.IsPrimitive() {
342 return true
343 }
344 if t.Kind == Struct {
345 for _, m := range t.Members {
346 if !m.Type.IsAssignable() {
347 return false
348 }
349 }
350 return true
351 }
352 return false
353}
354
355// IsAnonymousStruct returns true if the type is an anonymous struct or an alias
356// to an anonymous struct.
357func (t *Type) IsAnonymousStruct() bool {
358 return (t.Kind == Struct && t.Name.Name == "struct{}") || (t.Kind == Alias && t.Underlying.IsAnonymousStruct())
359}
360
361// A single struct member
362type Member struct {
363 // The name of the member.
364 Name string
365
366 // If the member is embedded (anonymous) this will be true, and the
367 // Name will be the type name.
368 Embedded bool
369
370 // If there are comment lines immediately before the member in the type
371 // definition, they will be recorded here.
372 CommentLines []string
373
374 // If there are tags along with this member, they will be saved here.
375 Tags string
376
377 // The type of this member.
378 Type *Type
379}
380
381// String returns the name and type of the member.
382func (m Member) String() string {
383 return m.Name + " " + m.Type.String()
384}
385
386// Signature is a function's signature.
387type Signature struct {
388 // TODO: store the parameter names, not just types.
389
390 // If a method of some type, this is the type it's a member of.
391 Receiver *Type
392 Parameters []*Type
393 Results []*Type
394
395 // True if the last in parameter is of the form ...T.
396 Variadic bool
397
398 // If there are comment lines immediately before this
399 // signature/method/function declaration, they will be recorded here.
400 CommentLines []string
401}
402
403// Built in types.
404var (
405 String = &Type{
406 Name: Name{Name: "string"},
407 Kind: Builtin,
408 }
409 Int64 = &Type{
410 Name: Name{Name: "int64"},
411 Kind: Builtin,
412 }
413 Int32 = &Type{
414 Name: Name{Name: "int32"},
415 Kind: Builtin,
416 }
417 Int16 = &Type{
418 Name: Name{Name: "int16"},
419 Kind: Builtin,
420 }
421 Int = &Type{
422 Name: Name{Name: "int"},
423 Kind: Builtin,
424 }
425 Uint64 = &Type{
426 Name: Name{Name: "uint64"},
427 Kind: Builtin,
428 }
429 Uint32 = &Type{
430 Name: Name{Name: "uint32"},
431 Kind: Builtin,
432 }
433 Uint16 = &Type{
434 Name: Name{Name: "uint16"},
435 Kind: Builtin,
436 }
437 Uint = &Type{
438 Name: Name{Name: "uint"},
439 Kind: Builtin,
440 }
441 Uintptr = &Type{
442 Name: Name{Name: "uintptr"},
443 Kind: Builtin,
444 }
445 Float64 = &Type{
446 Name: Name{Name: "float64"},
447 Kind: Builtin,
448 }
449 Float32 = &Type{
450 Name: Name{Name: "float32"},
451 Kind: Builtin,
452 }
453 Float = &Type{
454 Name: Name{Name: "float"},
455 Kind: Builtin,
456 }
457 Bool = &Type{
458 Name: Name{Name: "bool"},
459 Kind: Builtin,
460 }
461 Byte = &Type{
462 Name: Name{Name: "byte"},
463 Kind: Builtin,
464 }
465
466 builtins = &Package{
467 Types: map[string]*Type{
468 "bool": Bool,
469 "string": String,
470 "int": Int,
471 "int64": Int64,
472 "int32": Int32,
473 "int16": Int16,
474 "int8": Byte,
475 "uint": Uint,
476 "uint64": Uint64,
477 "uint32": Uint32,
478 "uint16": Uint16,
479 "uint8": Byte,
480 "uintptr": Uintptr,
481 "byte": Byte,
482 "float": Float,
483 "float64": Float64,
484 "float32": Float32,
485 },
486 Imports: map[string]*Package{},
487 Path: "",
488 Name: "",
489 }
490)
491
492func IsInteger(t *Type) bool {
493 switch t {
494 case Int, Int64, Int32, Int16, Uint, Uint64, Uint32, Uint16, Byte:
495 return true
496 default:
497 return false
498 }
499}