1
2
3
4
5 package ssa
6
7
8
9
10 import (
11 "fmt"
12 "go/ast"
13 "go/token"
14 "go/types"
15 "os"
16 "sync"
17
18 "golang.org/x/tools/go/types/typeutil"
19 "golang.org/x/tools/internal/typeparams"
20 )
21
22
23
24
25 func NewProgram(fset *token.FileSet, mode BuilderMode) *Program {
26 prog := &Program{
27 Fset: fset,
28 imported: make(map[string]*Package),
29 packages: make(map[*types.Package]*Package),
30 thunks: make(map[selectionKey]*Function),
31 bounds: make(map[boundsKey]*Function),
32 mode: mode,
33 canon: newCanonizer(),
34 ctxt: typeparams.NewContext(),
35 instances: make(map[*Function]*instanceSet),
36 parameterized: tpWalker{seen: make(map[types.Type]bool)},
37 }
38
39 h := typeutil.MakeHasher()
40 prog.methodSets.SetHasher(h)
41 prog.runtimeTypes.SetHasher(h)
42
43 return prog
44 }
45
46
47
48
49
50
51
52 func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
53 name := obj.Name()
54 switch obj := obj.(type) {
55 case *types.Builtin:
56 if pkg.Pkg != types.Unsafe {
57 panic("unexpected builtin object: " + obj.String())
58 }
59
60 case *types.TypeName:
61 pkg.Members[name] = &Type{
62 object: obj,
63 pkg: pkg,
64 }
65
66 case *types.Const:
67 c := &NamedConst{
68 object: obj,
69 Value: NewConst(obj.Val(), obj.Type()),
70 pkg: pkg,
71 }
72 pkg.objects[obj] = c
73 pkg.Members[name] = c
74
75 case *types.Var:
76 g := &Global{
77 Pkg: pkg,
78 name: name,
79 object: obj,
80 typ: types.NewPointer(obj.Type()),
81 pos: obj.Pos(),
82 }
83 pkg.objects[obj] = g
84 pkg.Members[name] = g
85
86 case *types.Func:
87 sig := obj.Type().(*types.Signature)
88 if sig.Recv() == nil && name == "init" {
89 pkg.ninit++
90 name = fmt.Sprintf("init#%d", pkg.ninit)
91 }
92
93
94 var tparams *typeparams.TypeParamList
95 if rtparams := typeparams.RecvTypeParams(sig); rtparams.Len() > 0 {
96 tparams = rtparams
97 } else if sigparams := typeparams.ForSignature(sig); sigparams.Len() > 0 {
98 tparams = sigparams
99 }
100
101 fn := &Function{
102 name: name,
103 object: obj,
104 Signature: sig,
105 syntax: syntax,
106 pos: obj.Pos(),
107 Pkg: pkg,
108 Prog: pkg.Prog,
109 typeparams: tparams,
110 info: pkg.info,
111 }
112 pkg.created.Add(fn)
113 if syntax == nil {
114 fn.Synthetic = "loaded from gc object file"
115 }
116 if tparams.Len() > 0 {
117 fn.Prog.createInstanceSet(fn)
118 }
119
120 pkg.objects[obj] = fn
121 if sig.Recv() == nil {
122 pkg.Members[name] = fn
123 }
124
125 default:
126 panic("unexpected Object type: " + obj.String())
127 }
128 }
129
130
131
132
133 func membersFromDecl(pkg *Package, decl ast.Decl) {
134 switch decl := decl.(type) {
135 case *ast.GenDecl:
136 switch decl.Tok {
137 case token.CONST:
138 for _, spec := range decl.Specs {
139 for _, id := range spec.(*ast.ValueSpec).Names {
140 if !isBlankIdent(id) {
141 memberFromObject(pkg, pkg.info.Defs[id], nil)
142 }
143 }
144 }
145
146 case token.VAR:
147 for _, spec := range decl.Specs {
148 for _, id := range spec.(*ast.ValueSpec).Names {
149 if !isBlankIdent(id) {
150 memberFromObject(pkg, pkg.info.Defs[id], spec)
151 }
152 }
153 }
154
155 case token.TYPE:
156 for _, spec := range decl.Specs {
157 id := spec.(*ast.TypeSpec).Name
158 if !isBlankIdent(id) {
159 memberFromObject(pkg, pkg.info.Defs[id], nil)
160 }
161 }
162 }
163
164 case *ast.FuncDecl:
165 id := decl.Name
166 if !isBlankIdent(id) {
167 memberFromObject(pkg, pkg.info.Defs[id], decl)
168 }
169 }
170 }
171
172
173
174
175
176
177 type creator []*Function
178
179 func (c *creator) Add(fn *Function) {
180 *c = append(*c, fn)
181 }
182 func (c *creator) At(i int) *Function { return (*c)[i] }
183 func (c *creator) Len() int { return len(*c) }
184
185
186
187
188
189
190
191
192
193
194 func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *types.Info, importable bool) *Package {
195 p := &Package{
196 Prog: prog,
197 Members: make(map[string]Member),
198 objects: make(map[types.Object]Member),
199 Pkg: pkg,
200 info: info,
201 files: files,
202 }
203
204
205 p.init = &Function{
206 name: "init",
207 Signature: new(types.Signature),
208 Synthetic: "package initializer",
209 Pkg: p,
210 Prog: prog,
211 info: p.info,
212 }
213 p.Members[p.init.name] = p.init
214 p.created.Add(p.init)
215
216
217
218 if len(files) > 0 {
219
220 for _, file := range files {
221 for _, decl := range file.Decls {
222 membersFromDecl(p, decl)
223 }
224 }
225 } else {
226
227
228
229 scope := p.Pkg.Scope()
230 for _, name := range scope.Names() {
231 obj := scope.Lookup(name)
232 memberFromObject(p, obj, nil)
233 if obj, ok := obj.(*types.TypeName); ok {
234 if named, ok := obj.Type().(*types.Named); ok {
235 for i, n := 0, named.NumMethods(); i < n; i++ {
236 memberFromObject(p, named.Method(i), nil)
237 }
238 }
239 }
240 }
241 }
242
243 if prog.mode&BareInits == 0 {
244
245 initguard := &Global{
246 Pkg: p,
247 name: "init$guard",
248 typ: types.NewPointer(tBool),
249 }
250 p.Members[initguard.Name()] = initguard
251 }
252
253 if prog.mode&GlobalDebug != 0 {
254 p.SetDebugMode(true)
255 }
256
257 if prog.mode&PrintPackages != 0 {
258 printMu.Lock()
259 p.WriteTo(os.Stdout)
260 printMu.Unlock()
261 }
262
263 if importable {
264 prog.imported[p.Pkg.Path()] = p
265 }
266 prog.packages[p.Pkg] = p
267
268 return p
269 }
270
271
272 var printMu sync.Mutex
273
274
275
276 func (prog *Program) AllPackages() []*Package {
277 pkgs := make([]*Package, 0, len(prog.packages))
278 for _, pkg := range prog.packages {
279 pkgs = append(pkgs, pkg)
280 }
281 return pkgs
282 }
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297 func (prog *Program) ImportedPackage(path string) *Package {
298 return prog.imported[path]
299 }
300
View as plain text