github.com/cyrilou242/gomobile-java@v0.0.0-20220215185836-09daef25a210/internal/importers/java/java.go (about) 1 // Copyright 2016 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 // The java package takes the result of an AST traversal by the 6 // importers package and queries the java command for the type 7 // information for the referenced Java classes and interfaces. 8 // 9 // It is the of go/types for Java types and is used by the bind 10 // package to generate Go wrappers for Java API on Android. 11 package java 12 13 import ( 14 "bufio" 15 "bytes" 16 "errors" 17 "fmt" 18 "os/exec" 19 "reflect" 20 "strings" 21 "unicode" 22 "unicode/utf8" 23 24 "github.com/cyrilou242/gomobile-java/internal/importers" 25 ) 26 27 // Class is the bind representation of a Java class or 28 // interface. 29 // Use Import to convert class references to Class. 30 type Class struct { 31 // "java.pkg.Class.Inner" 32 Name string 33 // "java.pkg.Class$Inner" 34 FindName string 35 // JNI mangled name 36 JNIName string 37 // "Inner" 38 PkgName string 39 Funcs []*FuncSet 40 Methods []*FuncSet 41 // funcMap maps function names. 42 funcMap map[string]*FuncSet 43 // FuncMap maps method names. 44 methodMap map[string]*FuncSet 45 // All methods, including methods from 46 // supers. 47 AllMethods []*FuncSet 48 Vars []*Var 49 Supers []string 50 Final bool 51 Abstract bool 52 Interface bool 53 Throwable bool 54 // Whether the class has a no-arg constructor 55 HasNoArgCon bool 56 } 57 58 // FuncSet is the set of overloaded variants of a function. 59 // If the function is not overloaded, its FuncSet contains 60 // one entry. 61 type FuncSet struct { 62 Name string 63 GoName string 64 Funcs []*Func 65 CommonSig 66 } 67 68 // CommonSig is a signature compatible with every 69 // overloaded variant of a FuncSet. 70 type CommonSig struct { 71 // Variadic is set if the signature covers variants 72 // with varying number of parameters. 73 Variadic bool 74 // HasRet is true if at least one variant returns a 75 // value. 76 HasRet bool 77 Throws bool 78 Params []*Type 79 Ret *Type 80 } 81 82 // Func is a Java static function or method or constructor. 83 type Func struct { 84 FuncSig 85 ArgDesc string 86 // Mangled JNI name 87 JNIName string 88 Static bool 89 Abstract bool 90 Final bool 91 Public bool 92 Constructor bool 93 Params []*Type 94 Ret *Type 95 Decl string 96 Throws string 97 } 98 99 // FuncSig uniquely identifies a Java Func. 100 type FuncSig struct { 101 Name string 102 // The method descriptor, in JNI format. 103 Desc string 104 } 105 106 // Var is a Java member variable. 107 type Var struct { 108 Name string 109 Static bool 110 Final bool 111 Val string 112 Type *Type 113 } 114 115 // Type is a Java type. 116 type Type struct { 117 Kind TypeKind 118 Class string 119 Elem *Type 120 } 121 122 type TypeKind int 123 124 type Importer struct { 125 Bootclasspath string 126 Classpath string 127 // JavaPkg is java package name for generated classes. 128 JavaPkg string 129 130 clsMap map[string]*Class 131 } 132 133 // funcRef is a reference to a Java function (static method). 134 // It is used as a key to filter unused Java functions. 135 type funcRef struct { 136 clsName string 137 goName string 138 } 139 140 type errClsNotFound struct { 141 name string 142 } 143 144 const ( 145 Int TypeKind = iota 146 Boolean 147 Short 148 Char 149 Byte 150 Long 151 Float 152 Double 153 String 154 Array 155 Object 156 ) 157 158 func (e *errClsNotFound) Error() string { 159 return "class not found: " + e.name 160 } 161 162 // IsAvailable reports whether the required tools are available for 163 // Import to work. In particular, IsAvailable checks the existence 164 // of the javap binary. 165 func IsAvailable() bool { 166 _, err := javapPath() 167 return err == nil 168 } 169 170 func javapPath() (string, error) { 171 return exec.LookPath("javap") 172 } 173 174 // Import returns Java Class descriptors for a list of references. 175 // 176 // The javap command from the Java SDK is used to dump 177 // class information. Its output looks like this: 178 // 179 // Compiled from "System.java" 180 // public final class java.lang.System { 181 // public static final java.io.InputStream in; 182 // descriptor: Ljava/io/InputStream; 183 // public static final java.io.PrintStream out; 184 // descriptor: Ljava/io/PrintStream; 185 // public static final java.io.PrintStream err; 186 // descriptor: Ljava/io/PrintStream; 187 // public static void setIn(java.io.InputStream); 188 // descriptor: (Ljava/io/InputStream;)V 189 // 190 // ... 191 // 192 // } 193 func (j *Importer) Import(refs *importers.References) ([]*Class, error) { 194 if j.clsMap == nil { 195 j.clsMap = make(map[string]*Class) 196 } 197 clsSet := make(map[string]struct{}) 198 var names []string 199 for _, ref := range refs.Refs { 200 // The reference could be to some/pkg.Class or some/pkg/Class.Identifier. Include both. 201 pkg := strings.Replace(ref.Pkg, "/", ".", -1) 202 for _, cls := range []string{pkg, pkg + "." + ref.Name} { 203 if _, exists := clsSet[cls]; !exists { 204 clsSet[cls] = struct{}{} 205 names = append(names, cls) 206 } 207 } 208 } 209 // Make sure toString() is included; it is called when wrapping Java exception types to Go 210 // errors. 211 refs.Names["ToString"] = struct{}{} 212 funcRefs := make(map[funcRef]struct{}) 213 for _, ref := range refs.Refs { 214 pkgName := strings.Replace(ref.Pkg, "/", ".", -1) 215 funcRefs[funcRef{pkgName, ref.Name}] = struct{}{} 216 } 217 classes, err := j.importClasses(names, true) 218 if err != nil { 219 return nil, err 220 } 221 j.filterReferences(classes, refs, funcRefs) 222 supers, err := j.importReferencedClasses(classes) 223 if err != nil { 224 return nil, err 225 } 226 j.filterReferences(supers, refs, funcRefs) 227 // Embedders refer to every exported Go struct that will have its class 228 // generated. Allow Go code to reverse bind to those classes by synthesizing 229 // their class descriptors. 230 for _, emb := range refs.Embedders { 231 n := emb.Pkg + "." + emb.Name 232 if j.JavaPkg != "" { 233 n = j.JavaPkg + "." + n 234 } 235 if _, exists := j.clsMap[n]; exists { 236 continue 237 } 238 clsSet[n] = struct{}{} 239 cls := &Class{ 240 Name: n, 241 FindName: n, 242 JNIName: JNIMangle(n), 243 PkgName: emb.Name, 244 HasNoArgCon: true, 245 } 246 for _, ref := range emb.Refs { 247 jpkg := strings.Replace(ref.Pkg, "/", ".", -1) 248 super := jpkg + "." + ref.Name 249 if _, exists := j.clsMap[super]; !exists { 250 return nil, fmt.Errorf("failed to find Java class %s, embedded by %s", super, n) 251 } 252 cls.Supers = append(cls.Supers, super) 253 } 254 classes = append(classes, cls) 255 j.clsMap[cls.Name] = cls 256 } 257 // Include implicit classes that are used in parameter or return values. 258 for _, cls := range classes { 259 for _, fsets := range [][]*FuncSet{cls.Funcs, cls.Methods} { 260 for _, fs := range fsets { 261 for _, f := range fs.Funcs { 262 names := j.implicitFuncTypes(f) 263 for _, name := range names { 264 if _, exists := clsSet[name]; exists { 265 continue 266 } 267 clsSet[name] = struct{}{} 268 classes = append(classes, j.clsMap[name]) 269 } 270 } 271 } 272 } 273 } 274 for _, cls := range j.clsMap { 275 j.fillFuncSigs(cls.Funcs) 276 j.fillFuncSigs(cls.Methods) 277 for _, m := range cls.Methods { 278 j.fillSuperSigs(cls, m) 279 } 280 } 281 for _, cls := range j.clsMap { 282 j.fillAllMethods(cls) 283 } 284 // Include classes that appear as ancestor types for overloaded signatures. 285 for _, cls := range classes { 286 for _, funcs := range [][]*FuncSet{cls.Funcs, cls.AllMethods} { 287 for _, f := range funcs { 288 for _, p := range f.Params { 289 if p == nil || p.Kind != Object { 290 continue 291 } 292 if _, exists := clsSet[p.Class]; !exists { 293 clsSet[p.Class] = struct{}{} 294 classes = append(classes, j.clsMap[p.Class]) 295 } 296 } 297 if t := f.Ret; t != nil && t.Kind == Object { 298 if _, exists := clsSet[t.Class]; !exists { 299 clsSet[t.Class] = struct{}{} 300 classes = append(classes, j.clsMap[t.Class]) 301 } 302 } 303 } 304 } 305 } 306 for _, cls := range classes { 307 j.fillJNINames(cls.Funcs) 308 j.fillJNINames(cls.AllMethods) 309 } 310 j.fillThrowables(classes) 311 return classes, nil 312 } 313 314 func (j *Importer) fillJNINames(funcs []*FuncSet) { 315 for _, fs := range funcs { 316 for _, f := range fs.Funcs { 317 f.JNIName = JNIMangle(f.Name) 318 if len(fs.Funcs) > 1 { 319 f.JNIName += "__" + JNIMangle(f.ArgDesc) 320 } 321 } 322 } 323 } 324 325 // commonType finds the most specific type common to t1 and t2. 326 // If t1 and t2 are both Java classes, the most specific ancestor 327 // class is returned. 328 // Else if the types are equal, their type is returned. 329 // Finally, nil is returned, indicating no common type. 330 func commonType(clsMap map[string]*Class, t1, t2 *Type) *Type { 331 if t1 == nil || t2 == nil { 332 return nil 333 } 334 if reflect.DeepEqual(t1, t2) { 335 return t1 336 } 337 if t1.Kind != Object || t2.Kind != Object { 338 // The types are fundamentally incompatible 339 return nil 340 } 341 superSet := make(map[string]struct{}) 342 supers := []string{t1.Class} 343 for len(supers) > 0 { 344 var newSupers []string 345 for _, s := range supers { 346 cls := clsMap[s] 347 superSet[s] = struct{}{} 348 newSupers = append(newSupers, cls.Supers...) 349 } 350 supers = newSupers 351 } 352 supers = []string{t2.Class} 353 for len(supers) > 0 { 354 var newSupers []string 355 for _, s := range supers { 356 if _, exists := superSet[s]; exists { 357 return &Type{Kind: Object, Class: s} 358 } 359 cls := clsMap[s] 360 newSupers = append(newSupers, cls.Supers...) 361 } 362 supers = newSupers 363 } 364 return &Type{Kind: Object, Class: "java.lang.Object"} 365 } 366 367 // combineSigs finds the most specific function signature 368 // that covers all its overload variants. 369 // If a function has only one variant, its common signature 370 // is the signature of that variant. 371 func combineSigs(clsMap map[string]*Class, sigs ...CommonSig) CommonSig { 372 var common CommonSig 373 minp := len(sigs[0].Params) 374 for i := 1; i < len(sigs); i++ { 375 sig := sigs[i] 376 n := len(sig.Params) 377 common.Variadic = common.Variadic || sig.Variadic || n != minp 378 if n < minp { 379 minp = n 380 } 381 } 382 for i, sig := range sigs { 383 for j, p := range sig.Params { 384 idx := j 385 // If the common signature is variadic, combine all parameters in the 386 // last parameter type of the shortest parameter list. 387 if idx > minp { 388 idx = minp 389 } 390 if idx < len(common.Params) { 391 common.Params[idx] = commonType(clsMap, common.Params[idx], p) 392 } else { 393 common.Params = append(common.Params, p) 394 } 395 } 396 common.Throws = common.Throws || sig.Throws 397 common.HasRet = common.HasRet || sig.HasRet 398 if i > 0 { 399 common.Ret = commonType(clsMap, common.Ret, sig.Ret) 400 } else { 401 common.Ret = sig.Ret 402 } 403 } 404 return common 405 } 406 407 // fillSuperSigs combines methods signatures with super class signatures, 408 // to preserve the assignability of classes to their super classes. 409 // 410 // For example, the class 411 // 412 // class A { 413 // void f(); 414 // } 415 // 416 // is by itself represented by the Go interface 417 // 418 // type A interface { 419 // f() 420 // } 421 // 422 // However, if class 423 // 424 // class B extends A { 425 // void f(int); 426 // } 427 // 428 // is also imported, it will be represented as 429 // 430 // type B interface { 431 // f(...int32) 432 // } 433 // 434 // To make Go B assignable to Go A, the signature of A's f must 435 // be updated to f(...int32) as well. 436 func (j *Importer) fillSuperSigs(cls *Class, m *FuncSet) { 437 for _, s := range cls.Supers { 438 sup := j.clsMap[s] 439 if sm, exists := sup.methodMap[m.GoName]; exists { 440 sm.CommonSig = combineSigs(j.clsMap, sm.CommonSig, m.CommonSig) 441 } 442 j.fillSuperSigs(sup, m) 443 } 444 } 445 446 func (v *Var) Constant() bool { 447 return v.Static && v.Final && v.Val != "" 448 } 449 450 // Mangle a name according to 451 // http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp16696 452 // 453 // TODO: Support unicode characters 454 func JNIMangle(s string) string { 455 var m []byte 456 for i := 0; i < len(s); i++ { 457 switch c := s[i]; c { 458 case '.', '/': 459 m = append(m, '_') 460 case '$': 461 m = append(m, "_00024"...) 462 case '_': 463 m = append(m, "_1"...) 464 case ';': 465 m = append(m, "_2"...) 466 case '[': 467 m = append(m, "_3"...) 468 default: 469 m = append(m, c) 470 } 471 } 472 return string(m) 473 } 474 475 func (t *Type) Type() string { 476 switch t.Kind { 477 case Int: 478 return "int" 479 case Boolean: 480 return "boolean" 481 case Short: 482 return "short" 483 case Char: 484 return "char" 485 case Byte: 486 return "byte" 487 case Long: 488 return "long" 489 case Float: 490 return "float" 491 case Double: 492 return "double" 493 case String: 494 return "String" 495 case Array: 496 return t.Elem.Type() + "[]" 497 case Object: 498 return t.Class 499 default: 500 panic("invalid kind") 501 } 502 } 503 504 func (t *Type) JNIType() string { 505 switch t.Kind { 506 case Int: 507 return "jint" 508 case Boolean: 509 return "jboolean" 510 case Short: 511 return "jshort" 512 case Char: 513 return "jchar" 514 case Byte: 515 return "jbyte" 516 case Long: 517 return "jlong" 518 case Float: 519 return "jfloat" 520 case Double: 521 return "jdouble" 522 case String: 523 return "jstring" 524 case Array: 525 return "jarray" 526 case Object: 527 return "jobject" 528 default: 529 panic("invalid kind") 530 } 531 } 532 533 func (t *Type) CType() string { 534 switch t.Kind { 535 case Int, Boolean, Short, Char, Byte, Long, Float, Double: 536 return t.JNIType() 537 case String: 538 return "nstring" 539 case Array: 540 if t.Elem.Kind != Byte { 541 panic("unsupported array type") 542 } 543 return "nbyteslice" 544 case Object: 545 return "jint" 546 default: 547 panic("invalid kind") 548 } 549 } 550 551 func (t *Type) JNICallType() string { 552 switch t.Kind { 553 case Int: 554 return "Int" 555 case Boolean: 556 return "Boolean" 557 case Short: 558 return "Short" 559 case Char: 560 return "Char" 561 case Byte: 562 return "Byte" 563 case Long: 564 return "Long" 565 case Float: 566 return "Float" 567 case Double: 568 return "Double" 569 case String, Object, Array: 570 return "Object" 571 default: 572 panic("invalid kind") 573 } 574 } 575 576 func (j *Importer) filterReferences(classes []*Class, refs *importers.References, funcRefs map[funcRef]struct{}) { 577 for _, cls := range classes { 578 var filtered []*FuncSet 579 for _, f := range cls.Funcs { 580 if _, exists := funcRefs[funcRef{cls.Name, f.GoName}]; exists { 581 filtered = append(filtered, f) 582 } 583 } 584 cls.Funcs = filtered 585 filtered = nil 586 for _, m := range cls.Methods { 587 if _, exists := refs.Names[m.GoName]; exists { 588 filtered = append(filtered, m) 589 } 590 } 591 cls.Methods = filtered 592 } 593 } 594 595 // importClasses imports the named classes from the classpaths of the Importer. 596 func (j *Importer) importClasses(names []string, allowMissingClasses bool) ([]*Class, error) { 597 if len(names) == 0 { 598 return nil, nil 599 } 600 args := []string{"-J-Duser.language=en", "-s", "-protected", "-constants"} 601 args = append(args, "-classpath", j.Classpath) 602 if j.Bootclasspath != "" { 603 args = append(args, "-bootclasspath", j.Bootclasspath) 604 } 605 args = append(args, names...) 606 javapPath, err := javapPath() 607 if err != nil { 608 return nil, err 609 } 610 javap := exec.Command(javapPath, args...) 611 out, err := javap.CombinedOutput() 612 if err != nil { 613 if _, ok := err.(*exec.ExitError); !ok { 614 return nil, fmt.Errorf("javap failed: %v", err) 615 } 616 // Not every name is a Java class so an exit error from javap is not 617 // fatal. 618 } 619 s := bufio.NewScanner(bytes.NewBuffer(out)) 620 var classes []*Class 621 for _, name := range names { 622 cls, err := j.scanClass(s, name) 623 if err != nil { 624 _, notfound := err.(*errClsNotFound) 625 if notfound && allowMissingClasses { 626 continue 627 } 628 if notfound && name != "android.databinding.DataBindingComponent" { 629 return nil, err 630 } 631 // The Android Databinding library generates android.databinding.DataBindingComponent 632 // too late in the build process for the gobind plugin to import it. Synthesize a class 633 // for it instead. 634 cls = &Class{ 635 Name: name, 636 FindName: name, 637 Interface: true, 638 PkgName: "databinding", 639 JNIName: JNIMangle(name), 640 } 641 } 642 classes = append(classes, cls) 643 j.clsMap[name] = cls 644 } 645 return classes, nil 646 } 647 648 // importReferencedClasses imports all implicit classes (super types, parameter and 649 // return types) for the given classes not already imported. 650 func (j *Importer) importReferencedClasses(classes []*Class) ([]*Class, error) { 651 var allCls []*Class 652 // Include methods from extended or implemented classes. 653 for { 654 set := make(map[string]struct{}) 655 for _, cls := range classes { 656 j.unknownImplicitClasses(cls, set) 657 } 658 if len(set) == 0 { 659 break 660 } 661 var names []string 662 for n := range set { 663 names = append(names, n) 664 } 665 newCls, err := j.importClasses(names, false) 666 if err != nil { 667 return nil, err 668 } 669 allCls = append(allCls, newCls...) 670 classes = newCls 671 } 672 return allCls, nil 673 } 674 675 func (j *Importer) implicitFuncTypes(f *Func) []string { 676 var unk []string 677 if rt := f.Ret; rt != nil && rt.Kind == Object { 678 unk = append(unk, rt.Class) 679 } 680 for _, t := range f.Params { 681 if t.Kind == Object { 682 unk = append(unk, t.Class) 683 } 684 } 685 return unk 686 } 687 688 func (j *Importer) unknownImplicitClasses(cls *Class, set map[string]struct{}) { 689 for _, fsets := range [][]*FuncSet{cls.Funcs, cls.Methods} { 690 for _, fs := range fsets { 691 for _, f := range fs.Funcs { 692 names := j.implicitFuncTypes(f) 693 for _, name := range names { 694 if _, exists := j.clsMap[name]; !exists { 695 set[name] = struct{}{} 696 } 697 } 698 } 699 } 700 } 701 for _, n := range cls.Supers { 702 if s, exists := j.clsMap[n]; exists { 703 j.unknownImplicitClasses(s, set) 704 } else { 705 set[n] = struct{}{} 706 } 707 } 708 } 709 710 func (j *Importer) implicitFuncClasses(funcs []*FuncSet, impl []string) []string { 711 var l []string 712 for _, fs := range funcs { 713 for _, f := range fs.Funcs { 714 if rt := f.Ret; rt != nil && rt.Kind == Object { 715 l = append(l, rt.Class) 716 } 717 for _, t := range f.Params { 718 if t.Kind == Object { 719 l = append(l, t.Class) 720 } 721 } 722 } 723 } 724 return impl 725 } 726 727 func (j *Importer) scanClass(s *bufio.Scanner, name string) (*Class, error) { 728 if !s.Scan() { 729 return nil, fmt.Errorf("%s: missing javap header", name) 730 } 731 head := s.Text() 732 if errPref := "Error: "; strings.HasPrefix(head, errPref) { 733 msg := head[len(errPref):] 734 if strings.HasPrefix(msg, "class not found: "+name) { 735 return nil, &errClsNotFound{name} 736 } 737 return nil, errors.New(msg) 738 } 739 if !strings.HasPrefix(head, "Compiled from ") { 740 return nil, fmt.Errorf("%s: unexpected header: %s", name, head) 741 } 742 if !s.Scan() { 743 return nil, fmt.Errorf("%s: missing javap class declaration", name) 744 } 745 clsDecl := s.Text() 746 cls, err := j.scanClassDecl(name, clsDecl) 747 if err != nil { 748 return nil, err 749 } 750 cls.JNIName = JNIMangle(cls.Name) 751 clsElems := strings.Split(cls.Name, ".") 752 cls.PkgName = clsElems[len(clsElems)-1] 753 var funcs []*Func 754 for s.Scan() { 755 decl := strings.TrimSpace(s.Text()) 756 if decl == "}" { 757 break 758 } else if decl == "" { 759 continue 760 } 761 if !s.Scan() { 762 return nil, fmt.Errorf("%s: missing descriptor for member %q", name, decl) 763 } 764 desc := strings.TrimSpace(s.Text()) 765 desc = strings.TrimPrefix(desc, "descriptor: ") 766 var static, final, abstract, public bool 767 // Trim modifiders from the declaration. 768 loop: 769 for { 770 idx := strings.Index(decl, " ") 771 if idx == -1 { 772 break 773 } 774 keyword := decl[:idx] 775 switch keyword { 776 case "public": 777 public = true 778 case "protected", "native": 779 // ignore 780 case "static": 781 static = true 782 case "final": 783 final = true 784 case "abstract": 785 abstract = true 786 default: 787 // Hopefully we reached the declaration now. 788 break loop 789 } 790 decl = decl[idx+1:] 791 } 792 // Trim ending ; 793 decl = decl[:len(decl)-1] 794 if idx := strings.Index(decl, "("); idx != -1 { 795 f, err := j.scanMethod(decl, desc, idx) 796 if err != nil { 797 return nil, fmt.Errorf("%s: %v", name, err) 798 } 799 if f != nil { 800 f.Static = static 801 f.Abstract = abstract 802 f.Public = public || cls.Interface 803 f.Final = final 804 f.Constructor = f.Name == cls.FindName 805 if f.Constructor { 806 cls.HasNoArgCon = cls.HasNoArgCon || len(f.Params) == 0 807 f.Public = f.Public && !cls.Abstract 808 f.Name = "new" 809 f.Ret = &Type{Class: name, Kind: Object} 810 } 811 funcs = append(funcs, f) 812 } 813 } else { 814 // Member is a variable 815 v, err := j.scanVar(decl, desc) 816 if err != nil { 817 return nil, fmt.Errorf("%s: %v", name, err) 818 } 819 if v != nil && public { 820 v.Static = static 821 v.Final = final 822 cls.Vars = append(cls.Vars, v) 823 } 824 } 825 } 826 for _, f := range funcs { 827 var m map[string]*FuncSet 828 var l *[]*FuncSet 829 goName := initialUpper(f.Name) 830 if f.Static || f.Constructor { 831 m = cls.funcMap 832 l = &cls.Funcs 833 } else { 834 m = cls.methodMap 835 l = &cls.Methods 836 } 837 fs, exists := m[goName] 838 if !exists { 839 fs = &FuncSet{ 840 Name: f.Name, 841 GoName: goName, 842 } 843 m[goName] = fs 844 *l = append(*l, fs) 845 } 846 fs.Funcs = append(fs.Funcs, f) 847 } 848 return cls, nil 849 } 850 851 func (j *Importer) scanClassDecl(name string, decl string) (*Class, error) { 852 isRoot := name == "java.lang.Object" 853 cls := &Class{ 854 Name: name, 855 funcMap: make(map[string]*FuncSet), 856 methodMap: make(map[string]*FuncSet), 857 HasNoArgCon: isRoot, 858 } 859 const ( 860 stMod = iota 861 stName 862 stExt 863 stImpl 864 ) 865 superClsDecl := isRoot 866 st := stMod 867 var w []byte 868 // if > 0, we're inside a generics declaration 869 gennest := 0 870 for i := 0; i < len(decl); i++ { 871 c := decl[i] 872 switch c { 873 default: 874 if gennest == 0 { 875 w = append(w, c) 876 } 877 case '>': 878 gennest-- 879 case '<': 880 gennest++ 881 case '{': 882 if !superClsDecl && !cls.Interface { 883 cls.Supers = append(cls.Supers, "java.lang.Object") 884 } 885 return cls, nil 886 case ' ', ',': 887 if gennest > 0 { 888 break 889 } 890 switch w := string(w); w { 891 default: 892 switch st { 893 case stName: 894 if strings.Replace(w, "$", ".", -1) != strings.Replace(name, "$", ".", -1) { 895 return nil, fmt.Errorf("unexpected name %q in class declaration: %q", w, decl) 896 } 897 cls.FindName = w 898 case stExt: 899 superClsDecl = true 900 cls.Supers = append(cls.Supers, w) 901 case stImpl: 902 if !cls.Interface { 903 cls.Supers = append(cls.Supers, w) 904 } 905 default: 906 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 907 } 908 case "": 909 // skip 910 case "public": 911 if st != stMod { 912 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 913 } 914 case "abstract": 915 if st != stMod { 916 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 917 } 918 cls.Abstract = true 919 case "final": 920 if st != stMod { 921 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 922 } 923 cls.Final = true 924 case "interface": 925 cls.Interface = true 926 fallthrough 927 case "class": 928 if st != stMod { 929 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 930 } 931 st = stName 932 case "extends": 933 if st != stName { 934 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 935 } 936 st = stExt 937 case "implements": 938 if st != stName && st != stExt { 939 return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl) 940 } 941 st = stImpl 942 } 943 w = w[:0] 944 } 945 } 946 return nil, fmt.Errorf("missing ending { in class declaration: %q", decl) 947 } 948 949 func (j *Importer) scanVar(decl, desc string) (*Var, error) { 950 v := new(Var) 951 const eq = " = " 952 idx := strings.Index(decl, eq) 953 if idx != -1 { 954 val, ok := j.parseJavaValue(decl[idx+len(eq):]) 955 if !ok { 956 // Skip constants that cannot be represented in Go 957 return nil, nil 958 } 959 v.Val = val 960 } else { 961 idx = len(decl) 962 } 963 for i := idx - 1; i >= 0; i-- { 964 if i == 0 || decl[i-1] == ' ' { 965 v.Name = decl[i:idx] 966 break 967 } 968 } 969 if v.Name == "" { 970 return nil, fmt.Errorf("unable to parse member name from declaration: %q", decl) 971 } 972 typ, _, err := j.parseJavaType(desc) 973 if err != nil { 974 return nil, fmt.Errorf("invalid type signature for %s: %q", v.Name, desc) 975 } 976 v.Type = typ 977 return v, nil 978 } 979 980 func (j *Importer) scanMethod(decl, desc string, parenIdx int) (*Func, error) { 981 // Member is a method 982 f := new(Func) 983 f.Desc = desc 984 for i := parenIdx - 1; i >= 0; i-- { 985 if i == 0 || decl[i-1] == ' ' { 986 f.Name = decl[i:parenIdx] 987 break 988 } 989 } 990 if f.Name == "" { 991 return nil, fmt.Errorf("unable to parse method name from declaration: %q", decl) 992 } 993 if desc[0] != '(' { 994 return nil, fmt.Errorf("invalid descriptor for method %s: %q", f.Name, desc) 995 } 996 const throws = " throws " 997 if idx := strings.Index(decl, throws); idx != -1 { 998 f.Throws = decl[idx+len(throws):] 999 } 1000 i := 1 1001 for desc[i] != ')' { 1002 typ, n, err := j.parseJavaType(desc[i:]) 1003 if err != nil { 1004 return nil, fmt.Errorf("invalid descriptor for method %s: %v", f.Name, err) 1005 } 1006 i += n 1007 f.Params = append(f.Params, typ) 1008 } 1009 f.ArgDesc = desc[1:i] 1010 i++ // skip ending ) 1011 if desc[i] != 'V' { 1012 typ, _, err := j.parseJavaType(desc[i:]) 1013 if err != nil { 1014 return nil, fmt.Errorf("invalid descriptor for method %s: %v", f.Name, err) 1015 } 1016 f.Ret = typ 1017 } 1018 return f, nil 1019 } 1020 1021 func (j *Importer) fillThrowables(classes []*Class) { 1022 thrCls, ok := j.clsMap["java.lang.Throwable"] 1023 if !ok { 1024 // If Throwable isn't in the class map 1025 // no imported class inherits from Throwable 1026 return 1027 } 1028 for _, cls := range classes { 1029 j.fillThrowableFor(cls, thrCls) 1030 } 1031 } 1032 1033 func (j *Importer) fillThrowableFor(cls, thrCls *Class) { 1034 if cls.Interface || cls.Throwable { 1035 return 1036 } 1037 cls.Throwable = cls == thrCls 1038 for _, name := range cls.Supers { 1039 sup := j.clsMap[name] 1040 j.fillThrowableFor(sup, thrCls) 1041 cls.Throwable = cls.Throwable || sup.Throwable 1042 } 1043 } 1044 1045 func commonSig(f *Func) CommonSig { 1046 return CommonSig{ 1047 Params: f.Params, 1048 Ret: f.Ret, 1049 HasRet: f.Ret != nil, 1050 Throws: f.Throws != "", 1051 } 1052 } 1053 1054 func (j *Importer) fillFuncSigs(funcs []*FuncSet) { 1055 for _, fs := range funcs { 1056 var sigs []CommonSig 1057 for _, f := range fs.Funcs { 1058 sigs = append(sigs, commonSig(f)) 1059 } 1060 fs.CommonSig = combineSigs(j.clsMap, sigs...) 1061 } 1062 } 1063 1064 func (j *Importer) fillAllMethods(cls *Class) { 1065 if len(cls.AllMethods) > 0 { 1066 return 1067 } 1068 for _, supName := range cls.Supers { 1069 super := j.clsMap[supName] 1070 j.fillAllMethods(super) 1071 } 1072 var fsets []*FuncSet 1073 fsets = append(fsets, cls.Methods...) 1074 for _, supName := range cls.Supers { 1075 super := j.clsMap[supName] 1076 fsets = append(fsets, super.AllMethods...) 1077 } 1078 sigs := make(map[FuncSig]struct{}) 1079 methods := make(map[string]*FuncSet) 1080 for _, fs := range fsets { 1081 clsFs, exists := methods[fs.Name] 1082 if !exists { 1083 clsFs = &FuncSet{ 1084 Name: fs.Name, 1085 GoName: fs.GoName, 1086 CommonSig: fs.CommonSig, 1087 } 1088 cls.AllMethods = append(cls.AllMethods, clsFs) 1089 methods[fs.Name] = clsFs 1090 } else { 1091 // Combine the (overloaded) signature with the other variants. 1092 clsFs.CommonSig = combineSigs(j.clsMap, clsFs.CommonSig, fs.CommonSig) 1093 } 1094 for _, f := range fs.Funcs { 1095 if _, exists := sigs[f.FuncSig]; exists { 1096 continue 1097 } 1098 sigs[f.FuncSig] = struct{}{} 1099 clsFs.Funcs = append(clsFs.Funcs, f) 1100 } 1101 } 1102 } 1103 1104 func (j *Importer) parseJavaValue(v string) (string, bool) { 1105 v = strings.TrimRight(v, "ldf") 1106 switch v { 1107 case "", "NaN", "Infinity", "-Infinity": 1108 return "", false 1109 default: 1110 if v[0] == '\'' { 1111 // Skip character constants, since they can contain invalid code points 1112 // that are unacceptable to Go. 1113 return "", false 1114 } 1115 return v, true 1116 } 1117 } 1118 1119 func (j *Importer) parseJavaType(desc string) (*Type, int, error) { 1120 t := new(Type) 1121 var n int 1122 if desc == "" { 1123 return t, n, errors.New("empty type signature") 1124 } 1125 n++ 1126 switch desc[0] { 1127 case 'Z': 1128 t.Kind = Boolean 1129 case 'B': 1130 t.Kind = Byte 1131 case 'C': 1132 t.Kind = Char 1133 case 'S': 1134 t.Kind = Short 1135 case 'I': 1136 t.Kind = Int 1137 case 'J': 1138 t.Kind = Long 1139 case 'F': 1140 t.Kind = Float 1141 case 'D': 1142 t.Kind = Double 1143 case 'L': 1144 var clsName string 1145 for i := n; i < len(desc); i++ { 1146 if desc[i] == ';' { 1147 clsName = strings.Replace(desc[n:i], "/", ".", -1) 1148 clsName = strings.Replace(clsName, "$", ".", -1) 1149 n += i - n + 1 1150 break 1151 } 1152 } 1153 if clsName == "" { 1154 return t, n, errors.New("missing ; in class type signature") 1155 } 1156 if clsName == "java.lang.String" { 1157 t.Kind = String 1158 } else { 1159 t.Kind = Object 1160 t.Class = clsName 1161 } 1162 case '[': 1163 et, n2, err := j.parseJavaType(desc[n:]) 1164 if err != nil { 1165 return t, n, err 1166 } 1167 n += n2 1168 t.Kind = Array 1169 t.Elem = et 1170 default: 1171 return t, n, fmt.Errorf("invalid type signature: %s", desc) 1172 } 1173 return t, n, nil 1174 } 1175 1176 func initialUpper(s string) string { 1177 if s == "" { 1178 return "" 1179 } 1180 r, n := utf8.DecodeRuneInString(s) 1181 return string(unicode.ToUpper(r)) + s[n:] 1182 }