github.com/F4RD1N/gomobile@v1.0.1/bind/gen.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package bind 6 7 import ( 8 "bytes" 9 "fmt" 10 "go/ast" 11 "go/token" 12 "go/types" 13 "io" 14 "regexp" 15 "strings" 16 "unicode" 17 "unicode/utf8" 18 ) 19 20 type ( 21 ErrorList []error 22 23 // varMode describes the lifetime of an argument or 24 // return value. Modes are used to guide the conversion 25 // of string and byte slice values accross the language 26 // barrier. The same conversion mode must be used for 27 // both the conversion before a foreign call and the 28 // corresponding conversion after the call. 29 // See the mode* constants for a description of 30 // each mode. 31 varMode int 32 ) 33 34 const ( 35 // modeTransient are for function arguments that 36 // are not used after the function returns. 37 // Transient byte slices don't need copying 38 // when passed accross the language barrier. 39 modeTransient varMode = iota 40 // modeRetained are for returned values and for function 41 // arguments that are used after the function returns. 42 // Retained byte slices need an intermediate copy. 43 modeRetained 44 ) 45 46 func (list ErrorList) Error() string { 47 buf := new(bytes.Buffer) 48 for i, err := range list { 49 if i > 0 { 50 buf.WriteRune('\n') 51 } 52 io.WriteString(buf, err.Error()) 53 } 54 return buf.String() 55 } 56 57 // interfaceInfo comes from Init and collects the auxillary information 58 // needed to generate bindings for an exported Go interface in a bound 59 // package. 60 type interfaceInfo struct { 61 obj *types.TypeName 62 t *types.Interface 63 summary ifaceSummary 64 } 65 66 // structInfo comes from Init and collects the auxillary information 67 // needed to generate bindings for an exported Go struct in a bound 68 // package. 69 type structInfo struct { 70 obj *types.TypeName 71 t *types.Struct 72 } 73 74 // Generator contains the common Go package information 75 // needed for the specific Go, Java, ObjC generators. 76 // 77 // After setting Printer, Fset, AllPkg, Pkg, the Init 78 // method is used to initialize the auxiliary information 79 // about the package to be generated, Pkg. 80 type Generator struct { 81 *Printer 82 Fset *token.FileSet 83 AllPkg []*types.Package 84 Files []*ast.File 85 Pkg *types.Package 86 err ErrorList 87 88 // fields set by init. 89 pkgName string 90 pkgPrefix string 91 funcs []*types.Func 92 constants []*types.Const 93 vars []*types.Var 94 95 interfaces []interfaceInfo 96 structs []structInfo 97 otherNames []*types.TypeName 98 // allIntf contains interfaces from all bound packages. 99 allIntf []interfaceInfo 100 101 docs pkgDocs 102 } 103 104 // A pkgDocs maps the name of each exported package-level declaration to its extracted documentation. 105 type pkgDocs map[string]*pkgDoc 106 107 type pkgDoc struct { 108 doc string 109 // Struct or interface fields and methods. 110 members map[string]string 111 } 112 113 // pkgPrefix returns a prefix that disambiguates symbol names for binding 114 // multiple packages. 115 // 116 // TODO(elias.naur): Avoid (and test) name clashes from multiple packages 117 // with the same name. Perhaps use the index from the order the package is 118 // generated. 119 func pkgPrefix(pkg *types.Package) string { 120 // The error type has no package 121 if pkg == nil { 122 return "" 123 } 124 return pkg.Name() 125 } 126 127 func (g *Generator) Init() { 128 if g.Pkg != nil { 129 g.pkgName = g.Pkg.Name() 130 } 131 g.pkgPrefix = pkgPrefix(g.Pkg) 132 133 if g.Pkg != nil { 134 g.parseDocs() 135 scope := g.Pkg.Scope() 136 hasExported := false 137 for _, name := range scope.Names() { 138 obj := scope.Lookup(name) 139 if !obj.Exported() { 140 continue 141 } 142 hasExported = true 143 switch obj := obj.(type) { 144 case *types.Func: 145 if isCallable(obj) { 146 g.funcs = append(g.funcs, obj) 147 } 148 case *types.TypeName: 149 named, ok := obj.Type().(*types.Named) 150 if !ok { 151 continue 152 } 153 switch t := named.Underlying().(type) { 154 case *types.Struct: 155 g.structs = append(g.structs, structInfo{obj, t}) 156 case *types.Interface: 157 g.interfaces = append(g.interfaces, interfaceInfo{obj, t, makeIfaceSummary(t)}) 158 default: 159 g.otherNames = append(g.otherNames, obj) 160 } 161 case *types.Const: 162 g.constants = append(g.constants, obj) 163 case *types.Var: 164 g.vars = append(g.vars, obj) 165 default: 166 g.errorf("unsupported exported type for %s: %T", obj.Name(), obj) 167 } 168 } 169 if !hasExported { 170 g.errorf("no exported names in the package %q", g.Pkg.Path()) 171 } 172 } else { 173 // Bind the single supported type from the universe scope, error. 174 errType := types.Universe.Lookup("error").(*types.TypeName) 175 t := errType.Type().Underlying().(*types.Interface) 176 g.interfaces = append(g.interfaces, interfaceInfo{errType, t, makeIfaceSummary(t)}) 177 } 178 for _, p := range g.AllPkg { 179 scope := p.Scope() 180 for _, name := range scope.Names() { 181 obj := scope.Lookup(name) 182 if !obj.Exported() { 183 continue 184 } 185 if obj, ok := obj.(*types.TypeName); ok { 186 named, ok := obj.Type().(*types.Named) 187 if !ok { 188 continue 189 } 190 if t, ok := named.Underlying().(*types.Interface); ok { 191 g.allIntf = append(g.allIntf, interfaceInfo{obj, t, makeIfaceSummary(t)}) 192 } 193 } 194 } 195 } 196 } 197 198 // parseDocs extracts documentation from a package in a form useful for lookups. 199 func (g *Generator) parseDocs() { 200 d := make(pkgDocs) 201 for _, f := range g.Files { 202 for _, decl := range f.Decls { 203 switch decl := decl.(type) { 204 case *ast.GenDecl: 205 for _, spec := range decl.Specs { 206 switch spec := spec.(type) { 207 case *ast.TypeSpec: 208 d.addType(spec, decl.Doc) 209 case *ast.ValueSpec: 210 d.addValue(spec, decl.Doc) 211 } 212 } 213 case *ast.FuncDecl: 214 d.addFunc(decl) 215 } 216 } 217 } 218 g.docs = d 219 } 220 221 func (d pkgDocs) addValue(t *ast.ValueSpec, outerDoc *ast.CommentGroup) { 222 for _, n := range t.Names { 223 if !ast.IsExported(n.Name) { 224 continue 225 } 226 doc := t.Doc 227 if doc == nil { 228 doc = outerDoc 229 } 230 if doc != nil { 231 d[n.Name] = &pkgDoc{doc: doc.Text()} 232 } 233 } 234 } 235 236 func (d pkgDocs) addFunc(f *ast.FuncDecl) { 237 doc := f.Doc 238 if doc == nil { 239 return 240 } 241 fn := f.Name.Name 242 if !ast.IsExported(fn) { 243 return 244 } 245 if r := f.Recv; r != nil { 246 // f is a method. 247 n := typeName(r.List[0].Type) 248 pd, exists := d[n] 249 if !exists { 250 pd = &pkgDoc{members: make(map[string]string)} 251 d[n] = pd 252 } 253 pd.members[fn] = doc.Text() 254 } else { 255 // f is a function. 256 d[fn] = &pkgDoc{doc: doc.Text()} 257 } 258 } 259 260 func (d pkgDocs) addType(t *ast.TypeSpec, outerDoc *ast.CommentGroup) { 261 if !ast.IsExported(t.Name.Name) { 262 return 263 } 264 doc := t.Doc 265 if doc == nil { 266 doc = outerDoc 267 } 268 pd := d[t.Name.Name] 269 pd = &pkgDoc{members: make(map[string]string)} 270 d[t.Name.Name] = pd 271 if doc != nil { 272 pd.doc = doc.Text() 273 } 274 var fields *ast.FieldList 275 switch t := t.Type.(type) { 276 case *ast.StructType: 277 fields = t.Fields 278 case *ast.InterfaceType: 279 fields = t.Methods 280 } 281 if fields != nil { 282 for _, field := range fields.List { 283 if field.Doc != nil { 284 if field.Names == nil { 285 // Anonymous field. Extract name from its type. 286 if n := typeName(field.Type); ast.IsExported(n) { 287 pd.members[n] = field.Doc.Text() 288 } 289 } 290 for _, n := range field.Names { 291 if ast.IsExported(n.Name) { 292 pd.members[n.Name] = field.Doc.Text() 293 } 294 } 295 } 296 } 297 } 298 } 299 300 // typeName returns the type name T for expressions on the 301 // T, *T, **T (etc.) form. 302 func typeName(t ast.Expr) string { 303 switch t := t.(type) { 304 case *ast.StarExpr: 305 return typeName(t.X) 306 case *ast.Ident: 307 return t.Name 308 case *ast.SelectorExpr: 309 return t.Sel.Name 310 default: 311 return "" 312 } 313 } 314 315 func (d *pkgDoc) Doc() string { 316 if d == nil { 317 return "" 318 } 319 return d.doc 320 } 321 322 func (d *pkgDoc) Member(n string) string { 323 if d == nil { 324 return "" 325 } 326 return d.members[n] 327 } 328 329 // constructorType returns the type T for a function of the forms: 330 // 331 // func NewT...(...) *T 332 // func NewT...(...) (*T, error) 333 func (g *Generator) constructorType(f *types.Func) *types.TypeName { 334 sig := f.Type().(*types.Signature) 335 res := sig.Results() 336 if res.Len() != 1 && !(res.Len() == 2 && isErrorType(res.At(1).Type())) { 337 return nil 338 } 339 rt := res.At(0).Type() 340 pt, ok := rt.(*types.Pointer) 341 if !ok { 342 return nil 343 } 344 nt, ok := pt.Elem().(*types.Named) 345 if !ok { 346 return nil 347 } 348 obj := nt.Obj() 349 if !strings.HasPrefix(f.Name(), "New"+obj.Name()) { 350 return nil 351 } 352 return obj 353 } 354 355 func toCFlag(v bool) int { 356 if v { 357 return 1 358 } 359 return 0 360 } 361 362 func (g *Generator) errorf(format string, args ...interface{}) { 363 g.err = append(g.err, fmt.Errorf(format, args...)) 364 } 365 366 // cgoType returns the name of a Cgo type suitable for converting a value of 367 // the given type. 368 func (g *Generator) cgoType(t types.Type) string { 369 switch t := t.(type) { 370 case *types.Basic: 371 switch t.Kind() { 372 case types.Bool, types.UntypedBool: 373 return "char" 374 case types.Int: 375 return "nint" 376 case types.Int8: 377 return "int8_t" 378 case types.Int16: 379 return "int16_t" 380 case types.Int32, types.UntypedRune: // types.Rune 381 return "int32_t" 382 case types.Int64, types.UntypedInt: 383 return "int64_t" 384 case types.Uint8: // types.Byte 385 return "uint8_t" 386 // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: 387 case types.Float32: 388 return "float" 389 case types.Float64, types.UntypedFloat: 390 return "double" 391 case types.String: 392 return "nstring" 393 default: 394 g.errorf("unsupported basic type: %s", t) 395 } 396 case *types.Slice: 397 switch e := t.Elem().(type) { 398 case *types.Basic: 399 switch e.Kind() { 400 case types.Uint8: // Byte. 401 return "nbyteslice" 402 default: 403 g.errorf("unsupported slice type: %s", t) 404 } 405 default: 406 g.errorf("unsupported slice type: %s", t) 407 } 408 case *types.Pointer: 409 if _, ok := t.Elem().(*types.Named); ok { 410 return g.cgoType(t.Elem()) 411 } 412 g.errorf("unsupported pointer to type: %s", t) 413 case *types.Named: 414 return "int32_t" 415 default: 416 g.errorf("unsupported type: %s", t) 417 } 418 return "TODO" 419 } 420 421 func (g *Generator) genInterfaceMethodSignature(m *types.Func, iName string, header bool, g_paramName func(*types.Tuple, int) string) { 422 sig := m.Type().(*types.Signature) 423 params := sig.Params() 424 res := sig.Results() 425 426 if res.Len() == 0 { 427 g.Printf("void ") 428 } else { 429 if res.Len() == 1 { 430 g.Printf("%s ", g.cgoType(res.At(0).Type())) 431 } else { 432 if header { 433 g.Printf("typedef struct cproxy%s_%s_%s_return {\n", g.pkgPrefix, iName, m.Name()) 434 g.Indent() 435 for i := 0; i < res.Len(); i++ { 436 t := res.At(i).Type() 437 g.Printf("%s r%d;\n", g.cgoType(t), i) 438 } 439 g.Outdent() 440 g.Printf("} cproxy%s_%s_%s_return;\n", g.pkgPrefix, iName, m.Name()) 441 } 442 g.Printf("struct cproxy%s_%s_%s_return ", g.pkgPrefix, iName, m.Name()) 443 } 444 } 445 g.Printf("cproxy%s_%s_%s(int32_t refnum", g.pkgPrefix, iName, m.Name()) 446 for i := 0; i < params.Len(); i++ { 447 t := params.At(i).Type() 448 g.Printf(", %s %s", g.cgoType(t), g_paramName(params, i)) 449 } 450 g.Printf(")") 451 if header { 452 g.Printf(";\n") 453 } else { 454 g.Printf(" {\n") 455 } 456 } 457 458 func (g *Generator) validPkg(pkg *types.Package) bool { 459 for _, p := range g.AllPkg { 460 if p == pkg { 461 return true 462 } 463 } 464 return false 465 } 466 467 // isSigSupported reports whether the generators can handle a given 468 // function signature. 469 func (g *Generator) isSigSupported(t types.Type) bool { 470 sig := t.(*types.Signature) 471 params := sig.Params() 472 for i := 0; i < params.Len(); i++ { 473 if !g.isSupported(params.At(i).Type()) { 474 return false 475 } 476 } 477 res := sig.Results() 478 for i := 0; i < res.Len(); i++ { 479 if !g.isSupported(res.At(i).Type()) { 480 return false 481 } 482 } 483 return true 484 } 485 486 // isSupported reports whether the generators can handle the type. 487 func (g *Generator) isSupported(t types.Type) bool { 488 if isErrorType(t) || isWrapperType(t) { 489 return true 490 } 491 switch t := t.(type) { 492 case *types.Basic: 493 switch t.Kind() { 494 case types.Bool, types.UntypedBool, 495 types.Int, 496 types.Int8, types.Uint8, // types.Byte 497 types.Int16, 498 types.Int32, types.UntypedRune, // types.Rune 499 types.Int64, types.UntypedInt, 500 types.Float32, 501 types.Float64, types.UntypedFloat, 502 types.String, types.UntypedString: 503 return true 504 } 505 return false 506 case *types.Slice: 507 switch e := t.Elem().(type) { 508 case *types.Basic: 509 return e.Kind() == types.Uint8 510 } 511 case *types.Pointer: 512 switch t := t.Elem().(type) { 513 case *types.Named: 514 return g.validPkg(t.Obj().Pkg()) 515 } 516 case *types.Named: 517 switch t.Underlying().(type) { 518 case *types.Interface, *types.Pointer: 519 return g.validPkg(t.Obj().Pkg()) 520 } 521 } 522 return false 523 } 524 525 var paramRE = regexp.MustCompile(`^p[0-9]*$`) 526 527 // basicParamName replaces incompatible name with a p0-pN name. 528 // Missing names, or existing names of the form p[0-9] are incompatible. 529 func basicParamName(params *types.Tuple, pos int) string { 530 name := params.At(pos).Name() 531 if name == "" || name[0] == '_' || paramRE.MatchString(name) { 532 name = fmt.Sprintf("p%d", pos) 533 } 534 return name 535 } 536 537 func lowerFirst(s string) string { 538 if s == "" { 539 return "" 540 } 541 542 var conv []rune 543 for len(s) > 0 { 544 r, n := utf8.DecodeRuneInString(s) 545 if !unicode.IsUpper(r) { 546 if l := len(conv); l > 1 { 547 conv[l-1] = unicode.ToUpper(conv[l-1]) 548 } 549 return string(conv) + s 550 } 551 conv = append(conv, unicode.ToLower(r)) 552 s = s[n:] 553 } 554 return string(conv) 555 } 556 557 // newNameSanitizer returns a functions that replaces all dashes and dots 558 // with underscores, as well as avoiding reserved words by suffixing such 559 // identifiers with underscores. 560 func newNameSanitizer(res []string) func(s string) string { 561 reserved := make(map[string]bool) 562 for _, word := range res { 563 reserved[word] = true 564 } 565 symbols := strings.NewReplacer( 566 "-", "_", 567 ".", "_", 568 ) 569 return func(s string) string { 570 if reserved[s] { 571 return s + "_" 572 } 573 return symbols.Replace(s) 574 } 575 }