| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183 |
- // Copyright 2016 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // The java package takes the result of an AST traversal by the
- // importers package and queries the java command for the type
- // information for the referenced Java classes and interfaces.
- //
- // It is the of go/types for Java types and is used by the bind
- // package to generate Go wrappers for Java API on Android.
- package java
- import (
- "bufio"
- "bytes"
- "errors"
- "fmt"
- "os/exec"
- "reflect"
- "strings"
- "unicode"
- "unicode/utf8"
- "golang.org/x/mobile/internal/importers"
- )
- // Class is the bind representation of a Java class or
- // interface.
- // Use Import to convert class references to Class.
- type Class struct {
- // "java.pkg.Class.Inner"
- Name string
- // "java.pkg.Class$Inner"
- FindName string
- // JNI mangled name
- JNIName string
- // "Inner"
- PkgName string
- Funcs []*FuncSet
- Methods []*FuncSet
- // funcMap maps function names.
- funcMap map[string]*FuncSet
- // FuncMap maps method names.
- methodMap map[string]*FuncSet
- // All methods, including methods from
- // supers.
- AllMethods []*FuncSet
- Vars []*Var
- Supers []string
- Final bool
- Abstract bool
- Interface bool
- Throwable bool
- // Whether the class has a no-arg constructor
- HasNoArgCon bool
- }
- // FuncSet is the set of overloaded variants of a function.
- // If the function is not overloaded, its FuncSet contains
- // one entry.
- type FuncSet struct {
- Name string
- GoName string
- Funcs []*Func
- CommonSig
- }
- // CommonSig is a signature compatible with every
- // overloaded variant of a FuncSet.
- type CommonSig struct {
- // Variadic is set if the signature covers variants
- // with varying number of parameters.
- Variadic bool
- // HasRet is true if at least one variant returns a
- // value.
- HasRet bool
- Throws bool
- Params []*Type
- Ret *Type
- }
- // Func is a Java static function or method or constructor.
- type Func struct {
- FuncSig
- ArgDesc string
- // Mangled JNI name
- JNIName string
- Static bool
- Abstract bool
- Final bool
- Public bool
- Constructor bool
- Params []*Type
- Ret *Type
- Decl string
- Throws string
- }
- // FuncSig uniquely identifies a Java Func.
- type FuncSig struct {
- Name string
- // The method descriptor, in JNI format.
- Desc string
- }
- // Var is a Java member variable.
- type Var struct {
- Name string
- Static bool
- Final bool
- Val string
- Type *Type
- }
- // Type is a Java type.
- type Type struct {
- Kind TypeKind
- Class string
- Elem *Type
- }
- type TypeKind int
- type Importer struct {
- Bootclasspath string
- Classpath string
- // JavaPkg is java package name for generated classes.
- JavaPkg string
- clsMap map[string]*Class
- }
- // funcRef is a reference to a Java function (static method).
- // It is used as a key to filter unused Java functions.
- type funcRef struct {
- clsName string
- goName string
- }
- type errClsNotFound struct {
- name string
- }
- const (
- Int TypeKind = iota
- Boolean
- Short
- Char
- Byte
- Long
- Float
- Double
- String
- Array
- Object
- )
- func (e *errClsNotFound) Error() string {
- return "class not found: " + e.name
- }
- // IsAvailable reports whether the required tools are available for
- // Import to work. In particular, IsAvailable checks the existence
- // of the javap binary.
- func IsAvailable() bool {
- _, err := javapPath()
- return err == nil
- }
- func javapPath() (string, error) {
- return exec.LookPath("javap")
- }
- // Import returns Java Class descriptors for a list of references.
- //
- // The javap command from the Java SDK is used to dump
- // class information. Its output looks like this:
- //
- // Compiled from "System.java"
- // public final class java.lang.System {
- //
- // public static final java.io.InputStream in;
- // descriptor: Ljava/io/InputStream;
- // public static final java.io.PrintStream out;
- // descriptor: Ljava/io/PrintStream;
- // public static final java.io.PrintStream err;
- // descriptor: Ljava/io/PrintStream;
- // public static void setIn(java.io.InputStream);
- // descriptor: (Ljava/io/InputStream;)V
- //
- // ...
- //
- // }
- func (j *Importer) Import(refs *importers.References) ([]*Class, error) {
- if j.clsMap == nil {
- j.clsMap = make(map[string]*Class)
- }
- clsSet := make(map[string]struct{})
- var names []string
- for _, ref := range refs.Refs {
- // The reference could be to some/pkg.Class or some/pkg/Class.Identifier. Include both.
- pkg := strings.Replace(ref.Pkg, "/", ".", -1)
- for _, cls := range []string{pkg, pkg + "." + ref.Name} {
- if _, exists := clsSet[cls]; !exists {
- clsSet[cls] = struct{}{}
- names = append(names, cls)
- }
- }
- }
- // Make sure toString() is included; it is called when wrapping Java exception types to Go
- // errors.
- refs.Names["ToString"] = struct{}{}
- funcRefs := make(map[funcRef]struct{})
- for _, ref := range refs.Refs {
- pkgName := strings.Replace(ref.Pkg, "/", ".", -1)
- funcRefs[funcRef{pkgName, ref.Name}] = struct{}{}
- }
- classes, err := j.importClasses(names, true)
- if err != nil {
- return nil, err
- }
- j.filterReferences(classes, refs, funcRefs)
- supers, err := j.importReferencedClasses(classes)
- if err != nil {
- return nil, err
- }
- j.filterReferences(supers, refs, funcRefs)
- // Embedders refer to every exported Go struct that will have its class
- // generated. Allow Go code to reverse bind to those classes by synthesizing
- // their class descriptors.
- for _, emb := range refs.Embedders {
- n := emb.Pkg + "." + emb.Name
- if j.JavaPkg != "" {
- n = j.JavaPkg + "." + n
- }
- if _, exists := j.clsMap[n]; exists {
- continue
- }
- clsSet[n] = struct{}{}
- cls := &Class{
- Name: n,
- FindName: n,
- JNIName: JNIMangle(n),
- PkgName: emb.Name,
- HasNoArgCon: true,
- }
- for _, ref := range emb.Refs {
- jpkg := strings.Replace(ref.Pkg, "/", ".", -1)
- super := jpkg + "." + ref.Name
- if _, exists := j.clsMap[super]; !exists {
- return nil, fmt.Errorf("failed to find Java class %s, embedded by %s", super, n)
- }
- cls.Supers = append(cls.Supers, super)
- }
- classes = append(classes, cls)
- j.clsMap[cls.Name] = cls
- }
- // Include implicit classes that are used in parameter or return values.
- for _, cls := range classes {
- for _, fsets := range [][]*FuncSet{cls.Funcs, cls.Methods} {
- for _, fs := range fsets {
- for _, f := range fs.Funcs {
- names := j.implicitFuncTypes(f)
- for _, name := range names {
- if _, exists := clsSet[name]; exists {
- continue
- }
- clsSet[name] = struct{}{}
- classes = append(classes, j.clsMap[name])
- }
- }
- }
- }
- }
- for _, cls := range j.clsMap {
- j.fillFuncSigs(cls.Funcs)
- j.fillFuncSigs(cls.Methods)
- for _, m := range cls.Methods {
- j.fillSuperSigs(cls, m)
- }
- }
- for _, cls := range j.clsMap {
- j.fillAllMethods(cls)
- }
- // Include classes that appear as ancestor types for overloaded signatures.
- for _, cls := range classes {
- for _, funcs := range [][]*FuncSet{cls.Funcs, cls.AllMethods} {
- for _, f := range funcs {
- for _, p := range f.Params {
- if p == nil || p.Kind != Object {
- continue
- }
- if _, exists := clsSet[p.Class]; !exists {
- clsSet[p.Class] = struct{}{}
- classes = append(classes, j.clsMap[p.Class])
- }
- }
- if t := f.Ret; t != nil && t.Kind == Object {
- if _, exists := clsSet[t.Class]; !exists {
- clsSet[t.Class] = struct{}{}
- classes = append(classes, j.clsMap[t.Class])
- }
- }
- }
- }
- }
- for _, cls := range classes {
- j.fillJNINames(cls.Funcs)
- j.fillJNINames(cls.AllMethods)
- }
- j.fillThrowables(classes)
- return classes, nil
- }
- func (j *Importer) fillJNINames(funcs []*FuncSet) {
- for _, fs := range funcs {
- for _, f := range fs.Funcs {
- f.JNIName = JNIMangle(f.Name)
- if len(fs.Funcs) > 1 {
- f.JNIName += "__" + JNIMangle(f.ArgDesc)
- }
- }
- }
- }
- // commonType finds the most specific type common to t1 and t2.
- // If t1 and t2 are both Java classes, the most specific ancestor
- // class is returned.
- // Else if the types are equal, their type is returned.
- // Finally, nil is returned, indicating no common type.
- func commonType(clsMap map[string]*Class, t1, t2 *Type) *Type {
- if t1 == nil || t2 == nil {
- return nil
- }
- if reflect.DeepEqual(t1, t2) {
- return t1
- }
- if t1.Kind != Object || t2.Kind != Object {
- // The types are fundamentally incompatible
- return nil
- }
- superSet := make(map[string]struct{})
- supers := []string{t1.Class}
- for len(supers) > 0 {
- var newSupers []string
- for _, s := range supers {
- cls := clsMap[s]
- superSet[s] = struct{}{}
- newSupers = append(newSupers, cls.Supers...)
- }
- supers = newSupers
- }
- supers = []string{t2.Class}
- for len(supers) > 0 {
- var newSupers []string
- for _, s := range supers {
- if _, exists := superSet[s]; exists {
- return &Type{Kind: Object, Class: s}
- }
- cls := clsMap[s]
- newSupers = append(newSupers, cls.Supers...)
- }
- supers = newSupers
- }
- return &Type{Kind: Object, Class: "java.lang.Object"}
- }
- // combineSigs finds the most specific function signature
- // that covers all its overload variants.
- // If a function has only one variant, its common signature
- // is the signature of that variant.
- func combineSigs(clsMap map[string]*Class, sigs ...CommonSig) CommonSig {
- var common CommonSig
- minp := len(sigs[0].Params)
- for i := 1; i < len(sigs); i++ {
- sig := sigs[i]
- n := len(sig.Params)
- common.Variadic = common.Variadic || sig.Variadic || n != minp
- if n < minp {
- minp = n
- }
- }
- for i, sig := range sigs {
- for j, p := range sig.Params {
- idx := j
- // If the common signature is variadic, combine all parameters in the
- // last parameter type of the shortest parameter list.
- if idx > minp {
- idx = minp
- }
- if idx < len(common.Params) {
- common.Params[idx] = commonType(clsMap, common.Params[idx], p)
- } else {
- common.Params = append(common.Params, p)
- }
- }
- common.Throws = common.Throws || sig.Throws
- common.HasRet = common.HasRet || sig.HasRet
- if i > 0 {
- common.Ret = commonType(clsMap, common.Ret, sig.Ret)
- } else {
- common.Ret = sig.Ret
- }
- }
- return common
- }
- // fillSuperSigs combines methods signatures with super class signatures,
- // to preserve the assignability of classes to their super classes.
- //
- // For example, the class
- //
- // class A {
- // void f();
- // }
- //
- // is by itself represented by the Go interface
- //
- // type A interface {
- // f()
- // }
- //
- // However, if class
- //
- // class B extends A {
- // void f(int);
- // }
- //
- // is also imported, it will be represented as
- //
- // type B interface {
- // f(...int32)
- // }
- //
- // To make Go B assignable to Go A, the signature of A's f must
- // be updated to f(...int32) as well.
- func (j *Importer) fillSuperSigs(cls *Class, m *FuncSet) {
- for _, s := range cls.Supers {
- sup := j.clsMap[s]
- if sm, exists := sup.methodMap[m.GoName]; exists {
- sm.CommonSig = combineSigs(j.clsMap, sm.CommonSig, m.CommonSig)
- }
- j.fillSuperSigs(sup, m)
- }
- }
- func (v *Var) Constant() bool {
- return v.Static && v.Final && v.Val != ""
- }
- // Mangle a name according to
- // http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp16696
- //
- // TODO: Support unicode characters
- func JNIMangle(s string) string {
- var m []byte
- for i := 0; i < len(s); i++ {
- switch c := s[i]; c {
- case '.', '/':
- m = append(m, '_')
- case '$':
- m = append(m, "_00024"...)
- case '_':
- m = append(m, "_1"...)
- case ';':
- m = append(m, "_2"...)
- case '[':
- m = append(m, "_3"...)
- default:
- m = append(m, c)
- }
- }
- return string(m)
- }
- func (t *Type) Type() string {
- switch t.Kind {
- case Int:
- return "int"
- case Boolean:
- return "boolean"
- case Short:
- return "short"
- case Char:
- return "char"
- case Byte:
- return "byte"
- case Long:
- return "long"
- case Float:
- return "float"
- case Double:
- return "double"
- case String:
- return "String"
- case Array:
- return t.Elem.Type() + "[]"
- case Object:
- return t.Class
- default:
- panic("invalid kind")
- }
- }
- func (t *Type) JNIType() string {
- switch t.Kind {
- case Int:
- return "jint"
- case Boolean:
- return "jboolean"
- case Short:
- return "jshort"
- case Char:
- return "jchar"
- case Byte:
- return "jbyte"
- case Long:
- return "jlong"
- case Float:
- return "jfloat"
- case Double:
- return "jdouble"
- case String:
- return "jstring"
- case Array:
- return "jarray"
- case Object:
- return "jobject"
- default:
- panic("invalid kind")
- }
- }
- func (t *Type) CType() string {
- switch t.Kind {
- case Int, Boolean, Short, Char, Byte, Long, Float, Double:
- return t.JNIType()
- case String:
- return "nstring"
- case Array:
- if t.Elem.Kind != Byte {
- panic("unsupported array type")
- }
- return "nbyteslice"
- case Object:
- return "jint"
- default:
- panic("invalid kind")
- }
- }
- func (t *Type) JNICallType() string {
- switch t.Kind {
- case Int:
- return "Int"
- case Boolean:
- return "Boolean"
- case Short:
- return "Short"
- case Char:
- return "Char"
- case Byte:
- return "Byte"
- case Long:
- return "Long"
- case Float:
- return "Float"
- case Double:
- return "Double"
- case String, Object, Array:
- return "Object"
- default:
- panic("invalid kind")
- }
- }
- func (j *Importer) filterReferences(classes []*Class, refs *importers.References, funcRefs map[funcRef]struct{}) {
- for _, cls := range classes {
- var filtered []*FuncSet
- for _, f := range cls.Funcs {
- if _, exists := funcRefs[funcRef{cls.Name, f.GoName}]; exists {
- filtered = append(filtered, f)
- }
- }
- cls.Funcs = filtered
- filtered = nil
- for _, m := range cls.Methods {
- if _, exists := refs.Names[m.GoName]; exists {
- filtered = append(filtered, m)
- }
- }
- cls.Methods = filtered
- }
- }
- // importClasses imports the named classes from the classpaths of the Importer.
- func (j *Importer) importClasses(names []string, allowMissingClasses bool) ([]*Class, error) {
- if len(names) == 0 {
- return nil, nil
- }
- args := []string{"-J-Duser.language=en", "-s", "-protected", "-constants"}
- args = append(args, "-classpath", j.Classpath)
- if j.Bootclasspath != "" {
- args = append(args, "-bootclasspath", j.Bootclasspath)
- }
- args = append(args, names...)
- javapPath, err := javapPath()
- if err != nil {
- return nil, err
- }
- javap := exec.Command(javapPath, args...)
- out, err := javap.CombinedOutput()
- if err != nil {
- if _, ok := err.(*exec.ExitError); !ok {
- return nil, fmt.Errorf("javap failed: %v", err)
- }
- // Not every name is a Java class so an exit error from javap is not
- // fatal.
- }
- s := bufio.NewScanner(bytes.NewBuffer(out))
- var classes []*Class
- for _, name := range names {
- cls, err := j.scanClass(s, name)
- if err != nil {
- _, notfound := err.(*errClsNotFound)
- if notfound && allowMissingClasses {
- continue
- }
- if notfound && name != "android.databinding.DataBindingComponent" {
- return nil, err
- }
- // The Android Databinding library generates android.databinding.DataBindingComponent
- // too late in the build process for the gobind plugin to import it. Synthesize a class
- // for it instead.
- cls = &Class{
- Name: name,
- FindName: name,
- Interface: true,
- PkgName: "databinding",
- JNIName: JNIMangle(name),
- }
- }
- classes = append(classes, cls)
- j.clsMap[name] = cls
- }
- return classes, nil
- }
- // importReferencedClasses imports all implicit classes (super types, parameter and
- // return types) for the given classes not already imported.
- func (j *Importer) importReferencedClasses(classes []*Class) ([]*Class, error) {
- var allCls []*Class
- // Include methods from extended or implemented classes.
- for {
- set := make(map[string]struct{})
- for _, cls := range classes {
- j.unknownImplicitClasses(cls, set)
- }
- if len(set) == 0 {
- break
- }
- var names []string
- for n := range set {
- names = append(names, n)
- }
- newCls, err := j.importClasses(names, false)
- if err != nil {
- return nil, err
- }
- allCls = append(allCls, newCls...)
- classes = newCls
- }
- return allCls, nil
- }
- func (j *Importer) implicitFuncTypes(f *Func) []string {
- var unk []string
- if rt := f.Ret; rt != nil && rt.Kind == Object {
- unk = append(unk, rt.Class)
- }
- for _, t := range f.Params {
- if t.Kind == Object {
- unk = append(unk, t.Class)
- }
- }
- return unk
- }
- func (j *Importer) unknownImplicitClasses(cls *Class, set map[string]struct{}) {
- for _, fsets := range [][]*FuncSet{cls.Funcs, cls.Methods} {
- for _, fs := range fsets {
- for _, f := range fs.Funcs {
- names := j.implicitFuncTypes(f)
- for _, name := range names {
- if _, exists := j.clsMap[name]; !exists {
- set[name] = struct{}{}
- }
- }
- }
- }
- }
- for _, n := range cls.Supers {
- if s, exists := j.clsMap[n]; exists {
- j.unknownImplicitClasses(s, set)
- } else {
- set[n] = struct{}{}
- }
- }
- }
- func (j *Importer) implicitFuncClasses(funcs []*FuncSet, impl []string) []string {
- var l []string
- for _, fs := range funcs {
- for _, f := range fs.Funcs {
- if rt := f.Ret; rt != nil && rt.Kind == Object {
- l = append(l, rt.Class)
- }
- for _, t := range f.Params {
- if t.Kind == Object {
- l = append(l, t.Class)
- }
- }
- }
- }
- return impl
- }
- func (j *Importer) scanClass(s *bufio.Scanner, name string) (*Class, error) {
- if !s.Scan() {
- return nil, fmt.Errorf("%s: missing javap header", name)
- }
- head := s.Text()
- if errPref := "Error: "; strings.HasPrefix(head, errPref) {
- msg := head[len(errPref):]
- if strings.HasPrefix(msg, "class not found: "+name) {
- return nil, &errClsNotFound{name}
- }
- return nil, errors.New(msg)
- }
- if !strings.HasPrefix(head, "Compiled from ") {
- return nil, fmt.Errorf("%s: unexpected header: %s", name, head)
- }
- if !s.Scan() {
- return nil, fmt.Errorf("%s: missing javap class declaration", name)
- }
- clsDecl := s.Text()
- cls, err := j.scanClassDecl(name, clsDecl)
- if err != nil {
- return nil, err
- }
- cls.JNIName = JNIMangle(cls.Name)
- clsElems := strings.Split(cls.Name, ".")
- cls.PkgName = clsElems[len(clsElems)-1]
- var funcs []*Func
- for s.Scan() {
- decl := strings.TrimSpace(s.Text())
- if decl == "}" {
- break
- } else if decl == "" {
- continue
- }
- if !s.Scan() {
- return nil, fmt.Errorf("%s: missing descriptor for member %q", name, decl)
- }
- desc := strings.TrimSpace(s.Text())
- desc = strings.TrimPrefix(desc, "descriptor: ")
- var static, final, abstract, public bool
- // Trim modifiders from the declaration.
- loop:
- for {
- idx := strings.Index(decl, " ")
- if idx == -1 {
- break
- }
- keyword := decl[:idx]
- switch keyword {
- case "public":
- public = true
- case "protected", "native":
- // ignore
- case "static":
- static = true
- case "final":
- final = true
- case "abstract":
- abstract = true
- default:
- // Hopefully we reached the declaration now.
- break loop
- }
- decl = decl[idx+1:]
- }
- // Trim ending ;
- decl = decl[:len(decl)-1]
- if idx := strings.Index(decl, "("); idx != -1 {
- f, err := j.scanMethod(decl, desc, idx)
- if err != nil {
- return nil, fmt.Errorf("%s: %v", name, err)
- }
- if f != nil {
- f.Static = static
- f.Abstract = abstract
- f.Public = public || cls.Interface
- f.Final = final
- f.Constructor = f.Name == cls.FindName
- if f.Constructor {
- cls.HasNoArgCon = cls.HasNoArgCon || len(f.Params) == 0
- f.Public = f.Public && !cls.Abstract
- f.Name = "new"
- f.Ret = &Type{Class: name, Kind: Object}
- }
- funcs = append(funcs, f)
- }
- } else {
- // Member is a variable
- v, err := j.scanVar(decl, desc)
- if err != nil {
- return nil, fmt.Errorf("%s: %v", name, err)
- }
- if v != nil && public {
- v.Static = static
- v.Final = final
- cls.Vars = append(cls.Vars, v)
- }
- }
- }
- for _, f := range funcs {
- var m map[string]*FuncSet
- var l *[]*FuncSet
- goName := initialUpper(f.Name)
- if f.Static || f.Constructor {
- m = cls.funcMap
- l = &cls.Funcs
- } else {
- m = cls.methodMap
- l = &cls.Methods
- }
- fs, exists := m[goName]
- if !exists {
- fs = &FuncSet{
- Name: f.Name,
- GoName: goName,
- }
- m[goName] = fs
- *l = append(*l, fs)
- }
- fs.Funcs = append(fs.Funcs, f)
- }
- return cls, nil
- }
- func (j *Importer) scanClassDecl(name string, decl string) (*Class, error) {
- isRoot := name == "java.lang.Object"
- cls := &Class{
- Name: name,
- funcMap: make(map[string]*FuncSet),
- methodMap: make(map[string]*FuncSet),
- HasNoArgCon: isRoot,
- }
- const (
- stMod = iota
- stName
- stExt
- stImpl
- )
- superClsDecl := isRoot
- st := stMod
- var w []byte
- // if > 0, we're inside a generics declaration
- gennest := 0
- for i := 0; i < len(decl); i++ {
- c := decl[i]
- switch c {
- default:
- if gennest == 0 {
- w = append(w, c)
- }
- case '>':
- gennest--
- case '<':
- gennest++
- case '{':
- if !superClsDecl && !cls.Interface {
- cls.Supers = append(cls.Supers, "java.lang.Object")
- }
- return cls, nil
- case ' ', ',':
- if gennest > 0 {
- break
- }
- switch w := string(w); w {
- default:
- switch st {
- case stName:
- if strings.Replace(w, "$", ".", -1) != strings.Replace(name, "$", ".", -1) {
- return nil, fmt.Errorf("unexpected name %q in class declaration: %q", w, decl)
- }
- cls.FindName = w
- case stExt:
- superClsDecl = true
- cls.Supers = append(cls.Supers, w)
- case stImpl:
- if !cls.Interface {
- cls.Supers = append(cls.Supers, w)
- }
- default:
- return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl)
- }
- case "":
- // skip
- case "public":
- if st != stMod {
- return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl)
- }
- case "abstract":
- if st != stMod {
- return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl)
- }
- cls.Abstract = true
- case "final":
- if st != stMod {
- return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl)
- }
- cls.Final = true
- case "interface":
- cls.Interface = true
- fallthrough
- case "class":
- if st != stMod {
- return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl)
- }
- st = stName
- case "extends":
- if st != stName {
- return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl)
- }
- st = stExt
- case "implements":
- if st != stName && st != stExt {
- return nil, fmt.Errorf("unexpected %q in class declaration: %q", w, decl)
- }
- st = stImpl
- }
- w = w[:0]
- }
- }
- return nil, fmt.Errorf("missing ending { in class declaration: %q", decl)
- }
- func (j *Importer) scanVar(decl, desc string) (*Var, error) {
- v := new(Var)
- const eq = " = "
- idx := strings.Index(decl, eq)
- if idx != -1 {
- val, ok := j.parseJavaValue(decl[idx+len(eq):])
- if !ok {
- // Skip constants that cannot be represented in Go
- return nil, nil
- }
- v.Val = val
- } else {
- idx = len(decl)
- }
- for i := idx - 1; i >= 0; i-- {
- if i == 0 || decl[i-1] == ' ' {
- v.Name = decl[i:idx]
- break
- }
- }
- if v.Name == "" {
- return nil, fmt.Errorf("unable to parse member name from declaration: %q", decl)
- }
- typ, _, err := j.parseJavaType(desc)
- if err != nil {
- return nil, fmt.Errorf("invalid type signature for %s: %q", v.Name, desc)
- }
- v.Type = typ
- return v, nil
- }
- func (j *Importer) scanMethod(decl, desc string, parenIdx int) (*Func, error) {
- // Member is a method
- f := new(Func)
- f.Desc = desc
- for i := parenIdx - 1; i >= 0; i-- {
- if i == 0 || decl[i-1] == ' ' {
- f.Name = decl[i:parenIdx]
- break
- }
- }
- if f.Name == "" {
- return nil, fmt.Errorf("unable to parse method name from declaration: %q", decl)
- }
- if desc[0] != '(' {
- return nil, fmt.Errorf("invalid descriptor for method %s: %q", f.Name, desc)
- }
- const throws = " throws "
- if idx := strings.Index(decl, throws); idx != -1 {
- f.Throws = decl[idx+len(throws):]
- }
- i := 1
- for desc[i] != ')' {
- typ, n, err := j.parseJavaType(desc[i:])
- if err != nil {
- return nil, fmt.Errorf("invalid descriptor for method %s: %v", f.Name, err)
- }
- i += n
- f.Params = append(f.Params, typ)
- }
- f.ArgDesc = desc[1:i]
- i++ // skip ending )
- if desc[i] != 'V' {
- typ, _, err := j.parseJavaType(desc[i:])
- if err != nil {
- return nil, fmt.Errorf("invalid descriptor for method %s: %v", f.Name, err)
- }
- f.Ret = typ
- }
- return f, nil
- }
- func (j *Importer) fillThrowables(classes []*Class) {
- thrCls, ok := j.clsMap["java.lang.Throwable"]
- if !ok {
- // If Throwable isn't in the class map
- // no imported class inherits from Throwable
- return
- }
- for _, cls := range classes {
- j.fillThrowableFor(cls, thrCls)
- }
- }
- func (j *Importer) fillThrowableFor(cls, thrCls *Class) {
- if cls.Interface || cls.Throwable {
- return
- }
- cls.Throwable = cls == thrCls
- for _, name := range cls.Supers {
- sup := j.clsMap[name]
- j.fillThrowableFor(sup, thrCls)
- cls.Throwable = cls.Throwable || sup.Throwable
- }
- }
- func commonSig(f *Func) CommonSig {
- return CommonSig{
- Params: f.Params,
- Ret: f.Ret,
- HasRet: f.Ret != nil,
- Throws: f.Throws != "",
- }
- }
- func (j *Importer) fillFuncSigs(funcs []*FuncSet) {
- for _, fs := range funcs {
- var sigs []CommonSig
- for _, f := range fs.Funcs {
- sigs = append(sigs, commonSig(f))
- }
- fs.CommonSig = combineSigs(j.clsMap, sigs...)
- }
- }
- func (j *Importer) fillAllMethods(cls *Class) {
- if len(cls.AllMethods) > 0 {
- return
- }
- for _, supName := range cls.Supers {
- super := j.clsMap[supName]
- j.fillAllMethods(super)
- }
- var fsets []*FuncSet
- fsets = append(fsets, cls.Methods...)
- for _, supName := range cls.Supers {
- super := j.clsMap[supName]
- fsets = append(fsets, super.AllMethods...)
- }
- sigs := make(map[FuncSig]struct{})
- methods := make(map[string]*FuncSet)
- for _, fs := range fsets {
- clsFs, exists := methods[fs.Name]
- if !exists {
- clsFs = &FuncSet{
- Name: fs.Name,
- GoName: fs.GoName,
- CommonSig: fs.CommonSig,
- }
- cls.AllMethods = append(cls.AllMethods, clsFs)
- methods[fs.Name] = clsFs
- } else {
- // Combine the (overloaded) signature with the other variants.
- clsFs.CommonSig = combineSigs(j.clsMap, clsFs.CommonSig, fs.CommonSig)
- }
- for _, f := range fs.Funcs {
- if _, exists := sigs[f.FuncSig]; exists {
- continue
- }
- sigs[f.FuncSig] = struct{}{}
- clsFs.Funcs = append(clsFs.Funcs, f)
- }
- }
- }
- func (j *Importer) parseJavaValue(v string) (string, bool) {
- v = strings.TrimRight(v, "ldf")
- switch v {
- case "", "NaN", "Infinity", "-Infinity":
- return "", false
- default:
- if v[0] == '\'' {
- // Skip character constants, since they can contain invalid code points
- // that are unacceptable to Go.
- return "", false
- }
- return v, true
- }
- }
- func (j *Importer) parseJavaType(desc string) (*Type, int, error) {
- t := new(Type)
- var n int
- if desc == "" {
- return t, n, errors.New("empty type signature")
- }
- n++
- switch desc[0] {
- case 'Z':
- t.Kind = Boolean
- case 'B':
- t.Kind = Byte
- case 'C':
- t.Kind = Char
- case 'S':
- t.Kind = Short
- case 'I':
- t.Kind = Int
- case 'J':
- t.Kind = Long
- case 'F':
- t.Kind = Float
- case 'D':
- t.Kind = Double
- case 'L':
- var clsName string
- for i := n; i < len(desc); i++ {
- if desc[i] == ';' {
- clsName = strings.Replace(desc[n:i], "/", ".", -1)
- clsName = strings.Replace(clsName, "$", ".", -1)
- n += i - n + 1
- break
- }
- }
- if clsName == "" {
- return t, n, errors.New("missing ; in class type signature")
- }
- if clsName == "java.lang.String" {
- t.Kind = String
- } else {
- t.Kind = Object
- t.Class = clsName
- }
- case '[':
- et, n2, err := j.parseJavaType(desc[n:])
- if err != nil {
- return t, n, err
- }
- n += n2
- t.Kind = Array
- t.Elem = et
- default:
- return t, n, fmt.Errorf("invalid type signature: %s", desc)
- }
- return t, n, nil
- }
- func initialUpper(s string) string {
- if s == "" {
- return ""
- }
- r, n := utf8.DecodeRuneInString(s)
- return string(unicode.ToUpper(r)) + s[n:]
- }
|