@@ -17,37 +17,33 @@ import (
1717type fileInfo struct {
1818 * ast.File
1919 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
2323 importCPos token.Pos
2424}
2525
2626// functionInfo stores some information about a Cgo function found by libclang
2727// and declared in the AST.
2828type functionInfo struct {
29- name string
30- args []paramInfo
31- result string
29+ args []paramInfo
30+ results * ast.FieldList
3231}
3332
3433// paramInfo is a parameter of a Cgo function (see functionInfo).
3534type paramInfo struct {
3635 name string
37- typeName string
36+ typeExpr ast. Expr
3837}
3938
4039// typedefInfo contains information about a single typedef in C.
4140type 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
4542}
4643
4744// globalInfo contains information about a declared global variable in C.
4845type globalInfo struct {
49- name string
50- typeName string
46+ typeExpr ast.Expr
5147}
5248
5349// cgoAliases list type aliases between Go and C, for types that are equivalent
@@ -84,8 +80,11 @@ typedef unsigned long long _Cgo_ulonglong;
8480// comment with libclang, and modifies the AST to use this information.
8581func (p * Package ) processCgo (filename string , f * ast.File , cflags []string ) error {
8682 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 {},
8988 }
9089
9190 // Find `import "C"` statements in the file.
@@ -151,16 +150,22 @@ func (p *Package) processCgo(filename string, f *ast.File, cflags []string) erro
151150func (info * fileInfo ) addFuncDecls () {
152151 // TODO: replace all uses of importCPos with the real locations from
153152 // 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 ]
155160 obj := & ast.Object {
156161 Kind : ast .Fun ,
157- Name : mapCgoType ( fn . name ) ,
162+ Name : "C." + name ,
158163 }
159164 args := make ([]* ast.Field , len (fn .args ))
160165 decl := & ast.FuncDecl {
161166 Name : & ast.Ident {
162167 NamePos : info .importCPos ,
163- Name : mapCgoType ( fn . name ) ,
168+ Name : "C." + name ,
164169 Obj : obj ,
165170 },
166171 Type : & ast.FuncType {
@@ -170,16 +175,7 @@ func (info *fileInfo) addFuncDecls() {
170175 List : args ,
171176 Closing : info .importCPos ,
172177 },
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 ,
183179 },
184180 }
185181 obj .Decl = decl
@@ -191,15 +187,12 @@ func (info *fileInfo) addFuncDecls() {
191187 Name : arg .name ,
192188 Obj : & ast.Object {
193189 Kind : ast .Var ,
194- Name : mapCgoType ( arg .name ) ,
190+ Name : arg .name ,
195191 Decl : decl ,
196192 },
197193 },
198194 },
199- Type : & ast.Ident {
200- NamePos : info .importCPos ,
201- Name : mapCgoType (arg .typeName ),
202- },
195+ Type : arg .typeExpr ,
203196 }
204197 }
205198 info .Decls = append (info .Decls , decl )
@@ -221,21 +214,24 @@ func (info *fileInfo) addVarDecls() {
221214 Lparen : info .importCPos ,
222215 Rparen : info .importCPos ,
223216 }
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 ]
225224 obj := & ast.Object {
226225 Kind : ast .Typ ,
227- Name : mapCgoType ( global . name ) ,
226+ Name : "C." + name ,
228227 }
229228 valueSpec := & ast.ValueSpec {
230229 Names : []* ast.Ident {& ast.Ident {
231230 NamePos : info .importCPos ,
232- Name : mapCgoType ( global . name ) ,
231+ Name : "C." + name ,
233232 Obj : obj ,
234233 }},
235- Type : & ast.Ident {
236- NamePos : info .importCPos ,
237- Name : mapCgoType (global .typeName ),
238- },
234+ Type : global .typeExpr ,
239235 }
240236 obj .Decl = valueSpec
241237 gen .Specs = append (gen .Specs , valueSpec )
@@ -292,55 +288,32 @@ func (info *fileInfo) addTypedefs() {
292288 TokPos : info .importCPos ,
293289 Tok : token .TYPE ,
294290 }
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_" ):]
325301 }
326- if _ , ok := cgoAliases [newType ]; ok {
302+ if _ , ok := cgoAliases [typeName ]; ok {
327303 // This is a type that also exists in Go (defined in stdint.h).
328304 continue
329305 }
330306 obj := & ast.Object {
331307 Kind : ast .Typ ,
332- Name : newType ,
308+ Name : typeName ,
333309 }
334310 typeSpec := & ast.TypeSpec {
335311 Name : & ast.Ident {
336312 NamePos : info .importCPos ,
337- Name : newType ,
313+ Name : typeName ,
338314 Obj : obj ,
339315 },
340- Type : & ast.Ident {
341- NamePos : info .importCPos ,
342- Name : oldType ,
343- },
316+ Type : typedef .typeExpr ,
344317 }
345318 obj .Decl = typeSpec
346319 gen .Specs = append (gen .Specs , typeSpec )
@@ -362,31 +335,9 @@ func (info *fileInfo) walker(cursor *astutil.Cursor) bool {
362335 if x .Name == "C" {
363336 cursor .Replace (& ast.Ident {
364337 NamePos : x .NamePos ,
365- Name : mapCgoType ( node .Sel .Name ) ,
338+ Name : "C." + node .Sel .Name ,
366339 })
367340 }
368341 }
369342 return true
370343}
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