forked from golang/tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
imports.go
134 lines (124 loc) · 3.57 KB
/
imports.go
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
// 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"
"github.com/goki/go-tools/internal/typeparams"
)
// 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 *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 = typeparams.NamedTypeOrigin(T)
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 := typeparams.ForNamed(T); tparams != nil {
for i := 0; i < tparams.Len(); i++ {
addType(tparams.At(i))
}
}
if targs := typeparams.NamedTypeArgs(T); 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 := typeparams.ForSignature(T); 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 *typeparams.Union:
for i := 0; i < T.Len(); i++ {
addType(T.Term(i).Type())
}
case *typeparams.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
}