Source file
src/cmd/cgo/ast.go
1
2
3
4
5
6
7 package main
8
9 import (
10 "fmt"
11 "go/ast"
12 "go/format"
13 "go/parser"
14 "go/scanner"
15 "go/token"
16 "os"
17 "strings"
18 )
19
20 func parse(name string, src []byte, flags parser.Mode) *ast.File {
21 ast1, err := parser.ParseFile(fset, name, src, flags)
22 if err != nil {
23 if list, ok := err.(scanner.ErrorList); ok {
24
25
26
27
28 for _, e := range list {
29 fmt.Fprintln(os.Stderr, e)
30 }
31 os.Exit(2)
32 }
33 fatalf("parsing %s: %s", name, err)
34 }
35 return ast1
36 }
37
38 func sourceLine(n ast.Node) int {
39 return fset.Position(n.Pos()).Line
40 }
41
42
43
44
45
46
47 func (f *File) ParseGo(abspath string, src []byte) {
48
49
50
51
52
53
54
55
56 ast1 := parse(abspath, src, parser.SkipObjectResolution|parser.ParseComments)
57 ast2 := parse(abspath, src, parser.SkipObjectResolution)
58
59 f.Package = ast1.Name.Name
60 f.Name = make(map[string]*Name)
61 f.NamePos = make(map[*Name]token.Pos)
62
63
64 sawC := false
65 for _, decl := range ast1.Decls {
66 switch decl := decl.(type) {
67 case *ast.GenDecl:
68 for _, spec := range decl.Specs {
69 s, ok := spec.(*ast.ImportSpec)
70 if !ok || s.Path.Value != `"C"` {
71 continue
72 }
73 sawC = true
74 if s.Name != nil {
75 error_(s.Path.Pos(), `cannot rename import "C"`)
76 }
77 cg := s.Doc
78 if cg == nil && len(decl.Specs) == 1 {
79 cg = decl.Doc
80 }
81 if cg != nil {
82 f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), abspath)
83 f.Preamble += commentText(cg) + "\n"
84 f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
85 }
86 }
87
88 case *ast.FuncDecl:
89
90
91
92 if decl.Recv != nil && len(decl.Recv.List) > 0 {
93 recvType := decl.Recv.List[0].Type
94 if recvType != nil {
95 t := recvType
96 if star, ok := unparen(t).(*ast.StarExpr); ok {
97 t = star.X
98 }
99 if sel, ok := unparen(t).(*ast.SelectorExpr); ok {
100 var buf strings.Builder
101 format.Node(&buf, fset, recvType)
102 error_(sel.Pos(), `cannot define new methods on non-local type %s`, &buf)
103 }
104 }
105 }
106 }
107
108 }
109 if !sawC {
110 error_(ast1.Package, `cannot find import "C"`)
111 }
112
113
114 if *godefs {
115 w := 0
116 for _, decl := range ast2.Decls {
117 d, ok := decl.(*ast.GenDecl)
118 if !ok {
119 ast2.Decls[w] = decl
120 w++
121 continue
122 }
123 ws := 0
124 for _, spec := range d.Specs {
125 s, ok := spec.(*ast.ImportSpec)
126 if !ok || s.Path.Value != `"C"` {
127 d.Specs[ws] = spec
128 ws++
129 }
130 }
131 if ws == 0 {
132 continue
133 }
134 d.Specs = d.Specs[0:ws]
135 ast2.Decls[w] = d
136 w++
137 }
138 ast2.Decls = ast2.Decls[0:w]
139 } else {
140 for _, decl := range ast2.Decls {
141 d, ok := decl.(*ast.GenDecl)
142 if !ok {
143 continue
144 }
145 for _, spec := range d.Specs {
146 if s, ok := spec.(*ast.ImportSpec); ok && s.Path.Value == `"C"` {
147
148
149
150 f.Edit.Replace(f.offset(s.Path.Pos()), f.offset(s.Path.End()), `_ "unsafe"`)
151 }
152 }
153 }
154 }
155
156
157 if f.Ref == nil {
158 f.Ref = make([]*Ref, 0, 8)
159 }
160 f.walk(ast2, ctxProg, (*File).validateIdents)
161 f.walk(ast2, ctxProg, (*File).saveExprs)
162
163
164
165
166
167
168
169 f.walk(ast1, ctxProg, (*File).saveExport)
170 f.walk(ast2, ctxProg, (*File).saveExport2)
171
172 f.Comments = ast1.Comments
173 f.AST = ast2
174 }
175
176
177
178 func commentText(g *ast.CommentGroup) string {
179 var pieces []string
180 for _, com := range g.List {
181 c := com.Text
182
183
184 switch c[1] {
185 case '/':
186
187 c = c[2:] + "\n"
188 case '*':
189
190 c = c[2 : len(c)-2]
191 }
192 pieces = append(pieces, c)
193 }
194 return strings.Join(pieces, "")
195 }
196
197 func (f *File) validateIdents(x interface{}, context astContext) {
198 if x, ok := x.(*ast.Ident); ok {
199 if f.isMangledName(x.Name) {
200 error_(x.Pos(), "identifier %q may conflict with identifiers generated by cgo", x.Name)
201 }
202 }
203 }
204
205
206 func (f *File) saveExprs(x interface{}, context astContext) {
207 switch x := x.(type) {
208 case *ast.Expr:
209 switch (*x).(type) {
210 case *ast.SelectorExpr:
211 f.saveRef(x, context)
212 }
213 case *ast.CallExpr:
214 f.saveCall(x, context)
215 }
216 }
217
218
219 func (f *File) saveRef(n *ast.Expr, context astContext) {
220 sel := (*n).(*ast.SelectorExpr)
221
222
223
224
225
226 if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
227 return
228 }
229 if context == ctxAssign2 {
230 context = ctxExpr
231 }
232 if context == ctxEmbedType {
233 error_(sel.Pos(), "cannot embed C type")
234 }
235 goname := sel.Sel.Name
236 if goname == "errno" {
237 error_(sel.Pos(), "cannot refer to errno directly; see documentation")
238 return
239 }
240 if goname == "_CMalloc" {
241 error_(sel.Pos(), "cannot refer to C._CMalloc; use C.malloc")
242 return
243 }
244 if goname == "malloc" {
245 goname = "_CMalloc"
246 }
247 name := f.Name[goname]
248 if name == nil {
249 name = &Name{
250 Go: goname,
251 }
252 f.Name[goname] = name
253 f.NamePos[name] = sel.Pos()
254 }
255 f.Ref = append(f.Ref, &Ref{
256 Name: name,
257 Expr: n,
258 Context: context,
259 })
260 }
261
262
263 func (f *File) saveCall(call *ast.CallExpr, context astContext) {
264 sel, ok := call.Fun.(*ast.SelectorExpr)
265 if !ok {
266 return
267 }
268 if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
269 return
270 }
271 c := &Call{Call: call, Deferred: context == ctxDefer}
272 f.Calls = append(f.Calls, c)
273 }
274
275
276 func (f *File) saveExport(x interface{}, context astContext) {
277 n, ok := x.(*ast.FuncDecl)
278 if !ok {
279 return
280 }
281
282 if n.Doc == nil {
283 return
284 }
285 for _, c := range n.Doc.List {
286 if !strings.HasPrefix(c.Text, "//export ") {
287 continue
288 }
289
290 name := strings.TrimSpace(c.Text[9:])
291 if name == "" {
292 error_(c.Pos(), "export missing name")
293 }
294
295 if name != n.Name.Name {
296 error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
297 }
298
299 doc := ""
300 for _, c1 := range n.Doc.List {
301 if c1 != c {
302 doc += c1.Text + "\n"
303 }
304 }
305
306 f.ExpFunc = append(f.ExpFunc, &ExpFunc{
307 Func: n,
308 ExpName: name,
309 Doc: doc,
310 })
311 break
312 }
313 }
314
315
316 func (f *File) saveExport2(x interface{}, context astContext) {
317 n, ok := x.(*ast.FuncDecl)
318 if !ok {
319 return
320 }
321
322 for _, exp := range f.ExpFunc {
323 if exp.Func.Name.Name == n.Name.Name {
324 exp.Func = n
325 break
326 }
327 }
328 }
329
330 type astContext int
331
332 const (
333 ctxProg astContext = iota
334 ctxEmbedType
335 ctxType
336 ctxStmt
337 ctxExpr
338 ctxField
339 ctxParam
340 ctxAssign2
341 ctxSwitch
342 ctxTypeSwitch
343 ctxFile
344 ctxDecl
345 ctxSpec
346 ctxDefer
347 ctxCall
348 ctxCall2
349 ctxSelector
350 )
351
352
353 func (f *File) walk(x interface{}, context astContext, visit func(*File, interface{}, astContext)) {
354 visit(f, x, context)
355 switch n := x.(type) {
356 case *ast.Expr:
357 f.walk(*n, context, visit)
358
359
360 default:
361 f.walkUnexpected(x, context, visit)
362
363 case nil:
364
365
366 case *ast.Field:
367 if len(n.Names) == 0 && context == ctxField {
368 f.walk(&n.Type, ctxEmbedType, visit)
369 } else {
370 f.walk(&n.Type, ctxType, visit)
371 }
372 case *ast.FieldList:
373 for _, field := range n.List {
374 f.walk(field, context, visit)
375 }
376 case *ast.BadExpr:
377 case *ast.Ident:
378 case *ast.Ellipsis:
379 f.walk(&n.Elt, ctxType, visit)
380 case *ast.BasicLit:
381 case *ast.FuncLit:
382 f.walk(n.Type, ctxType, visit)
383 f.walk(n.Body, ctxStmt, visit)
384 case *ast.CompositeLit:
385 f.walk(&n.Type, ctxType, visit)
386 f.walk(n.Elts, ctxExpr, visit)
387 case *ast.ParenExpr:
388 f.walk(&n.X, context, visit)
389 case *ast.SelectorExpr:
390 f.walk(&n.X, ctxSelector, visit)
391 case *ast.IndexExpr:
392 f.walk(&n.X, ctxExpr, visit)
393 f.walk(&n.Index, ctxExpr, visit)
394 case *ast.SliceExpr:
395 f.walk(&n.X, ctxExpr, visit)
396 if n.Low != nil {
397 f.walk(&n.Low, ctxExpr, visit)
398 }
399 if n.High != nil {
400 f.walk(&n.High, ctxExpr, visit)
401 }
402 if n.Max != nil {
403 f.walk(&n.Max, ctxExpr, visit)
404 }
405 case *ast.TypeAssertExpr:
406 f.walk(&n.X, ctxExpr, visit)
407 f.walk(&n.Type, ctxType, visit)
408 case *ast.CallExpr:
409 if context == ctxAssign2 {
410 f.walk(&n.Fun, ctxCall2, visit)
411 } else {
412 f.walk(&n.Fun, ctxCall, visit)
413 }
414 f.walk(n.Args, ctxExpr, visit)
415 case *ast.StarExpr:
416 f.walk(&n.X, context, visit)
417 case *ast.UnaryExpr:
418 f.walk(&n.X, ctxExpr, visit)
419 case *ast.BinaryExpr:
420 f.walk(&n.X, ctxExpr, visit)
421 f.walk(&n.Y, ctxExpr, visit)
422 case *ast.KeyValueExpr:
423 f.walk(&n.Key, ctxExpr, visit)
424 f.walk(&n.Value, ctxExpr, visit)
425
426 case *ast.ArrayType:
427 f.walk(&n.Len, ctxExpr, visit)
428 f.walk(&n.Elt, ctxType, visit)
429 case *ast.StructType:
430 f.walk(n.Fields, ctxField, visit)
431 case *ast.FuncType:
432 if tparams := funcTypeTypeParams(n); tparams != nil {
433 f.walk(tparams, ctxParam, visit)
434 }
435 f.walk(n.Params, ctxParam, visit)
436 if n.Results != nil {
437 f.walk(n.Results, ctxParam, visit)
438 }
439 case *ast.InterfaceType:
440 f.walk(n.Methods, ctxField, visit)
441 case *ast.MapType:
442 f.walk(&n.Key, ctxType, visit)
443 f.walk(&n.Value, ctxType, visit)
444 case *ast.ChanType:
445 f.walk(&n.Value, ctxType, visit)
446
447 case *ast.BadStmt:
448 case *ast.DeclStmt:
449 f.walk(n.Decl, ctxDecl, visit)
450 case *ast.EmptyStmt:
451 case *ast.LabeledStmt:
452 f.walk(n.Stmt, ctxStmt, visit)
453 case *ast.ExprStmt:
454 f.walk(&n.X, ctxExpr, visit)
455 case *ast.SendStmt:
456 f.walk(&n.Chan, ctxExpr, visit)
457 f.walk(&n.Value, ctxExpr, visit)
458 case *ast.IncDecStmt:
459 f.walk(&n.X, ctxExpr, visit)
460 case *ast.AssignStmt:
461 f.walk(n.Lhs, ctxExpr, visit)
462 if len(n.Lhs) == 2 && len(n.Rhs) == 1 {
463 f.walk(n.Rhs, ctxAssign2, visit)
464 } else {
465 f.walk(n.Rhs, ctxExpr, visit)
466 }
467 case *ast.GoStmt:
468 f.walk(n.Call, ctxExpr, visit)
469 case *ast.DeferStmt:
470 f.walk(n.Call, ctxDefer, visit)
471 case *ast.ReturnStmt:
472 f.walk(n.Results, ctxExpr, visit)
473 case *ast.BranchStmt:
474 case *ast.BlockStmt:
475 f.walk(n.List, context, visit)
476 case *ast.IfStmt:
477 f.walk(n.Init, ctxStmt, visit)
478 f.walk(&n.Cond, ctxExpr, visit)
479 f.walk(n.Body, ctxStmt, visit)
480 f.walk(n.Else, ctxStmt, visit)
481 case *ast.CaseClause:
482 if context == ctxTypeSwitch {
483 context = ctxType
484 } else {
485 context = ctxExpr
486 }
487 f.walk(n.List, context, visit)
488 f.walk(n.Body, ctxStmt, visit)
489 case *ast.SwitchStmt:
490 f.walk(n.Init, ctxStmt, visit)
491 f.walk(&n.Tag, ctxExpr, visit)
492 f.walk(n.Body, ctxSwitch, visit)
493 case *ast.TypeSwitchStmt:
494 f.walk(n.Init, ctxStmt, visit)
495 f.walk(n.Assign, ctxStmt, visit)
496 f.walk(n.Body, ctxTypeSwitch, visit)
497 case *ast.CommClause:
498 f.walk(n.Comm, ctxStmt, visit)
499 f.walk(n.Body, ctxStmt, visit)
500 case *ast.SelectStmt:
501 f.walk(n.Body, ctxStmt, visit)
502 case *ast.ForStmt:
503 f.walk(n.Init, ctxStmt, visit)
504 f.walk(&n.Cond, ctxExpr, visit)
505 f.walk(n.Post, ctxStmt, visit)
506 f.walk(n.Body, ctxStmt, visit)
507 case *ast.RangeStmt:
508 f.walk(&n.Key, ctxExpr, visit)
509 f.walk(&n.Value, ctxExpr, visit)
510 f.walk(&n.X, ctxExpr, visit)
511 f.walk(n.Body, ctxStmt, visit)
512
513 case *ast.ImportSpec:
514 case *ast.ValueSpec:
515 f.walk(&n.Type, ctxType, visit)
516 if len(n.Names) == 2 && len(n.Values) == 1 {
517 f.walk(&n.Values[0], ctxAssign2, visit)
518 } else {
519 f.walk(n.Values, ctxExpr, visit)
520 }
521 case *ast.TypeSpec:
522 if tparams := typeSpecTypeParams(n); tparams != nil {
523 f.walk(tparams, ctxParam, visit)
524 }
525 f.walk(&n.Type, ctxType, visit)
526
527 case *ast.BadDecl:
528 case *ast.GenDecl:
529 f.walk(n.Specs, ctxSpec, visit)
530 case *ast.FuncDecl:
531 if n.Recv != nil {
532 f.walk(n.Recv, ctxParam, visit)
533 }
534 f.walk(n.Type, ctxType, visit)
535 if n.Body != nil {
536 f.walk(n.Body, ctxStmt, visit)
537 }
538
539 case *ast.File:
540 f.walk(n.Decls, ctxDecl, visit)
541
542 case *ast.Package:
543 for _, file := range n.Files {
544 f.walk(file, ctxFile, visit)
545 }
546
547 case []ast.Decl:
548 for _, d := range n {
549 f.walk(d, context, visit)
550 }
551 case []ast.Expr:
552 for i := range n {
553 f.walk(&n[i], context, visit)
554 }
555 case []ast.Stmt:
556 for _, s := range n {
557 f.walk(s, context, visit)
558 }
559 case []ast.Spec:
560 for _, s := range n {
561 f.walk(s, context, visit)
562 }
563 }
564 }
565
566
567 func unparen(x ast.Expr) ast.Expr {
568 if p, isParen := x.(*ast.ParenExpr); isParen {
569 x = unparen(p.X)
570 }
571 return x
572 }
573
View as plain text