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 if strings.ContainsAny(abspath, "\r\n") {
83
84
85 fatalf("internal error: ParseGo: abspath contains unexpected newline character: %q", abspath)
86 }
87 f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), abspath)
88 f.Preamble += commentText(cg) + "\n"
89 f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
90 }
91 }
92
93 case *ast.FuncDecl:
94
95
96
97 if decl.Recv != nil && len(decl.Recv.List) > 0 {
98 recvType := decl.Recv.List[0].Type
99 if recvType != nil {
100 t := recvType
101 if star, ok := unparen(t).(*ast.StarExpr); ok {
102 t = star.X
103 }
104 if sel, ok := unparen(t).(*ast.SelectorExpr); ok {
105 var buf strings.Builder
106 format.Node(&buf, fset, recvType)
107 error_(sel.Pos(), `cannot define new methods on non-local type %s`, &buf)
108 }
109 }
110 }
111 }
112
113 }
114 if !sawC {
115 error_(ast1.Package, `cannot find import "C"`)
116 }
117
118
119 if *godefs {
120 w := 0
121 for _, decl := range ast2.Decls {
122 d, ok := decl.(*ast.GenDecl)
123 if !ok {
124 ast2.Decls[w] = decl
125 w++
126 continue
127 }
128 ws := 0
129 for _, spec := range d.Specs {
130 s, ok := spec.(*ast.ImportSpec)
131 if !ok || s.Path.Value != `"C"` {
132 d.Specs[ws] = spec
133 ws++
134 }
135 }
136 if ws == 0 {
137 continue
138 }
139 d.Specs = d.Specs[0:ws]
140 ast2.Decls[w] = d
141 w++
142 }
143 ast2.Decls = ast2.Decls[0:w]
144 } else {
145 for _, decl := range ast2.Decls {
146 d, ok := decl.(*ast.GenDecl)
147 if !ok {
148 continue
149 }
150 for _, spec := range d.Specs {
151 if s, ok := spec.(*ast.ImportSpec); ok && s.Path.Value == `"C"` {
152
153
154
155 f.Edit.Replace(f.offset(s.Path.Pos()), f.offset(s.Path.End()), `_ "unsafe"`)
156 }
157 }
158 }
159 }
160
161
162 if f.Ref == nil {
163 f.Ref = make([]*Ref, 0, 8)
164 }
165 f.walk(ast2, ctxProg, (*File).validateIdents)
166 f.walk(ast2, ctxProg, (*File).saveExprs)
167
168
169
170
171
172
173
174 f.walk(ast1, ctxProg, (*File).saveExport)
175 f.walk(ast2, ctxProg, (*File).saveExport2)
176
177 f.Comments = ast1.Comments
178 f.AST = ast2
179 }
180
181
182
183 func commentText(g *ast.CommentGroup) string {
184 pieces := make([]string, 0, len(g.List))
185 for _, com := range g.List {
186 c := com.Text
187
188
189 switch c[1] {
190 case '/':
191
192 c = c[2:] + "\n"
193 case '*':
194
195 c = c[2 : len(c)-2]
196 }
197 pieces = append(pieces, c)
198 }
199 return strings.Join(pieces, "")
200 }
201
202 func (f *File) validateIdents(x interface{}, context astContext) {
203 if x, ok := x.(*ast.Ident); ok {
204 if f.isMangledName(x.Name) {
205 error_(x.Pos(), "identifier %q may conflict with identifiers generated by cgo", x.Name)
206 }
207 }
208 }
209
210
211 func (f *File) saveExprs(x interface{}, context astContext) {
212 switch x := x.(type) {
213 case *ast.Expr:
214 switch (*x).(type) {
215 case *ast.SelectorExpr:
216 f.saveRef(x, context)
217 }
218 case *ast.CallExpr:
219 f.saveCall(x, context)
220 }
221 }
222
223
224 func (f *File) saveRef(n *ast.Expr, context astContext) {
225 sel := (*n).(*ast.SelectorExpr)
226
227
228
229
230
231 if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
232 return
233 }
234 if context == ctxAssign2 {
235 context = ctxExpr
236 }
237 if context == ctxEmbedType {
238 error_(sel.Pos(), "cannot embed C type")
239 }
240 goname := sel.Sel.Name
241 if goname == "errno" {
242 error_(sel.Pos(), "cannot refer to errno directly; see documentation")
243 return
244 }
245 if goname == "_CMalloc" {
246 error_(sel.Pos(), "cannot refer to C._CMalloc; use C.malloc")
247 return
248 }
249 if goname == "malloc" {
250 goname = "_CMalloc"
251 }
252 name := f.Name[goname]
253 if name == nil {
254 name = &Name{
255 Go: goname,
256 }
257 f.Name[goname] = name
258 f.NamePos[name] = sel.Pos()
259 }
260 f.Ref = append(f.Ref, &Ref{
261 Name: name,
262 Expr: n,
263 Context: context,
264 })
265 }
266
267
268 func (f *File) saveCall(call *ast.CallExpr, context astContext) {
269 sel, ok := call.Fun.(*ast.SelectorExpr)
270 if !ok {
271 return
272 }
273 if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
274 return
275 }
276 c := &Call{Call: call, Deferred: context == ctxDefer}
277 f.Calls = append(f.Calls, c)
278 }
279
280
281 func (f *File) saveExport(x interface{}, context astContext) {
282 n, ok := x.(*ast.FuncDecl)
283 if !ok {
284 return
285 }
286
287 if n.Doc == nil {
288 return
289 }
290 for _, c := range n.Doc.List {
291 if !strings.HasPrefix(c.Text, "//export ") {
292 continue
293 }
294
295 name := strings.TrimSpace(c.Text[9:])
296 if name == "" {
297 error_(c.Pos(), "export missing name")
298 }
299
300 if name != n.Name.Name {
301 error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
302 }
303
304 f.ExpFunc = append(f.ExpFunc, &ExpFunc{
305 Func: n,
306 ExpName: name,
307
308
309
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