Source file
src/cmd/fix/cftype.go
1
2
3
4
5 package main
6
7 import (
8 "go/ast"
9 "go/token"
10 "reflect"
11 "strings"
12 )
13
14 func init() {
15 register(cftypeFix)
16 }
17
18 var cftypeFix = fix{
19 name: "cftype",
20 date: "2017-09-27",
21 f: cftypefix,
22 desc: `Fixes initializers and casts of C.*Ref and JNI types`,
23 disabled: false,
24 }
25
26
27
28
29
30
31
32
33
34
35
36 func cftypefix(f *ast.File) bool {
37 return typefix(f, func(s string) bool {
38 return strings.HasPrefix(s, "C.") && strings.HasSuffix(s, "Ref") && s != "C.CFAllocatorRef"
39 })
40 }
41
42
43 func typefix(f *ast.File, badType func(string) bool) bool {
44 if !imports(f, "C") {
45 return false
46 }
47 typeof, _ := typecheck(&TypeConfig{}, f)
48 changed := false
49
50
51
52 badNils := map[any]ast.Expr{}
53 walk(f, func(n any) {
54 if i, ok := n.(*ast.Ident); ok && i.Name == "nil" && badType(typeof[n]) {
55 badNils[n] = &ast.BasicLit{ValuePos: i.NamePos, Kind: token.INT, Value: "0"}
56 }
57 })
58
59
60
61
62 if len(badNils) > 0 {
63 exprType := reflect.TypeFor[ast.Expr]()
64 exprSliceType := reflect.TypeFor[[]ast.Expr]()
65 walk(f, func(n any) {
66 if n == nil {
67 return
68 }
69 v := reflect.ValueOf(n)
70 if v.Type().Kind() != reflect.Pointer {
71 return
72 }
73 if v.IsNil() {
74 return
75 }
76 v = v.Elem()
77 if v.Type().Kind() != reflect.Struct {
78 return
79 }
80 for i := 0; i < v.NumField(); i++ {
81 f := v.Field(i)
82 if f.Type() == exprType {
83 if r := badNils[f.Interface()]; r != nil {
84 f.Set(reflect.ValueOf(r))
85 changed = true
86 }
87 }
88 if f.Type() == exprSliceType {
89 for j := 0; j < f.Len(); j++ {
90 e := f.Index(j)
91 if r := badNils[e.Interface()]; r != nil {
92 e.Set(reflect.ValueOf(r))
93 changed = true
94 }
95 }
96 }
97 }
98 })
99 }
100
101
102
103
104
105
106 walk(f, func(n any) {
107 if n == nil {
108 return
109 }
110
111 c, ok := n.(*ast.CallExpr)
112 if !ok {
113 return
114 }
115 if len(c.Args) != 1 {
116 return
117 }
118 p, ok := c.Fun.(*ast.ParenExpr)
119 if !ok {
120 return
121 }
122 s, ok := p.X.(*ast.StarExpr)
123 if !ok {
124 return
125 }
126 t, ok := s.X.(*ast.SelectorExpr)
127 if !ok {
128 return
129 }
130 pkg, ok := t.X.(*ast.Ident)
131 if !ok {
132 return
133 }
134 dst := pkg.Name + "." + t.Sel.Name
135 src := typeof[c.Args[0]]
136 if badType(dst) && src == "*unsafe.Pointer" ||
137 dst == "unsafe.Pointer" && strings.HasPrefix(src, "*") && badType(src[1:]) {
138 c.Args[0] = &ast.CallExpr{
139 Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "unsafe"}, Sel: &ast.Ident{Name: "Pointer"}},
140 Args: []ast.Expr{c.Args[0]},
141 }
142 changed = true
143 }
144 })
145
146 return changed
147 }
148
View as plain text