1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package facts
import (
"go/types"
"golang.org/x/tools/internal/aliases"
)
// importMap computes the import map for a package by traversing the
// entire exported API each of its imports.
//
// This is a workaround for the fact that we cannot access the map used
// internally by the types.Importer returned by go/importer. The entries
// in this map are the packages and objects that may be relevant to the
// current analysis unit.
//
// Packages in the map that are only indirectly imported may be
// incomplete (!pkg.Complete()).
//
// This function scales very poorly with packages' transitive object
// references, which can be more than a million for each package near
// the top of a large project. (This was a significant contributor to
// #60621.)
// TODO(adonovan): opt: compute this information more efficiently
// by obtaining it from the internals of the gcexportdata decoder.
func importMap(imports []*types.Package) map[string]*types.Package {
objects := make(map[types.Object]bool)
typs := make(map[types.Type]bool) // Named and TypeParam
packages := make(map[string]*types.Package)
var addObj func(obj types.Object)
var addType func(T types.Type)
addObj = func(obj types.Object) {
if !objects[obj] {
objects[obj] = true
addType(obj.Type())
if pkg := obj.Pkg(); pkg != nil {
packages[pkg.Path()] = pkg
}
}
}
addType = func(T types.Type) {
switch T := T.(type) {
case *aliases.Alias:
addType(aliases.Unalias(T))
case *types.Basic:
// nop
case *types.Named:
// Remove infinite expansions of *types.Named by always looking at the origin.
// Some named types with type parameters [that will not type check] have
// infinite expansions:
// type N[T any] struct { F *N[N[T]] }
// importMap() is called on such types when Analyzer.RunDespiteErrors is true.
T = T.Origin()
if !typs[T] {
typs[T] = true
addObj(T.Obj())
addType(T.Underlying())
for i := 0; i < T.NumMethods(); i++ {
addObj(T.Method(i))
}
if tparams := T.TypeParams(); tparams != nil {
for i := 0; i < tparams.Len(); i++ {
addType(tparams.At(i))
}
}
if targs := T.TypeArgs(); targs != nil {
for i := 0; i < targs.Len(); i++ {
addType(targs.At(i))
}
}
}
case *types.Pointer:
addType(T.Elem())
case *types.Slice:
addType(T.Elem())
case *types.Array:
addType(T.Elem())
case *types.Chan:
addType(T.Elem())
case *types.Map:
addType(T.Key())
addType(T.Elem())
case *types.Signature:
addType(T.Params())
addType(T.Results())
if tparams := T.TypeParams(); tparams != nil {
for i := 0; i < tparams.Len(); i++ {
addType(tparams.At(i))
}
}
case *types.Struct:
for i := 0; i < T.NumFields(); i++ {
addObj(T.Field(i))
}
case *types.Tuple:
for i := 0; i < T.Len(); i++ {
addObj(T.At(i))
}
case *types.Interface:
for i := 0; i < T.NumMethods(); i++ {
addObj(T.Method(i))
}
for i := 0; i < T.NumEmbeddeds(); i++ {
addType(T.EmbeddedType(i)) // walk Embedded for implicits
}
case *types.Union:
for i := 0; i < T.Len(); i++ {
addType(T.Term(i).Type())
}
case *types.TypeParam:
if !typs[T] {
typs[T] = true
addObj(T.Obj())
addType(T.Constraint())
}
}
}
for _, imp := range imports {
packages[imp.Path()] = imp
scope := imp.Scope()
for _, name := range scope.Names() {
addObj(scope.Lookup(name))
}
}
return packages
}
|