@@ -17,37 +17,33 @@ import (
17
17
type fileInfo struct {
18
18
* ast.File
19
19
filename string
20
- functions [ ]* functionInfo
21
- typedefs [] * typedefInfo
22
- globals [] * globalInfo
20
+ functions map [ string ]* functionInfo
21
+ globals map [ string ] * globalInfo
22
+ typedefs map [ string ] * typedefInfo
23
23
importCPos token.Pos
24
24
}
25
25
26
26
// functionInfo stores some information about a Cgo function found by libclang
27
27
// and declared in the AST.
28
28
type functionInfo struct {
29
- name string
30
- args []paramInfo
31
- result string
29
+ args []paramInfo
30
+ results * ast.FieldList
32
31
}
33
32
34
33
// paramInfo is a parameter of a Cgo function (see functionInfo).
35
34
type paramInfo struct {
36
35
name string
37
- typeName string
36
+ typeExpr ast. Expr
38
37
}
39
38
40
39
// typedefInfo contains information about a single typedef in C.
41
40
type typedefInfo struct {
42
- newName string // newly defined type name
43
- oldName string // old type name, may be something like "unsigned long long"
44
- size int // size in bytes
41
+ typeExpr ast.Expr
45
42
}
46
43
47
44
// globalInfo contains information about a declared global variable in C.
48
45
type globalInfo struct {
49
- name string
50
- typeName string
46
+ typeExpr ast.Expr
51
47
}
52
48
53
49
// cgoAliases list type aliases between Go and C, for types that are equivalent
@@ -84,8 +80,11 @@ typedef unsigned long long _Cgo_ulonglong;
84
80
// comment with libclang, and modifies the AST to use this information.
85
81
func (p * Package ) processCgo (filename string , f * ast.File , cflags []string ) error {
86
82
info := & fileInfo {
87
- File : f ,
88
- filename : filename ,
83
+ File : f ,
84
+ filename : filename ,
85
+ functions : map [string ]* functionInfo {},
86
+ globals : map [string ]* globalInfo {},
87
+ typedefs : map [string ]* typedefInfo {},
89
88
}
90
89
91
90
// Find `import "C"` statements in the file.
@@ -151,16 +150,22 @@ func (p *Package) processCgo(filename string, f *ast.File, cflags []string) erro
151
150
func (info * fileInfo ) addFuncDecls () {
152
151
// TODO: replace all uses of importCPos with the real locations from
153
152
// libclang.
154
- for _ , fn := range info .functions {
153
+ names := make ([]string , 0 , len (info .functions ))
154
+ for name := range info .functions {
155
+ names = append (names , name )
156
+ }
157
+ sort .Strings (names )
158
+ for _ , name := range names {
159
+ fn := info .functions [name ]
155
160
obj := & ast.Object {
156
161
Kind : ast .Fun ,
157
- Name : mapCgoType ( fn . name ) ,
162
+ Name : "C." + name ,
158
163
}
159
164
args := make ([]* ast.Field , len (fn .args ))
160
165
decl := & ast.FuncDecl {
161
166
Name : & ast.Ident {
162
167
NamePos : info .importCPos ,
163
- Name : mapCgoType ( fn . name ) ,
168
+ Name : "C." + name ,
164
169
Obj : obj ,
165
170
},
166
171
Type : & ast.FuncType {
@@ -170,16 +175,7 @@ func (info *fileInfo) addFuncDecls() {
170
175
List : args ,
171
176
Closing : info .importCPos ,
172
177
},
173
- Results : & ast.FieldList {
174
- List : []* ast.Field {
175
- & ast.Field {
176
- Type : & ast.Ident {
177
- NamePos : info .importCPos ,
178
- Name : mapCgoType (fn .result ),
179
- },
180
- },
181
- },
182
- },
178
+ Results : fn .results ,
183
179
},
184
180
}
185
181
obj .Decl = decl
@@ -191,15 +187,12 @@ func (info *fileInfo) addFuncDecls() {
191
187
Name : arg .name ,
192
188
Obj : & ast.Object {
193
189
Kind : ast .Var ,
194
- Name : mapCgoType ( arg .name ) ,
190
+ Name : arg .name ,
195
191
Decl : decl ,
196
192
},
197
193
},
198
194
},
199
- Type : & ast.Ident {
200
- NamePos : info .importCPos ,
201
- Name : mapCgoType (arg .typeName ),
202
- },
195
+ Type : arg .typeExpr ,
203
196
}
204
197
}
205
198
info .Decls = append (info .Decls , decl )
@@ -221,21 +214,24 @@ func (info *fileInfo) addVarDecls() {
221
214
Lparen : info .importCPos ,
222
215
Rparen : info .importCPos ,
223
216
}
224
- for _ , global := range info .globals {
217
+ names := make ([]string , 0 , len (info .globals ))
218
+ for name := range info .globals {
219
+ names = append (names , name )
220
+ }
221
+ sort .Strings (names )
222
+ for _ , name := range names {
223
+ global := info .globals [name ]
225
224
obj := & ast.Object {
226
225
Kind : ast .Typ ,
227
- Name : mapCgoType ( global . name ) ,
226
+ Name : "C." + name ,
228
227
}
229
228
valueSpec := & ast.ValueSpec {
230
229
Names : []* ast.Ident {& ast.Ident {
231
230
NamePos : info .importCPos ,
232
- Name : mapCgoType ( global . name ) ,
231
+ Name : "C." + name ,
233
232
Obj : obj ,
234
233
}},
235
- Type : & ast.Ident {
236
- NamePos : info .importCPos ,
237
- Name : mapCgoType (global .typeName ),
238
- },
234
+ Type : global .typeExpr ,
239
235
}
240
236
obj .Decl = valueSpec
241
237
gen .Specs = append (gen .Specs , valueSpec )
@@ -292,55 +288,32 @@ func (info *fileInfo) addTypedefs() {
292
288
TokPos : info .importCPos ,
293
289
Tok : token .TYPE ,
294
290
}
295
- for _ , typedef := range info .typedefs {
296
- newType := mapCgoType (typedef .newName )
297
- oldType := mapCgoType (typedef .oldName )
298
- switch oldType {
299
- // TODO: plain char (may be signed or unsigned)
300
- case "C.schar" , "C.short" , "C.int" , "C.long" , "C.longlong" :
301
- switch typedef .size {
302
- case 1 :
303
- oldType = "int8"
304
- case 2 :
305
- oldType = "int16"
306
- case 4 :
307
- oldType = "int32"
308
- case 8 :
309
- oldType = "int64"
310
- }
311
- case "C.uchar" , "C.ushort" , "C.uint" , "C.ulong" , "C.ulonglong" :
312
- switch typedef .size {
313
- case 1 :
314
- oldType = "uint8"
315
- case 2 :
316
- oldType = "uint16"
317
- case 4 :
318
- oldType = "uint32"
319
- case 8 :
320
- oldType = "uint64"
321
- }
322
- }
323
- if strings .HasPrefix (newType , "C._Cgo_" ) {
324
- newType = "C." + newType [len ("C._Cgo_" ):]
291
+ names := make ([]string , 0 , len (info .typedefs ))
292
+ for name := range info .typedefs {
293
+ names = append (names , name )
294
+ }
295
+ sort .Strings (names )
296
+ for _ , name := range names {
297
+ typedef := info .typedefs [name ]
298
+ typeName := "C." + name
299
+ if strings .HasPrefix (name , "_Cgo_" ) {
300
+ typeName = "C." + name [len ("_Cgo_" ):]
325
301
}
326
- if _ , ok := cgoAliases [newType ]; ok {
302
+ if _ , ok := cgoAliases [typeName ]; ok {
327
303
// This is a type that also exists in Go (defined in stdint.h).
328
304
continue
329
305
}
330
306
obj := & ast.Object {
331
307
Kind : ast .Typ ,
332
- Name : newType ,
308
+ Name : typeName ,
333
309
}
334
310
typeSpec := & ast.TypeSpec {
335
311
Name : & ast.Ident {
336
312
NamePos : info .importCPos ,
337
- Name : newType ,
313
+ Name : typeName ,
338
314
Obj : obj ,
339
315
},
340
- Type : & ast.Ident {
341
- NamePos : info .importCPos ,
342
- Name : oldType ,
343
- },
316
+ Type : typedef .typeExpr ,
344
317
}
345
318
obj .Decl = typeSpec
346
319
gen .Specs = append (gen .Specs , typeSpec )
@@ -362,31 +335,9 @@ func (info *fileInfo) walker(cursor *astutil.Cursor) bool {
362
335
if x .Name == "C" {
363
336
cursor .Replace (& ast.Ident {
364
337
NamePos : x .NamePos ,
365
- Name : mapCgoType ( node .Sel .Name ) ,
338
+ Name : "C." + node .Sel .Name ,
366
339
})
367
340
}
368
341
}
369
342
return true
370
343
}
371
-
372
- // mapCgoType converts a C type name into a Go type name with a "C." prefix.
373
- func mapCgoType (t string ) string {
374
- switch t {
375
- case "signed char" :
376
- return "C.schar"
377
- case "long long" :
378
- return "C.longlong"
379
- case "unsigned char" :
380
- return "C.schar"
381
- case "unsigned short" :
382
- return "C.ushort"
383
- case "unsigned int" :
384
- return "C.uint"
385
- case "unsigned long" :
386
- return "C.ulong"
387
- case "unsigned long long" :
388
- return "C.ulonglong"
389
- default :
390
- return "C." + t
391
- }
392
- }
0 commit comments