parse.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. /*
  2. Copyright 2015 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package parser
  14. import (
  15. "fmt"
  16. "go/ast"
  17. "go/build"
  18. "go/parser"
  19. "go/token"
  20. tc "go/types"
  21. "io/ioutil"
  22. "os"
  23. "os/exec"
  24. "path/filepath"
  25. "strings"
  26. "github.com/golang/glog"
  27. "k8s.io/kubernetes/cmd/libs/go2idl/types"
  28. )
  29. // Builder lets you add all the go files in all the packages that you care
  30. // about, then constructs the type source data.
  31. type Builder struct {
  32. context *build.Context
  33. buildInfo map[string]*build.Package
  34. fset *token.FileSet
  35. // map of package id to list of parsed files
  36. parsed map[string][]parsedFile
  37. // map of package id to absolute path (to prevent overlap)
  38. absPaths map[string]string
  39. // Set by makePackage(), used by importer() and friends.
  40. pkgs map[string]*tc.Package
  41. // Map of package path to whether the user requested it or it was from
  42. // an import.
  43. userRequested map[string]bool
  44. // All comments from everywhere in every parsed file.
  45. endLineToCommentGroup map[fileLine]*ast.CommentGroup
  46. // map of package to list of packages it imports.
  47. importGraph map[string]map[string]struct{}
  48. }
  49. // parsedFile is for tracking files with name
  50. type parsedFile struct {
  51. name string
  52. file *ast.File
  53. }
  54. // key type for finding comments.
  55. type fileLine struct {
  56. file string
  57. line int
  58. }
  59. // New constructs a new builder.
  60. func New() *Builder {
  61. c := build.Default
  62. if c.GOROOT == "" {
  63. if p, err := exec.Command("which", "go").CombinedOutput(); err == nil {
  64. // The returned string will have some/path/bin/go, so remove the last two elements.
  65. c.GOROOT = filepath.Dir(filepath.Dir(strings.Trim(string(p), "\n")))
  66. } else {
  67. glog.Warningf("Warning: $GOROOT not set, and unable to run `which go` to find it: %v\n", err)
  68. }
  69. }
  70. // Force this to off, since we don't properly parse CGo. All symbols must
  71. // have non-CGo equivalents.
  72. c.CgoEnabled = false
  73. return &Builder{
  74. context: &c,
  75. buildInfo: map[string]*build.Package{},
  76. fset: token.NewFileSet(),
  77. parsed: map[string][]parsedFile{},
  78. absPaths: map[string]string{},
  79. userRequested: map[string]bool{},
  80. endLineToCommentGroup: map[fileLine]*ast.CommentGroup{},
  81. importGraph: map[string]map[string]struct{}{},
  82. }
  83. }
  84. // AddBuildTags adds the specified build tags to the parse context.
  85. func (b *Builder) AddBuildTags(tags ...string) {
  86. b.context.BuildTags = append(b.context.BuildTags, tags...)
  87. }
  88. // Get package information from the go/build package. Automatically excludes
  89. // e.g. test files and files for other platforms-- there is quite a bit of
  90. // logic of that nature in the build package.
  91. func (b *Builder) buildPackage(pkgPath string) (*build.Package, error) {
  92. // This is a bit of a hack. The srcDir argument to Import() should
  93. // properly be the dir of the file which depends on the package to be
  94. // imported, so that vendoring can work properly. We assume that there is
  95. // only one level of vendoring, and that the CWD is inside the GOPATH, so
  96. // this should be safe.
  97. cwd, err := os.Getwd()
  98. if err != nil {
  99. return nil, fmt.Errorf("unable to get current directory: %v", err)
  100. }
  101. // First, find it, so we know what path to use.
  102. pkg, err := b.context.Import(pkgPath, cwd, build.FindOnly)
  103. if err != nil {
  104. return nil, fmt.Errorf("unable to *find* %q: %v", pkgPath, err)
  105. }
  106. pkgPath = pkg.ImportPath
  107. if pkg, ok := b.buildInfo[pkgPath]; ok {
  108. return pkg, nil
  109. }
  110. pkg, err = b.context.Import(pkgPath, cwd, build.ImportComment)
  111. if err != nil {
  112. if _, ok := err.(*build.NoGoError); !ok {
  113. return nil, fmt.Errorf("unable to import %q: %v", pkgPath, err)
  114. }
  115. }
  116. b.buildInfo[pkgPath] = pkg
  117. if b.importGraph[pkgPath] == nil {
  118. b.importGraph[pkgPath] = map[string]struct{}{}
  119. }
  120. for _, p := range pkg.Imports {
  121. b.importGraph[pkgPath][p] = struct{}{}
  122. }
  123. return pkg, nil
  124. }
  125. // AddFile adds a file to the set. The pkg must be of the form
  126. // "canonical/pkg/path" and the path must be the absolute path to the file.
  127. func (b *Builder) AddFile(pkg string, path string, src []byte) error {
  128. return b.addFile(pkg, path, src, true)
  129. }
  130. // addFile adds a file to the set. The pkg must be of the form
  131. // "canonical/pkg/path" and the path must be the absolute path to the file. A
  132. // flag indicates whether this file was user-requested or just from following
  133. // the import graph.
  134. func (b *Builder) addFile(pkg string, path string, src []byte, userRequested bool) error {
  135. p, err := parser.ParseFile(b.fset, path, src, parser.DeclarationErrors|parser.ParseComments)
  136. if err != nil {
  137. return err
  138. }
  139. dirPath := filepath.Dir(path)
  140. if prev, found := b.absPaths[pkg]; found {
  141. if dirPath != prev {
  142. return fmt.Errorf("package %q (%s) previously resolved to %s", pkg, dirPath, prev)
  143. }
  144. } else {
  145. b.absPaths[pkg] = dirPath
  146. }
  147. b.parsed[pkg] = append(b.parsed[pkg], parsedFile{path, p})
  148. b.userRequested[pkg] = userRequested
  149. for _, c := range p.Comments {
  150. position := b.fset.Position(c.End())
  151. b.endLineToCommentGroup[fileLine{position.Filename, position.Line}] = c
  152. }
  153. // We have to get the packages from this specific file, in case the
  154. // user added individual files instead of entire directories.
  155. if b.importGraph[pkg] == nil {
  156. b.importGraph[pkg] = map[string]struct{}{}
  157. }
  158. for _, im := range p.Imports {
  159. importedPath := strings.Trim(im.Path.Value, `"`)
  160. b.importGraph[pkg][importedPath] = struct{}{}
  161. }
  162. return nil
  163. }
  164. // AddDir adds an entire directory, scanning it for go files. 'dir' should have
  165. // a single go package in it. GOPATH, GOROOT, and the location of your go
  166. // binary (`which go`) will all be searched if dir doesn't literally resolve.
  167. func (b *Builder) AddDir(dir string) error {
  168. return b.addDir(dir, true)
  169. }
  170. // AddDirRecursive is just like AddDir, but it also recursively adds
  171. // subdirectories; it returns an error only if the path couldn't be resolved;
  172. // any directories recursed into without go source are ignored.
  173. func (b *Builder) AddDirRecursive(dir string) error {
  174. // This is a bit of a hack. The srcDir argument to Import() should
  175. // properly be the dir of the file which depends on the package to be
  176. // imported, so that vendoring can work properly. We assume that there is
  177. // only one level of vendoring, and that the CWD is inside the GOPATH, so
  178. // this should be safe.
  179. cwd, err := os.Getwd()
  180. if err != nil {
  181. return fmt.Errorf("unable to get current directory: %v", err)
  182. }
  183. // First, find it, so we know what path to use.
  184. pkg, err := b.context.Import(dir, cwd, build.FindOnly)
  185. if err != nil {
  186. return fmt.Errorf("unable to *find* %q: %v", dir, err)
  187. }
  188. if err := b.addDir(dir, true); err != nil {
  189. glog.Warningf("Ignoring directory %v: %v", dir, err)
  190. }
  191. prefix := strings.TrimSuffix(pkg.Dir, strings.TrimSuffix(dir, "/"))
  192. filepath.Walk(pkg.Dir, func(path string, info os.FileInfo, err error) error {
  193. if info != nil && info.IsDir() {
  194. trimmed := strings.TrimPrefix(path, prefix)
  195. if trimmed != "" {
  196. if err := b.addDir(trimmed, true); err != nil {
  197. glog.Warningf("Ignoring child directory %v: %v", trimmed, err)
  198. }
  199. }
  200. }
  201. return nil
  202. })
  203. return nil
  204. }
  205. // AddDirTo adds an entire directory to a given Universe. Unlike AddDir, this
  206. // processes the package immediately, which makes it safe to use from within a
  207. // generator (rather than just at init time. 'dir' must be a single go package.
  208. // GOPATH, GOROOT, and the location of your go binary (`which go`) will all be
  209. // searched if dir doesn't literally resolve.
  210. func (b *Builder) AddDirTo(dir string, u *types.Universe) error {
  211. if _, found := b.parsed[dir]; !found {
  212. // We want all types from this package, as if they were directly added
  213. // by the user. They WERE added by the user, in effect.
  214. if err := b.addDir(dir, true); err != nil {
  215. return err
  216. }
  217. } else {
  218. // We already had this package, but we want it to be considered as if
  219. // the user addid it directly.
  220. b.userRequested[dir] = true
  221. }
  222. return b.findTypesIn(dir, u)
  223. }
  224. // The implementation of AddDir. A flag indicates whether this directory was
  225. // user-requested or just from following the import graph.
  226. func (b *Builder) addDir(dir string, userRequested bool) error {
  227. pkg, err := b.buildPackage(dir)
  228. if err != nil {
  229. return err
  230. }
  231. // Check in case this package was added (maybe dir was not canonical)
  232. if wasRequested, wasAdded := b.userRequested[dir]; wasAdded {
  233. if !userRequested || userRequested == wasRequested {
  234. return nil
  235. }
  236. }
  237. for _, n := range pkg.GoFiles {
  238. if !strings.HasSuffix(n, ".go") {
  239. continue
  240. }
  241. absPath := filepath.Join(pkg.Dir, n)
  242. data, err := ioutil.ReadFile(absPath)
  243. if err != nil {
  244. return fmt.Errorf("while loading %q: %v", absPath, err)
  245. }
  246. err = b.addFile(dir, absPath, data, userRequested)
  247. if err != nil {
  248. return fmt.Errorf("while parsing %q: %v", absPath, err)
  249. }
  250. }
  251. return nil
  252. }
  253. // importer is a function that will be called by the type check package when it
  254. // needs to import a go package. 'path' is the import path. go1.5 changes the
  255. // interface, and importAdapter below implements the new interface in terms of
  256. // the old one.
  257. func (b *Builder) importer(imports map[string]*tc.Package, path string) (*tc.Package, error) {
  258. if pkg, ok := imports[path]; ok {
  259. return pkg, nil
  260. }
  261. ignoreError := false
  262. if _, ours := b.parsed[path]; !ours {
  263. // Ignore errors in paths that we're importing solely because
  264. // they're referenced by other packages.
  265. ignoreError = true
  266. if err := b.addDir(path, false); err != nil {
  267. return nil, err
  268. }
  269. }
  270. pkg, err := b.typeCheckPackage(path)
  271. if err != nil {
  272. if ignoreError && pkg != nil {
  273. glog.V(2).Infof("type checking encountered some errors in %q, but ignoring.\n", path)
  274. } else {
  275. return nil, err
  276. }
  277. }
  278. imports[path] = pkg
  279. return pkg, nil
  280. }
  281. type importAdapter struct {
  282. b *Builder
  283. }
  284. func (a importAdapter) Import(path string) (*tc.Package, error) {
  285. return a.b.importer(a.b.pkgs, path)
  286. }
  287. // typeCheckPackage will attempt to return the package even if there are some
  288. // errors, so you may check whether the package is nil or not even if you get
  289. // an error.
  290. func (b *Builder) typeCheckPackage(id string) (*tc.Package, error) {
  291. if pkg, ok := b.pkgs[id]; ok {
  292. if pkg != nil {
  293. return pkg, nil
  294. }
  295. // We store a nil right before starting work on a package. So
  296. // if we get here and it's present and nil, that means there's
  297. // another invocation of this function on the call stack
  298. // already processing this package.
  299. return nil, fmt.Errorf("circular dependency for %q", id)
  300. }
  301. parsedFiles, ok := b.parsed[id]
  302. if !ok {
  303. return nil, fmt.Errorf("No files for pkg %q: %#v", id, b.parsed)
  304. }
  305. files := make([]*ast.File, len(parsedFiles))
  306. for i := range parsedFiles {
  307. files[i] = parsedFiles[i].file
  308. }
  309. b.pkgs[id] = nil
  310. c := tc.Config{
  311. IgnoreFuncBodies: true,
  312. // Note that importAdater can call b.import which calls this
  313. // method. So there can't be cycles in the import graph.
  314. Importer: importAdapter{b},
  315. Error: func(err error) {
  316. glog.V(2).Infof("type checker error: %v\n", err)
  317. },
  318. }
  319. pkg, err := c.Check(id, b.fset, files, nil)
  320. b.pkgs[id] = pkg // record the result whether or not there was an error
  321. return pkg, err
  322. }
  323. func (b *Builder) makeAllPackages() error {
  324. // Take a snapshot to iterate, since this will recursively mutate b.parsed.
  325. keys := []string{}
  326. for id := range b.parsed {
  327. keys = append(keys, id)
  328. }
  329. for _, id := range keys {
  330. if _, err := b.makePackage(id); err != nil {
  331. return err
  332. }
  333. }
  334. return nil
  335. }
  336. func (b *Builder) makePackage(id string) (*tc.Package, error) {
  337. if b.pkgs == nil {
  338. b.pkgs = map[string]*tc.Package{}
  339. }
  340. // We have to check here even though we made a new one above,
  341. // because typeCheckPackage follows the import graph, which may
  342. // cause a package to be filled before we get to it in this
  343. // loop.
  344. if pkg, done := b.pkgs[id]; done {
  345. return pkg, nil
  346. }
  347. return b.typeCheckPackage(id)
  348. }
  349. // FindPackages fetches a list of the user-imported packages.
  350. func (b *Builder) FindPackages() []string {
  351. result := []string{}
  352. for pkgPath := range b.pkgs {
  353. if b.userRequested[pkgPath] {
  354. // Since walkType is recursive, all types that are in packages that
  355. // were directly mentioned will be included. We don't need to
  356. // include all types in all transitive packages, though.
  357. result = append(result, pkgPath)
  358. }
  359. }
  360. return result
  361. }
  362. // FindTypes finalizes the package imports, and searches through all the
  363. // packages for types.
  364. func (b *Builder) FindTypes() (types.Universe, error) {
  365. if err := b.makeAllPackages(); err != nil {
  366. return nil, err
  367. }
  368. u := types.Universe{}
  369. for pkgPath := range b.parsed {
  370. if err := b.findTypesIn(pkgPath, &u); err != nil {
  371. return nil, err
  372. }
  373. }
  374. return u, nil
  375. }
  376. // findTypesIn finalizes the package import and searches through the package
  377. // for types.
  378. func (b *Builder) findTypesIn(pkgPath string, u *types.Universe) error {
  379. pkg, err := b.makePackage(pkgPath)
  380. if err != nil {
  381. return err
  382. }
  383. if !b.userRequested[pkgPath] {
  384. // Since walkType is recursive, all types that the
  385. // packages they asked for depend on will be included.
  386. // But we don't need to include all types in all
  387. // *packages* they depend on.
  388. return nil
  389. }
  390. for _, f := range b.parsed[pkgPath] {
  391. if strings.HasSuffix(f.name, "/doc.go") {
  392. tp := u.Package(pkgPath)
  393. for i := range f.file.Comments {
  394. tp.Comments = append(tp.Comments, splitLines(f.file.Comments[i].Text())...)
  395. }
  396. if f.file.Doc != nil {
  397. tp.DocComments = splitLines(f.file.Doc.Text())
  398. }
  399. }
  400. }
  401. s := pkg.Scope()
  402. for _, n := range s.Names() {
  403. obj := s.Lookup(n)
  404. tn, ok := obj.(*tc.TypeName)
  405. if ok {
  406. t := b.walkType(*u, nil, tn.Type())
  407. c1 := b.priorCommentLines(obj.Pos(), 1)
  408. t.CommentLines = splitLines(c1.Text())
  409. if c1 == nil {
  410. t.SecondClosestCommentLines = splitLines(b.priorCommentLines(obj.Pos(), 2).Text())
  411. } else {
  412. t.SecondClosestCommentLines = splitLines(b.priorCommentLines(c1.List[0].Slash, 2).Text())
  413. }
  414. }
  415. tf, ok := obj.(*tc.Func)
  416. // We only care about functions, not concrete/abstract methods.
  417. if ok && tf.Type() != nil && tf.Type().(*tc.Signature).Recv() == nil {
  418. b.addFunction(*u, nil, tf)
  419. }
  420. tv, ok := obj.(*tc.Var)
  421. if ok && !tv.IsField() {
  422. b.addVariable(*u, nil, tv)
  423. }
  424. }
  425. for p := range b.importGraph[pkgPath] {
  426. u.AddImports(pkgPath, p)
  427. }
  428. u.Package(pkgPath).Name = pkg.Name()
  429. return nil
  430. }
  431. // if there's a comment on the line `lines` before pos, return its text, otherwise "".
  432. func (b *Builder) priorCommentLines(pos token.Pos, lines int) *ast.CommentGroup {
  433. position := b.fset.Position(pos)
  434. key := fileLine{position.Filename, position.Line - lines}
  435. return b.endLineToCommentGroup[key]
  436. }
  437. func splitLines(str string) []string {
  438. return strings.Split(strings.TrimRight(str, "\n"), "\n")
  439. }
  440. func tcFuncNameToName(in string) types.Name {
  441. name := strings.TrimLeft(in, "func ")
  442. nameParts := strings.Split(name, "(")
  443. return tcNameToName(nameParts[0])
  444. }
  445. func tcVarNameToName(in string) types.Name {
  446. nameParts := strings.Split(in, " ")
  447. // nameParts[0] is "var".
  448. // nameParts[2:] is the type of the variable, we ignore it for now.
  449. return tcNameToName(nameParts[1])
  450. }
  451. func tcNameToName(in string) types.Name {
  452. // Detect anonymous type names. (These may have '.' characters because
  453. // embedded types may have packages, so we detect them specially.)
  454. if strings.HasPrefix(in, "struct{") ||
  455. strings.HasPrefix(in, "<-chan") ||
  456. strings.HasPrefix(in, "chan<-") ||
  457. strings.HasPrefix(in, "chan ") ||
  458. strings.HasPrefix(in, "func(") ||
  459. strings.HasPrefix(in, "*") ||
  460. strings.HasPrefix(in, "map[") ||
  461. strings.HasPrefix(in, "[") {
  462. return types.Name{Name: in}
  463. }
  464. // Otherwise, if there are '.' characters present, the name has a
  465. // package path in front.
  466. nameParts := strings.Split(in, ".")
  467. name := types.Name{Name: in}
  468. if n := len(nameParts); n >= 2 {
  469. // The final "." is the name of the type--previous ones must
  470. // have been in the package path.
  471. name.Package, name.Name = strings.Join(nameParts[:n-1], "."), nameParts[n-1]
  472. }
  473. return name
  474. }
  475. func (b *Builder) convertSignature(u types.Universe, t *tc.Signature) *types.Signature {
  476. signature := &types.Signature{}
  477. for i := 0; i < t.Params().Len(); i++ {
  478. signature.Parameters = append(signature.Parameters, b.walkType(u, nil, t.Params().At(i).Type()))
  479. }
  480. for i := 0; i < t.Results().Len(); i++ {
  481. signature.Results = append(signature.Results, b.walkType(u, nil, t.Results().At(i).Type()))
  482. }
  483. if r := t.Recv(); r != nil {
  484. signature.Receiver = b.walkType(u, nil, r.Type())
  485. }
  486. signature.Variadic = t.Variadic()
  487. return signature
  488. }
  489. // walkType adds the type, and any necessary child types.
  490. func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *types.Type {
  491. // Most of the cases are underlying types of the named type.
  492. name := tcNameToName(in.String())
  493. if useName != nil {
  494. name = *useName
  495. }
  496. switch t := in.(type) {
  497. case *tc.Struct:
  498. out := u.Type(name)
  499. if out.Kind != types.Unknown {
  500. return out
  501. }
  502. out.Kind = types.Struct
  503. for i := 0; i < t.NumFields(); i++ {
  504. f := t.Field(i)
  505. m := types.Member{
  506. Name: f.Name(),
  507. Embedded: f.Anonymous(),
  508. Tags: t.Tag(i),
  509. Type: b.walkType(u, nil, f.Type()),
  510. CommentLines: splitLines(b.priorCommentLines(f.Pos(), 1).Text()),
  511. }
  512. out.Members = append(out.Members, m)
  513. }
  514. return out
  515. case *tc.Map:
  516. out := u.Type(name)
  517. if out.Kind != types.Unknown {
  518. return out
  519. }
  520. out.Kind = types.Map
  521. out.Elem = b.walkType(u, nil, t.Elem())
  522. out.Key = b.walkType(u, nil, t.Key())
  523. return out
  524. case *tc.Pointer:
  525. out := u.Type(name)
  526. if out.Kind != types.Unknown {
  527. return out
  528. }
  529. out.Kind = types.Pointer
  530. out.Elem = b.walkType(u, nil, t.Elem())
  531. return out
  532. case *tc.Slice:
  533. out := u.Type(name)
  534. if out.Kind != types.Unknown {
  535. return out
  536. }
  537. out.Kind = types.Slice
  538. out.Elem = b.walkType(u, nil, t.Elem())
  539. return out
  540. case *tc.Array:
  541. out := u.Type(name)
  542. if out.Kind != types.Unknown {
  543. return out
  544. }
  545. out.Kind = types.Array
  546. out.Elem = b.walkType(u, nil, t.Elem())
  547. // TODO: need to store array length, otherwise raw type name
  548. // cannot be properly written.
  549. return out
  550. case *tc.Chan:
  551. out := u.Type(name)
  552. if out.Kind != types.Unknown {
  553. return out
  554. }
  555. out.Kind = types.Chan
  556. out.Elem = b.walkType(u, nil, t.Elem())
  557. // TODO: need to store direction, otherwise raw type name
  558. // cannot be properly written.
  559. return out
  560. case *tc.Basic:
  561. out := u.Type(types.Name{
  562. Package: "",
  563. Name: t.Name(),
  564. })
  565. if out.Kind != types.Unknown {
  566. return out
  567. }
  568. out.Kind = types.Unsupported
  569. return out
  570. case *tc.Signature:
  571. out := u.Type(name)
  572. if out.Kind != types.Unknown {
  573. return out
  574. }
  575. out.Kind = types.Func
  576. out.Signature = b.convertSignature(u, t)
  577. return out
  578. case *tc.Interface:
  579. out := u.Type(name)
  580. if out.Kind != types.Unknown {
  581. return out
  582. }
  583. out.Kind = types.Interface
  584. t.Complete()
  585. for i := 0; i < t.NumMethods(); i++ {
  586. if out.Methods == nil {
  587. out.Methods = map[string]*types.Type{}
  588. }
  589. out.Methods[t.Method(i).Name()] = b.walkType(u, nil, t.Method(i).Type())
  590. }
  591. return out
  592. case *tc.Named:
  593. switch t.Underlying().(type) {
  594. case *tc.Named, *tc.Basic, *tc.Map, *tc.Slice:
  595. name := tcNameToName(t.String())
  596. out := u.Type(name)
  597. if out.Kind != types.Unknown {
  598. return out
  599. }
  600. out.Kind = types.Alias
  601. out.Underlying = b.walkType(u, nil, t.Underlying())
  602. return out
  603. default:
  604. // tc package makes everything "named" with an
  605. // underlying anonymous type--we remove that annoying
  606. // "feature" for users. This flattens those types
  607. // together.
  608. name := tcNameToName(t.String())
  609. if out := u.Type(name); out.Kind != types.Unknown {
  610. return out // short circuit if we've already made this.
  611. }
  612. out := b.walkType(u, &name, t.Underlying())
  613. if len(out.Methods) == 0 {
  614. // If the underlying type didn't already add
  615. // methods, add them. (Interface types will
  616. // have already added methods.)
  617. for i := 0; i < t.NumMethods(); i++ {
  618. if out.Methods == nil {
  619. out.Methods = map[string]*types.Type{}
  620. }
  621. out.Methods[t.Method(i).Name()] = b.walkType(u, nil, t.Method(i).Type())
  622. }
  623. }
  624. return out
  625. }
  626. default:
  627. out := u.Type(name)
  628. if out.Kind != types.Unknown {
  629. return out
  630. }
  631. out.Kind = types.Unsupported
  632. glog.Warningf("Making unsupported type entry %q for: %#v\n", out, t)
  633. return out
  634. }
  635. }
  636. func (b *Builder) addFunction(u types.Universe, useName *types.Name, in *tc.Func) *types.Type {
  637. name := tcFuncNameToName(in.String())
  638. if useName != nil {
  639. name = *useName
  640. }
  641. out := u.Function(name)
  642. out.Kind = types.DeclarationOf
  643. out.Underlying = b.walkType(u, nil, in.Type())
  644. return out
  645. }
  646. func (b *Builder) addVariable(u types.Universe, useName *types.Name, in *tc.Var) *types.Type {
  647. name := tcVarNameToName(in.String())
  648. if useName != nil {
  649. name = *useName
  650. }
  651. out := u.Variable(name)
  652. out.Kind = types.DeclarationOf
  653. out.Underlying = b.walkType(u, nil, in.Type())
  654. return out
  655. }