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