| 1 | // Copyright 2018 The Go Authors. All rights reserved. |
|---|---|
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package facts |
| 6 | |
| 7 | import ( |
| 8 | "go/types" |
| 9 | |
| 10 | "golang.org/x/tools/internal/typeparams" |
| 11 | ) |
| 12 | |
| 13 | // importMap computes the import map for a package by traversing the |
| 14 | // entire exported API each of its imports. |
| 15 | // |
| 16 | // This is a workaround for the fact that we cannot access the map used |
| 17 | // internally by the types.Importer returned by go/importer. The entries |
| 18 | // in this map are the packages and objects that may be relevant to the |
| 19 | // current analysis unit. |
| 20 | // |
| 21 | // Packages in the map that are only indirectly imported may be |
| 22 | // incomplete (!pkg.Complete()). |
| 23 | // |
| 24 | // TODO(adonovan): opt: compute this information more efficiently |
| 25 | // by obtaining it from the internals of the gcexportdata decoder. |
| 26 | func importMap(imports []*types.Package) map[string]*types.Package { |
| 27 | objects := make(map[types.Object]bool) |
| 28 | packages := make(map[string]*types.Package) |
| 29 | |
| 30 | var addObj func(obj types.Object) bool |
| 31 | var addType func(T types.Type) |
| 32 | |
| 33 | addObj = func(obj types.Object) bool { |
| 34 | if !objects[obj] { |
| 35 | objects[obj] = true |
| 36 | addType(obj.Type()) |
| 37 | if pkg := obj.Pkg(); pkg != nil { |
| 38 | packages[pkg.Path()] = pkg |
| 39 | } |
| 40 | return true |
| 41 | } |
| 42 | return false |
| 43 | } |
| 44 | |
| 45 | addType = func(T types.Type) { |
| 46 | switch T := T.(type) { |
| 47 | case *types.Basic: |
| 48 | // nop |
| 49 | case *types.Named: |
| 50 | if addObj(T.Obj()) { |
| 51 | // TODO(taking): Investigate why the Underlying type is not added here. |
| 52 | for i := 0; i < T.NumMethods(); i++ { |
| 53 | addObj(T.Method(i)) |
| 54 | } |
| 55 | if tparams := typeparams.ForNamed(T); tparams != nil { |
| 56 | for i := 0; i < tparams.Len(); i++ { |
| 57 | addType(tparams.At(i)) |
| 58 | } |
| 59 | } |
| 60 | if targs := typeparams.NamedTypeArgs(T); targs != nil { |
| 61 | for i := 0; i < targs.Len(); i++ { |
| 62 | addType(targs.At(i)) |
| 63 | } |
| 64 | } |
| 65 | } |
| 66 | case *types.Pointer: |
| 67 | addType(T.Elem()) |
| 68 | case *types.Slice: |
| 69 | addType(T.Elem()) |
| 70 | case *types.Array: |
| 71 | addType(T.Elem()) |
| 72 | case *types.Chan: |
| 73 | addType(T.Elem()) |
| 74 | case *types.Map: |
| 75 | addType(T.Key()) |
| 76 | addType(T.Elem()) |
| 77 | case *types.Signature: |
| 78 | addType(T.Params()) |
| 79 | addType(T.Results()) |
| 80 | if tparams := typeparams.ForSignature(T); tparams != nil { |
| 81 | for i := 0; i < tparams.Len(); i++ { |
| 82 | addType(tparams.At(i)) |
| 83 | } |
| 84 | } |
| 85 | case *types.Struct: |
| 86 | for i := 0; i < T.NumFields(); i++ { |
| 87 | addObj(T.Field(i)) |
| 88 | } |
| 89 | case *types.Tuple: |
| 90 | for i := 0; i < T.Len(); i++ { |
| 91 | addObj(T.At(i)) |
| 92 | } |
| 93 | case *types.Interface: |
| 94 | for i := 0; i < T.NumMethods(); i++ { |
| 95 | addObj(T.Method(i)) |
| 96 | } |
| 97 | for i := 0; i < T.NumEmbeddeds(); i++ { |
| 98 | addType(T.EmbeddedType(i)) // walk Embedded for implicits |
| 99 | } |
| 100 | case *typeparams.Union: |
| 101 | for i := 0; i < T.Len(); i++ { |
| 102 | addType(T.Term(i).Type()) |
| 103 | } |
| 104 | case *typeparams.TypeParam: |
| 105 | if addObj(T.Obj()) { |
| 106 | addType(T.Constraint()) |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | for _, imp := range imports { |
| 112 | packages[imp.Path()] = imp |
| 113 | |
| 114 | scope := imp.Scope() |
| 115 | for _, name := range scope.Names() { |
| 116 | addObj(scope.Lookup(name)) |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | return packages |
| 121 | } |
| 122 |
Members