1
2
3
4
5 package ssautil
6
7
8
9 import (
10 "go/ast"
11 "go/token"
12 "go/types"
13
14 "golang.org/x/tools/go/loader"
15 "golang.org/x/tools/go/packages"
16 "golang.org/x/tools/go/ssa"
17 "golang.org/x/tools/internal/typeparams"
18 )
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 func Packages(initial []*packages.Package, mode ssa.BuilderMode) (*ssa.Program, []*ssa.Package) {
38 return doPackages(initial, mode, false)
39 }
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 func AllPackages(initial []*packages.Package, mode ssa.BuilderMode) (*ssa.Program, []*ssa.Package) {
59 return doPackages(initial, mode, true)
60 }
61
62 func doPackages(initial []*packages.Package, mode ssa.BuilderMode, deps bool) (*ssa.Program, []*ssa.Package) {
63
64 var fset *token.FileSet
65 if len(initial) > 0 {
66 fset = initial[0].Fset
67 }
68
69 prog := ssa.NewProgram(fset, mode)
70
71 isInitial := make(map[*packages.Package]bool, len(initial))
72 for _, p := range initial {
73 isInitial[p] = true
74 }
75
76 ssamap := make(map[*packages.Package]*ssa.Package)
77 packages.Visit(initial, nil, func(p *packages.Package) {
78 if p.Types != nil && !p.IllTyped {
79 var files []*ast.File
80 var info *types.Info
81 if deps || isInitial[p] {
82 files = p.Syntax
83 info = p.TypesInfo
84 }
85 ssamap[p] = prog.CreatePackage(p.Types, files, info, true)
86 }
87 })
88
89 var ssapkgs []*ssa.Package
90 for _, p := range initial {
91 ssapkgs = append(ssapkgs, ssamap[p])
92 }
93 return prog, ssapkgs
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107 func CreateProgram(lprog *loader.Program, mode ssa.BuilderMode) *ssa.Program {
108 prog := ssa.NewProgram(lprog.Fset, mode)
109
110 for _, info := range lprog.AllPackages {
111 if info.TransitivelyErrorFree {
112 prog.CreatePackage(info.Pkg, info.Files, &info.Info, info.Importable)
113 }
114 }
115
116 return prog
117 }
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 func BuildPackage(tc *types.Config, fset *token.FileSet, pkg *types.Package, files []*ast.File, mode ssa.BuilderMode) (*ssa.Package, *types.Info, error) {
134 if fset == nil {
135 panic("no token.FileSet")
136 }
137 if pkg.Path() == "" {
138 panic("package has no import path")
139 }
140
141 info := &types.Info{
142 Types: make(map[ast.Expr]types.TypeAndValue),
143 Defs: make(map[*ast.Ident]types.Object),
144 Uses: make(map[*ast.Ident]types.Object),
145 Implicits: make(map[ast.Node]types.Object),
146 Scopes: make(map[ast.Node]*types.Scope),
147 Selections: make(map[*ast.SelectorExpr]*types.Selection),
148 }
149 typeparams.InitInstanceInfo(info)
150 if err := types.NewChecker(tc, fset, pkg, info).Files(files); err != nil {
151 return nil, nil, err
152 }
153
154 prog := ssa.NewProgram(fset, mode)
155
156
157
158 created := make(map[*types.Package]bool)
159 var createAll func(pkgs []*types.Package)
160 createAll = func(pkgs []*types.Package) {
161 for _, p := range pkgs {
162 if !created[p] {
163 created[p] = true
164 prog.CreatePackage(p, nil, nil, true)
165 createAll(p.Imports())
166 }
167 }
168 }
169 createAll(pkg.Imports())
170
171
172 ssapkg := prog.CreatePackage(pkg, files, info, false)
173 ssapkg.Build()
174 return ssapkg, info, nil
175 }
176
View as plain text