1
2
3
4
5
6
7 package analysisinternal
8
9 import (
10 "bytes"
11 "fmt"
12 "go/ast"
13 "go/token"
14 "go/types"
15 "strconv"
16 )
17
18 func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos {
19
20 offset, end := fset.PositionFor(start, false).Offset, start
21 if offset >= len(src) {
22 return end
23 }
24 if width := bytes.IndexAny(src[offset:], " \n,():;[]+-*"); width > 0 {
25 end = start + token.Pos(width)
26 }
27 return end
28 }
29
30 func ZeroValue(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
31 under := typ
32 if n, ok := typ.(*types.Named); ok {
33 under = n.Underlying()
34 }
35 switch u := under.(type) {
36 case *types.Basic:
37 switch {
38 case u.Info()&types.IsNumeric != 0:
39 return &ast.BasicLit{Kind: token.INT, Value: "0"}
40 case u.Info()&types.IsBoolean != 0:
41 return &ast.Ident{Name: "false"}
42 case u.Info()&types.IsString != 0:
43 return &ast.BasicLit{Kind: token.STRING, Value: `""`}
44 default:
45 panic(fmt.Sprintf("unknown basic type %v", u))
46 }
47 case *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Signature, *types.Slice, *types.Array:
48 return ast.NewIdent("nil")
49 case *types.Struct:
50 texpr := TypeExpr(f, pkg, typ)
51 if texpr == nil {
52 return nil
53 }
54 return &ast.CompositeLit{
55 Type: texpr,
56 }
57 }
58 return nil
59 }
60
61
62
63 func IsZeroValue(expr ast.Expr) bool {
64 switch e := expr.(type) {
65 case *ast.BasicLit:
66 return e.Value == "0" || e.Value == `""`
67 case *ast.Ident:
68 return e.Name == "nil" || e.Name == "false"
69 default:
70 return false
71 }
72 }
73
74
75
76
77 func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
78 switch t := typ.(type) {
79 case *types.Basic:
80 switch t.Kind() {
81 case types.UnsafePointer:
82 return &ast.SelectorExpr{X: ast.NewIdent("unsafe"), Sel: ast.NewIdent("Pointer")}
83 default:
84 return ast.NewIdent(t.Name())
85 }
86 case *types.Pointer:
87 x := TypeExpr(f, pkg, t.Elem())
88 if x == nil {
89 return nil
90 }
91 return &ast.UnaryExpr{
92 Op: token.MUL,
93 X: x,
94 }
95 case *types.Array:
96 elt := TypeExpr(f, pkg, t.Elem())
97 if elt == nil {
98 return nil
99 }
100 return &ast.ArrayType{
101 Len: &ast.BasicLit{
102 Kind: token.INT,
103 Value: fmt.Sprintf("%d", t.Len()),
104 },
105 Elt: elt,
106 }
107 case *types.Slice:
108 elt := TypeExpr(f, pkg, t.Elem())
109 if elt == nil {
110 return nil
111 }
112 return &ast.ArrayType{
113 Elt: elt,
114 }
115 case *types.Map:
116 key := TypeExpr(f, pkg, t.Key())
117 value := TypeExpr(f, pkg, t.Elem())
118 if key == nil || value == nil {
119 return nil
120 }
121 return &ast.MapType{
122 Key: key,
123 Value: value,
124 }
125 case *types.Chan:
126 dir := ast.ChanDir(t.Dir())
127 if t.Dir() == types.SendRecv {
128 dir = ast.SEND | ast.RECV
129 }
130 value := TypeExpr(f, pkg, t.Elem())
131 if value == nil {
132 return nil
133 }
134 return &ast.ChanType{
135 Dir: dir,
136 Value: value,
137 }
138 case *types.Signature:
139 var params []*ast.Field
140 for i := 0; i < t.Params().Len(); i++ {
141 p := TypeExpr(f, pkg, t.Params().At(i).Type())
142 if p == nil {
143 return nil
144 }
145 params = append(params, &ast.Field{
146 Type: p,
147 Names: []*ast.Ident{
148 {
149 Name: t.Params().At(i).Name(),
150 },
151 },
152 })
153 }
154 var returns []*ast.Field
155 for i := 0; i < t.Results().Len(); i++ {
156 r := TypeExpr(f, pkg, t.Results().At(i).Type())
157 if r == nil {
158 return nil
159 }
160 returns = append(returns, &ast.Field{
161 Type: r,
162 })
163 }
164 return &ast.FuncType{
165 Params: &ast.FieldList{
166 List: params,
167 },
168 Results: &ast.FieldList{
169 List: returns,
170 },
171 }
172 case *types.Named:
173 if t.Obj().Pkg() == nil {
174 return ast.NewIdent(t.Obj().Name())
175 }
176 if t.Obj().Pkg() == pkg {
177 return ast.NewIdent(t.Obj().Name())
178 }
179 pkgName := t.Obj().Pkg().Name()
180
181
182 for _, cand := range f.Imports {
183 if path, _ := strconv.Unquote(cand.Path.Value); path == t.Obj().Pkg().Path() {
184 if cand.Name != nil && cand.Name.Name != "" {
185 pkgName = cand.Name.Name
186 }
187 }
188 }
189 if pkgName == "." {
190 return ast.NewIdent(t.Obj().Name())
191 }
192 return &ast.SelectorExpr{
193 X: ast.NewIdent(pkgName),
194 Sel: ast.NewIdent(t.Obj().Name()),
195 }
196 case *types.Struct:
197 return ast.NewIdent(t.String())
198 case *types.Interface:
199 return ast.NewIdent(t.String())
200 default:
201 return nil
202 }
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220 func StmtToInsertVarBefore(path []ast.Node) ast.Stmt {
221 enclosingIndex := -1
222 for i, p := range path {
223 if _, ok := p.(ast.Stmt); ok {
224 enclosingIndex = i
225 break
226 }
227 }
228 if enclosingIndex == -1 {
229 return nil
230 }
231 enclosingStmt := path[enclosingIndex]
232 switch enclosingStmt.(type) {
233 case *ast.IfStmt:
234
235
236
237 return baseIfStmt(path, enclosingIndex)
238 case *ast.CaseClause:
239
240
241 for i := enclosingIndex + 1; i < len(path); i++ {
242 if node, ok := path[i].(*ast.SwitchStmt); ok {
243 return node
244 } else if node, ok := path[i].(*ast.TypeSwitchStmt); ok {
245 return node
246 }
247 }
248 }
249 if len(path) <= enclosingIndex+1 {
250 return enclosingStmt.(ast.Stmt)
251 }
252
253 switch expr := path[enclosingIndex+1].(type) {
254 case *ast.IfStmt:
255
256 return baseIfStmt(path, enclosingIndex+1)
257 case *ast.ForStmt:
258 if expr.Init == enclosingStmt || expr.Post == enclosingStmt {
259 return expr
260 }
261 }
262 return enclosingStmt.(ast.Stmt)
263 }
264
265
266
267 func baseIfStmt(path []ast.Node, index int) ast.Stmt {
268 stmt := path[index]
269 for i := index + 1; i < len(path); i++ {
270 if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt {
271 stmt = node
272 continue
273 }
274 break
275 }
276 return stmt.(ast.Stmt)
277 }
278
279
280
281 func WalkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) {
282 var ancestors []ast.Node
283 ast.Inspect(n, func(n ast.Node) (recurse bool) {
284 if n == nil {
285 ancestors = ancestors[:len(ancestors)-1]
286 return false
287 }
288
289 var parent ast.Node
290 if len(ancestors) > 0 {
291 parent = ancestors[len(ancestors)-1]
292 }
293 ancestors = append(ancestors, n)
294 return f(n, parent)
295 })
296 }
297
298
299
300
301
302 func MatchingIdents(typs []types.Type, node ast.Node, pos token.Pos, info *types.Info, pkg *types.Package) map[types.Type][]string {
303
304
305 matches := make(map[types.Type][]string)
306 for _, typ := range typs {
307 if typ == nil {
308 continue
309 }
310 matches[typ] = nil
311 }
312
313 seen := map[types.Object]struct{}{}
314 ast.Inspect(node, func(n ast.Node) bool {
315 if n == nil {
316 return false
317 }
318
319
320
321
322
323
324 if assign, ok := n.(*ast.AssignStmt); ok && pos > assign.Pos() && pos <= assign.End() {
325 return false
326 }
327 if n.End() > pos {
328 return n.Pos() <= pos
329 }
330 ident, ok := n.(*ast.Ident)
331 if !ok || ident.Name == "_" {
332 return true
333 }
334 obj := info.Defs[ident]
335 if obj == nil || obj.Type() == nil {
336 return true
337 }
338 if _, ok := obj.(*types.TypeName); ok {
339 return true
340 }
341
342 if _, ok = seen[obj]; ok {
343 return true
344 }
345 seen[obj] = struct{}{}
346
347
348 innerScope := pkg.Scope().Innermost(pos)
349 if innerScope == nil {
350 return true
351 }
352 _, foundObj := innerScope.LookupParent(ident.Name, pos)
353 if foundObj != obj {
354 return true
355 }
356
357
358 if names, ok := matches[obj.Type()]; ok {
359 matches[obj.Type()] = append(names, ident.Name)
360 } else {
361
362
363
364 for typ := range matches {
365 if equivalentTypes(obj.Type(), typ) {
366 matches[typ] = append(matches[typ], ident.Name)
367 }
368 }
369 }
370 return true
371 })
372 return matches
373 }
374
375 func equivalentTypes(want, got types.Type) bool {
376 if types.Identical(want, got) {
377 return true
378 }
379
380 if rhs, ok := want.(*types.Basic); ok && rhs.Info()&types.IsUntyped > 0 {
381 if lhs, ok := got.Underlying().(*types.Basic); ok {
382 return rhs.Info()&types.IsConstType == lhs.Info()&types.IsConstType
383 }
384 }
385 return types.AssignableTo(want, got)
386 }
387
View as plain text