Matthias Andreas Benkard | 832a54e | 2019-01-29 09:27:38 +0100 | [diff] [blame] | 1 | /* |
| 2 | Copyright 2015 The Kubernetes Authors. |
| 3 | |
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | you may not use this file except in compliance with the License. |
| 6 | You may obtain a copy of the License at |
| 7 | |
| 8 | http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | |
| 10 | Unless required by applicable law or agreed to in writing, software |
| 11 | distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | See the License for the specific language governing permissions and |
| 14 | limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package types |
| 18 | |
| 19 | import "strings" |
| 20 | |
| 21 | // Ref makes a reference to the given type. It can only be used for e.g. |
| 22 | // passing to namers. |
| 23 | func 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. |
| 31 | type 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. |
| 42 | func (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. |
| 50 | func 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. |
| 63 | type Kind string |
| 64 | |
| 65 | const ( |
| 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. |
| 108 | type 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. |
| 144 | func (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. |
| 152 | func (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. |
| 172 | func (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. |
| 186 | func (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. |
| 198 | func (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. |
| 206 | type 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. |
| 212 | func (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. |
| 220 | func (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. |
| 228 | func (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. |
| 234 | func (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. |
| 245 | func (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. |
| 261 | type 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. |
| 323 | func (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. |
| 330 | func (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. |
| 340 | func (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. |
| 357 | func (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 |
| 362 | type 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. |
| 382 | func (m Member) String() string { |
| 383 | return m.Name + " " + m.Type.String() |
| 384 | } |
| 385 | |
| 386 | // Signature is a function's signature. |
| 387 | type 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. |
| 404 | var ( |
| 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 | |
| 492 | func 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 | } |