func (g *JavaGen) genConstructor(f *types.Func, n string, jcls bool) { g.Printf("public %s(", n) g.genFuncArgs(f, nil, false) g.Printf(") {\n") g.Indent() sig := f.Type().(*types.Signature) params := sig.Params() if jcls { g.Printf("super(") for i := 0; i < params.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf(g.paramName(params, i)) } g.Printf(");\n") } g.Printf("this.ref = ") g.Printf("__%s(", f.Name()) for i := 0; i < params.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf(g.paramName(params, i)) } g.Printf(");\n") g.Outdent() g.Printf("}\n\n") g.Printf("private static native Seq.Ref __%s(", f.Name()) g.genFuncArgs(f, nil, false) g.Printf(");\n\n") }
func (g *goGen) genFuncSignature(o *types.Func, objName string) { g.Printf("//export proxy%s_%s_%s\n", g.pkgPrefix, objName, o.Name()) g.Printf("func proxy%s_%s_%s(", g.pkgPrefix, objName, o.Name()) if objName != "" { g.Printf("refnum C.int32_t") } sig := o.Type().(*types.Signature) params := sig.Params() for i := 0; i < params.Len(); i++ { if objName != "" || i > 0 { g.Printf(", ") } p := params.At(i) g.Printf("param_%s C.%s", g.paramName(params, i), g.cgoType(p.Type())) } g.Printf(") ") res := sig.Results() if res.Len() > 0 { g.Printf("(") for i := 0; i < res.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("C.%s", g.cgoType(res.At(i).Type())) } g.Printf(") ") } g.Printf("{\n") }
func (g *goGen) genFunc(o *types.Func) { g.Printf("func proxy_%s(out, in *seq.Buffer) {\n", o.Name()) g.Indent() g.genFuncBody(o, g.pkg.Name()) g.Outdent() g.Printf("}\n\n") }
func findMethod(prog *ssa.Program, meth *types.Func, typ types.Type, infer *TypeInfer) *ssa.Function { if meth != nil { return prog.LookupMethod(typ, meth.Pkg(), meth.Name()) } infer.Logger.Fatal(ErrMethodNotFound) return nil }
func (g *javaGen) genMethodInterfaceProxy(oName string, m *types.Func) { if !g.isSigSupported(m.Type()) { g.Printf("// skipped method %s with unsupported parameter or return types\n\n", oName) return } sig := m.Type().(*types.Signature) params := sig.Params() res := sig.Results() g.genInterfaceMethodSignature(m, oName, false) g.Indent() // Push a JNI reference frame with a conservative capacity of two for each per parameter (Seq.Ref and Seq.Object), // plus extra space for the receiver, the return value, and exception (if any). g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", 2*params.Len()+10) g.Printf("jobject o = go_seq_from_refnum(env, refnum, proxy_class_%s_%s, proxy_class_%s_%s_cons);\n", g.pkgPrefix, oName, g.pkgPrefix, oName) for i := 0; i < params.Len(); i++ { pn := paramName(params, i) g.genCToJava("_"+pn, pn, params.At(i).Type(), modeTransient) } if res.Len() > 0 && !isErrorType(res.At(0).Type()) { t := res.At(0).Type() g.Printf("%s res = (*env)->Call%sMethod(env, o, ", g.jniType(t), g.jniCallType(t)) } else { g.Printf("(*env)->CallVoidMethod(env, o, ") } g.Printf("mid_%s_%s", oName, m.Name()) for i := 0; i < params.Len(); i++ { g.Printf(", _%s", paramName(params, i)) } g.Printf(");\n") var retName string if res.Len() > 0 { var rets []string t := res.At(0).Type() if !isErrorType(t) { g.genJavaToC("res", t, modeRetained) retName = "_res" rets = append(rets, retName) } if res.Len() == 2 || isErrorType(t) { g.Printf("jstring exc = go_seq_get_exception_message(env);\n") st := types.Typ[types.String] g.genJavaToC("exc", st, modeRetained) retName = "_exc" rets = append(rets, "_exc") } if res.Len() > 1 { g.Printf("cproxy%s_%s_%s_return sres = {\n", g.pkgPrefix, oName, m.Name()) g.Printf(" %s\n", strings.Join(rets, ", ")) g.Printf("};\n") retName = "sres" } } g.Printf("go_seq_pop_local_frame(env);\n") if retName != "" { g.Printf("return %s;\n", retName) } g.Outdent() g.Printf("}\n\n") }
func (w *Walker) emitFunc(f *types.Func) { sig := f.Type().(*types.Signature) if sig.Recv() != nil { panic("method considered a regular function: " + f.String()) } w.emitf("func %s%s", f.Name(), w.signatureString(sig)) }
func (g *javaGen) genFunc(o *types.Func, method bool) { if err := g.funcSignature(o, !method); err != nil { g.errorf("%v", err) return } sig := o.Type().(*types.Signature) res := sig.Results() g.Printf(" {\n") g.Indent() g.Printf("go.Seq _in = null;\n") g.Printf("go.Seq _out = null;\n") returnsError := false var resultType types.Type if res.Len() > 0 { if !isErrorType(res.At(0).Type()) { resultType = res.At(0).Type() } if res.Len() > 1 || isErrorType(res.At(0).Type()) { returnsError = true } } if resultType != nil || returnsError { g.Printf("_out = new go.Seq();\n") } if resultType != nil { t := g.javaType(resultType) g.Printf("%s _result;\n", t) } params := sig.Params() if method || params.Len() > 0 { g.Printf("_in = new go.Seq();\n") } if method { g.Printf("_in.writeRef(ref);\n") } for i := 0; i < params.Len(); i++ { p := params.At(i) g.Printf("_in.write%s;\n", seqWrite(p.Type(), paramName(params, i))) } g.Printf("Seq.send(DESCRIPTOR, CALL_%s, _in, _out);\n", o.Name()) if resultType != nil { g.genRead("_result", "_out", resultType) } if returnsError { g.Printf(`String _err = _out.readString(); if (_err != null && !_err.isEmpty()) { throw new Exception(_err); } `) } if resultType != nil { g.Printf("return _result;\n") } g.Outdent() g.Printf("}\n\n") }
func GoProto(fn *types.Func) (string, string, string) { pkgname := "package " + fn.Pkg().Name() + "\n" imports := "" signature := fn.Type().(*types.Signature) sig := strings.TrimPrefix(signature.String(), "func(") fnproto := "func " + fn.Name() + "(" + sig + "\n" return pkgname, imports, fnproto }
func (g *JavaGen) genMethodInterfaceProxy(oName string, m *types.Func) { if !g.isSigSupported(m.Type()) { g.Printf("// skipped method %s with unsupported parameter or return types\n\n", oName) return } sig := m.Type().(*types.Signature) params := sig.Params() res := sig.Results() g.genInterfaceMethodSignature(m, oName, false, g.paramName) g.Indent() g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", params.Len()) g.Printf("jobject o = go_seq_from_refnum(env, refnum, proxy_class_%s_%s, proxy_class_%s_%s_cons);\n", g.pkgPrefix, oName, g.pkgPrefix, oName) for i := 0; i < params.Len(); i++ { pn := g.paramName(params, i) g.genCToJava("_"+pn, pn, params.At(i).Type(), modeTransient) } if res.Len() > 0 && !isErrorType(res.At(0).Type()) { t := res.At(0).Type() g.Printf("%s res = (*env)->Call%sMethod(env, o, ", g.jniType(t), g.jniCallType(t)) } else { g.Printf("(*env)->CallVoidMethod(env, o, ") } g.Printf("mid_%s_%s", oName, m.Name()) for i := 0; i < params.Len(); i++ { g.Printf(", _%s", g.paramName(params, i)) } g.Printf(");\n") var retName string if res.Len() > 0 { var rets []string t := res.At(0).Type() if !isErrorType(t) { g.genJavaToC("res", t, modeRetained) retName = "_res" rets = append(rets, retName) } if res.Len() == 2 || isErrorType(t) { g.Printf("jobject exc = go_seq_get_exception(env);\n") errType := types.Universe.Lookup("error").Type() g.genJavaToC("exc", errType, modeRetained) retName = "_exc" rets = append(rets, "_exc") } if res.Len() > 1 { g.Printf("cproxy%s_%s_%s_return sres = {\n", g.pkgPrefix, oName, m.Name()) g.Printf(" %s\n", strings.Join(rets, ", ")) g.Printf("};\n") retName = "sres" } } g.Printf("go_seq_pop_local_frame(env);\n") if retName != "" { g.Printf("return %s;\n", retName) } g.Outdent() g.Printf("}\n\n") }
func (g *JavaGen) genJNIFuncBody(o *types.Func, sName string, jm *java.Func, isjava bool) { sig := o.Type().(*types.Signature) res := sig.Results() if sName != "" { g.Printf("int32_t o = go_seq_to_refnum_go(env, __this__);\n") } params := sig.Params() first := 0 if isjava && params.Len() > 0 && params.At(0).Name() == "this" { // Start after the implicit this argument. first = 1 g.Printf("int32_t _%s = go_seq_to_refnum(env, __this__);\n", g.paramName(params, 0)) } for i := first; i < params.Len(); i++ { name := g.paramName(params, i) g.genJavaToC(name, params.At(i).Type(), modeTransient) } resPrefix := "" if res.Len() > 0 { if res.Len() == 1 { g.Printf("%s r0 = ", g.cgoType(res.At(0).Type())) } else { resPrefix = "res." g.Printf("struct proxy%s_%s_%s_return res = ", g.pkgPrefix, sName, o.Name()) } } g.Printf("proxy%s_%s_%s(", g.pkgPrefix, sName, o.Name()) if sName != "" { g.Printf("o") } // Pass all arguments, including the implicit this argument. for i := 0; i < params.Len(); i++ { if i > 0 || sName != "" { g.Printf(", ") } g.Printf("_%s", g.paramName(params, i)) } g.Printf(");\n") for i := first; i < params.Len(); i++ { g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient) } for i := 0; i < res.Len(); i++ { tn := fmt.Sprintf("_r%d", i) t := res.At(i).Type() g.genCToJava(tn, fmt.Sprintf("%sr%d", resPrefix, i), t, modeRetained) } // Go backwards so that any exception is thrown before // the return. for i := res.Len() - 1; i >= 0; i-- { t := res.At(i).Type() if !isErrorType(t) { g.Printf("return _r%d;\n", i) } else { g.Printf("go_seq_maybe_throw_exception(env, _r%d);\n", i) } } }
func (g *ObjcGen) genFuncH(obj *types.Func) { if !g.isSigSupported(obj.Type()) { g.Printf("// skipped function %s with unsupported parameter or return types\n\n", obj.Name()) return } if s := g.funcSummary(nil, obj); s != nil { g.Printf("FOUNDATION_EXPORT %s;\n", s.asFunc(g)) } }
// lookupMethod returns the method set for type typ, which may be one // of the interpreter's fake types. func lookupMethod(i *interpreter, typ types.Type, meth *types.Func) *ssa.Function { switch typ { case rtypeType: return i.rtypeMethods[meth.Id()] case errorType: return i.errorMethods[meth.Id()] } return i.prog.LookupMethod(typ, meth.Pkg(), meth.Name()) }
func (g *goGen) genFunc(o *types.Func) { if !g.isSigSupported(o.Type()) { g.Printf("// skipped function %s with unsupported parameter or result types\n", o.Name()) return } g.genFuncSignature(o, "") g.Indent() g.genFuncBody(o, g.pkgName(g.Pkg)) g.Outdent() g.Printf("}\n\n") }
func (p *printer) printFunc(recvType types.Type, obj *types.Func) { p.print("func ") sig := obj.Type().(*types.Signature) if recvType != nil { p.print("(") p.writeType(p.pkg, recvType) p.print(") ") } p.print(obj.Name()) p.writeSignature(p.pkg, sig) }
func (g *javaGen) genFuncSignature(o *types.Func, static, header bool) { sig := o.Type().(*types.Signature) res := sig.Results() var returnsError bool var ret string switch res.Len() { case 2: if !isErrorType(res.At(1).Type()) { g.errorf("second result value must be of type error: %s", o) return } returnsError = true ret = g.javaType(res.At(0).Type()) case 1: if isErrorType(res.At(0).Type()) { returnsError = true ret = "void" } else { ret = g.javaType(res.At(0).Type()) } case 0: ret = "void" default: g.errorf("too many result values: %s", o) return } g.Printf("public ") if static { g.Printf("static ") } if !header { g.Printf("native ") } oName := o.Name() g.Printf("%s %s(", ret, oName) params := sig.Params() for i := 0; i < params.Len(); i++ { if i > 0 { g.Printf(", ") } v := sig.Params().At(i) name := paramName(params, i) jt := g.javaType(v.Type()) g.Printf("%s %s", jt, name) } g.Printf(")") if returnsError { g.Printf(" throws Exception") } g.Printf(";\n") }
func (g *JavaGen) genFuncSignature(o *types.Func, jm *java.Func, hasThis bool) { sig := o.Type().(*types.Signature) res := sig.Results() var returnsError bool var ret string switch res.Len() { case 2: if !isErrorType(res.At(1).Type()) { g.errorf("second result value must be of type error: %s", o) return } returnsError = true ret = g.javaType(res.At(0).Type()) case 1: if isErrorType(res.At(0).Type()) { returnsError = true ret = "void" } else { ret = g.javaType(res.At(0).Type()) } case 0: ret = "void" default: g.errorf("too many result values: %s", o) return } g.Printf("%s ", ret) if jm != nil { g.Printf(jm.Name) } else { g.Printf(javaNameReplacer(lowerFirst(o.Name()))) } g.Printf("(") g.genFuncArgs(o, jm, hasThis) g.Printf(")") if returnsError { if jm != nil { if jm.Throws == "" { g.errorf("%s declares an error return value but the overriden method does not throw", o) return } g.Printf(" throws %s", jm.Throws) } else { g.Printf(" throws Exception") } } g.Printf(";\n") }
func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) { sig := o.Type().(*types.Signature) params := sig.Params() for i := 0; i < params.Len(); i++ { p := params.At(i) pn := "param_" + g.paramName(params, i) g.genRead("_"+pn, pn, p.Type(), modeTransient) } res := sig.Results() if res.Len() > 2 || res.Len() == 2 && !isErrorType(res.At(1).Type()) { g.errorf("functions and methods must return either zero or one values, and optionally an error") return } if res.Len() > 0 { for i := 0; i < res.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("res_%d", i) } g.Printf(" := ") } g.Printf("%s%s(", selectorLHS, o.Name()) for i := 0; i < params.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("_param_%s", g.paramName(params, i)) } g.Printf(")\n") for i := 0; i < res.Len(); i++ { pn := fmt.Sprintf("res_%d", i) g.genWrite("_"+pn, pn, res.At(i).Type(), modeRetained) } if res.Len() > 0 { g.Printf("return ") for i := 0; i < res.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("_res_%d", i) } g.Printf("\n") } }
func (g *JavaGen) genJNIConstructor(f *types.Func, sName string) { if !g.isSigSupported(f.Type()) { return } sig := f.Type().(*types.Signature) res := sig.Results() g.Printf("JNIEXPORT jobject JNICALL\n") g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz", g.jniPkgName(), sName, java.JNIMangle("__"+f.Name())) params := sig.Params() for i := 0; i < params.Len(); i++ { v := params.At(i) jt := g.jniType(v.Type()) g.Printf(", %s %s", jt, g.paramName(params, i)) } g.Printf(") {\n") g.Indent() for i := 0; i < params.Len(); i++ { name := g.paramName(params, i) g.genJavaToC(name, params.At(i).Type(), modeTransient) } // Constructors always return a mandatory *T and an optional error if res.Len() == 1 { g.Printf("int32_t refnum = proxy%s__%s(", g.pkgPrefix, f.Name()) } else { g.Printf("struct proxy%s__%s_return res = proxy%s__%s(", g.pkgPrefix, f.Name(), g.pkgPrefix, f.Name()) } for i := 0; i < params.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("_%s", g.paramName(params, i)) } g.Printf(");\n") for i := 0; i < params.Len(); i++ { g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient) } // Extract multi returns and handle errors if res.Len() == 2 { g.Printf("int32_t refnum = res.r0;\n") g.genCToJava("_err", "res.r1", res.At(1).Type(), modeRetained) g.Printf("go_seq_maybe_throw_exception(env, _err);\n") } // Pass no proxy class so that the Seq.Ref is returned instead. g.Printf("return go_seq_from_refnum(env, refnum, NULL, NULL);\n") g.Outdent() g.Printf("}\n\n") }
func (c *converter) convertFunc(v *gotypes.Func) *types.Func { if v == nil { return nil } if v, ok := c.converted[v]; ok { return v.(*types.Func) } ret := types.NewFunc( token.Pos(v.Pos()), c.ret, v.Name(), c.convertSignature(v.Type().(*gotypes.Signature)), ) c.converted[v] = ret return ret }
func (g *javaGen) genJNIFuncSignature(o *types.Func, sName string, proxy bool) { sig := o.Type().(*types.Signature) res := sig.Results() var ret string switch res.Len() { case 2: ret = g.jniType(res.At(0).Type()) case 1: if isErrorType(res.At(0).Type()) { ret = "void" } else { ret = g.jniType(res.At(0).Type()) } case 0: ret = "void" default: g.errorf("too many result values: %s", o) return } g.Printf("JNIEXPORT %s JNICALL\n", ret) g.Printf("Java_%s_%s", g.jniPkgName(), g.className()) if sName != "" { // 0024 is the mangled form of $, for naming inner classes. g.Printf("_00024") if proxy { g.Printf("proxy") } g.Printf("%s", sName) } g.Printf("_%s(JNIEnv* env, ", o.Name()) if sName != "" { g.Printf("jobject this") } else { g.Printf("jclass clazz") } params := sig.Params() for i := 0; i < params.Len(); i++ { g.Printf(", ") v := sig.Params().At(i) name := paramName(params, i) jt := g.jniType(v.Type()) g.Printf("%s %s", jt, name) } g.Printf(")") }
func (g *JavaGen) genJNIFunc(o *types.Func, sName string, jm *java.Func, proxy, isjava bool) { if !g.isSigSupported(o.Type()) { n := o.Name() if sName != "" { n = sName + "." + n } g.Printf("// skipped function %s with unsupported parameter or return types\n\n", n) return } g.genJNIFuncSignature(o, sName, jm, proxy, isjava) g.Printf(" {\n") g.Indent() g.genJNIFuncBody(o, sName, jm, isjava) g.Outdent() g.Printf("}\n\n") }
func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) { sig := o.Type().(*types.Signature) params := sig.Params() for i := 0; i < params.Len(); i++ { p := params.At(i) g.genRead("param_"+paramName(params, i), "in", p.Type()) } res := sig.Results() if res.Len() > 2 || res.Len() == 2 && !isErrorType(res.At(1).Type()) { g.errorf("functions and methods must return either zero or one values, and optionally an error") return } returnsValue := false returnsError := false if res.Len() == 1 { if isErrorType(res.At(0).Type()) { returnsError = true g.Printf("err := ") } else { returnsValue = true g.Printf("res := ") } } else if res.Len() == 2 { returnsValue = true returnsError = true g.Printf("res, err := ") } g.Printf("%s.%s(", selectorLHS, o.Name()) for i := 0; i < params.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("param_%s", paramName(params, i)) } g.Printf(")\n") if returnsValue { g.genWrite("res", "out", res.At(0).Type()) } if returnsError { g.genWrite("err", "out", res.At(res.Len()-1).Type()) } }
func checkFuncValue(t *testing.T, prog *ssa.Program, obj *types.Func) { fn := prog.FuncValue(obj) // fmt.Printf("FuncValue(%s) = %s\n", obj, fn) // debugging if fn == nil { if obj.Name() != "interfaceMethod" { t.Errorf("FuncValue(%s) == nil", obj) } return } if fnobj := fn.Object(); fnobj != obj { t.Errorf("FuncValue(%s).Object() == %s; value was %s", obj, fnobj, fn.Name()) return } if !types.Identical(fn.Type(), obj.Type()) { t.Errorf("FuncValue(%s).Type() == %s", obj, fn.Type()) return } }
// makeBound returns a bound method wrapper (or "bound"), a synthetic // function that delegates to a concrete or interface method denoted // by obj. The resulting function has no receiver, but has one free // variable which will be used as the method's receiver in the // tail-call. // // Use MakeClosure with such a wrapper to construct a bound method // closure. e.g.: // // type T int or: type T interface { meth() } // func (t T) meth() // var t T // f := t.meth // f() // calls t.meth() // // f is a closure of a synthetic wrapper defined as if by: // // f := func() { return t.meth() } // // Unlike makeWrapper, makeBound need perform no indirection or field // selections because that can be done before the closure is // constructed. // // EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu) // func makeBound(prog *Program, obj *types.Func) *Function { prog.methodsMu.Lock() defer prog.methodsMu.Unlock() fn, ok := prog.bounds[obj] if !ok { description := fmt.Sprintf("bound method wrapper for %s", obj) if prog.mode&LogSource != 0 { defer logStack("%s", description)() } fn = &Function{ name: obj.Name() + "$bound", object: obj, Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver Synthetic: description, Prog: prog, pos: obj.Pos(), } fv := &FreeVar{name: "recv", typ: recvType(obj), parent: fn} fn.FreeVars = []*FreeVar{fv} fn.startBody() createParams(fn, 0) var c Call if !isInterface(recvType(obj)) { // concrete c.Call.Value = prog.declaredFunc(obj) c.Call.Args = []Value{fv} } else { c.Call.Value = fv c.Call.Method = obj } for _, arg := range fn.Params { c.Call.Args = append(c.Call.Args, arg) } emitTailCall(fn, &c) fn.finishBody() prog.bounds[obj] = fn } return fn }
// constructorType returns the type T for a function of the forms: // // func NewT...(...) *T // func NewT...(...) (*T, error) func (g *Generator) constructorType(f *types.Func) *types.TypeName { sig := f.Type().(*types.Signature) res := sig.Results() if res.Len() != 1 && !(res.Len() == 2 && isErrorType(res.At(1).Type())) { return nil } rt := res.At(0).Type() pt, ok := rt.(*types.Pointer) if !ok { return nil } nt, ok := pt.Elem().(*types.Named) if !ok { return nil } obj := nt.Obj() if !strings.HasPrefix(f.Name(), "New"+obj.Name()) { return nil } return obj }
func (p *exporter) method(m *types.Func) { sig := m.Type().(*types.Signature) if sig.Recv() == nil { log.Fatalf("gcimporter: method expected") } p.pos(m) p.string(m.Name()) if m.Name() != "_" && !ast.IsExported(m.Name()) { p.pkg(m.Pkg(), false) } // interface method; no need to encode receiver. p.paramList(sig.Params(), sig.Variadic()) p.paramList(sig.Results(), false) }
func (g *generator) genInterfaceMethodSignature(m *types.Func, iName string, header bool) { sig := m.Type().(*types.Signature) params := sig.Params() res := sig.Results() if res.Len() == 0 { g.Printf("void ") } else { if res.Len() == 1 { g.Printf("%s ", g.cgoType(res.At(0).Type())) } else { if header { g.Printf("typedef struct cproxy%s_%s_%s_return {\n", g.pkgPrefix, iName, m.Name()) g.Indent() for i := 0; i < res.Len(); i++ { t := res.At(i).Type() g.Printf("%s r%d;\n", g.cgoType(t), i) } g.Outdent() g.Printf("} cproxy%s_%s_%s_return;\n", g.pkgPrefix, iName, m.Name()) } g.Printf("struct cproxy%s_%s_%s_return ", g.pkgPrefix, iName, m.Name()) } } g.Printf("cproxy%s_%s_%s(int32_t refnum", g.pkgPrefix, iName, m.Name()) for i := 0; i < params.Len(); i++ { t := params.At(i).Type() g.Printf(", %s %s", g.cgoType(t), paramName(params, i)) } g.Printf(")") if header { g.Printf(";\n") } else { g.Printf(" {\n") } }
// Implements displays the "implements" relation as it pertains to the // selected type. // If the selection is a method, 'implements' displays // the corresponding methods of the types that would have been reported // by an implements query on the receiver type. // func implements(q *Query) error { lconf := loader.Config{Build: q.Build} allowErrors(&lconf) qpkg, err := importQueryPackage(q.Pos, &lconf) if err != nil { return err } // Set the packages to search. if len(q.Scope) > 0 { // Inspect all packages in the analysis scope, if specified. if err := setPTAScope(&lconf, q.Scope); err != nil { return err } } else { // Otherwise inspect the forward and reverse // transitive closure of the selected package. // (In theory even this is incomplete.) _, rev, _ := importgraph.Build(q.Build) for path := range rev.Search(qpkg) { lconf.ImportWithTests(path) } // TODO(adonovan): for completeness, we should also // type-check and inspect function bodies in all // imported packages. This would be expensive, but we // could optimize by skipping functions that do not // contain type declarations. This would require // changing the loader's TypeCheckFuncBodies hook to // provide the []*ast.File. } // Load/parse/type-check the program. lprog, err := lconf.Load() if err != nil { return err } q.Fset = lprog.Fset qpos, err := parseQueryPos(lprog, q.Pos, false) if err != nil { return err } // Find the selected type. path, action := findInterestingNode(qpos.info, qpos.path) var method *types.Func var T types.Type // selected type (receiver if method != nil) switch action { case actionExpr: // method? if id, ok := path[0].(*ast.Ident); ok { if obj, ok := qpos.info.ObjectOf(id).(*types.Func); ok { recv := obj.Type().(*types.Signature).Recv() if recv == nil { return fmt.Errorf("this function is not a method") } method = obj T = recv.Type() } } case actionType: T = qpos.info.TypeOf(path[0].(ast.Expr)) } if T == nil { return fmt.Errorf("no type or method here") } // Find all named types, even local types (which can have // methods via promotion) and the built-in "error". var allNamed []types.Type for _, info := range lprog.AllPackages { for _, obj := range info.Defs { if obj, ok := obj.(*types.TypeName); ok { allNamed = append(allNamed, obj.Type()) } } } allNamed = append(allNamed, types.Universe.Lookup("error").Type()) var msets typeutil.MethodSetCache // Test each named type. var to, from, fromPtr []types.Type for _, U := range allNamed { if isInterface(T) { if msets.MethodSet(T).Len() == 0 { continue // empty interface } if isInterface(U) { if msets.MethodSet(U).Len() == 0 { continue // empty interface } // T interface, U interface if !types.Identical(T, U) { if types.AssignableTo(U, T) { to = append(to, U) } if types.AssignableTo(T, U) { from = append(from, U) } } } else { // T interface, U concrete if types.AssignableTo(U, T) { to = append(to, U) } else if pU := types.NewPointer(U); types.AssignableTo(pU, T) { to = append(to, pU) } } } else if isInterface(U) { if msets.MethodSet(U).Len() == 0 { continue // empty interface } // T concrete, U interface if types.AssignableTo(T, U) { from = append(from, U) } else if pT := types.NewPointer(T); types.AssignableTo(pT, U) { fromPtr = append(fromPtr, U) } } } var pos interface{} = qpos if nt, ok := deref(T).(*types.Named); ok { pos = nt.Obj() } // Sort types (arbitrarily) to ensure test determinism. sort.Sort(typesByString(to)) sort.Sort(typesByString(from)) sort.Sort(typesByString(fromPtr)) var toMethod, fromMethod, fromPtrMethod []*types.Selection // contain nils if method != nil { for _, t := range to { toMethod = append(toMethod, types.NewMethodSet(t).Lookup(method.Pkg(), method.Name())) } for _, t := range from { fromMethod = append(fromMethod, types.NewMethodSet(t).Lookup(method.Pkg(), method.Name())) } for _, t := range fromPtr { fromPtrMethod = append(fromPtrMethod, types.NewMethodSet(t).Lookup(method.Pkg(), method.Name())) } } q.result = &implementsResult{ qpos, T, pos, to, from, fromPtr, method, toMethod, fromMethod, fromPtrMethod, } return nil }
func (g *objcGen) funcSummary(obj *types.Func) *funcSummary { s := &funcSummary{name: obj.Name()} sig := obj.Type().(*types.Signature) params := sig.Params() for i := 0; i < params.Len(); i++ { p := params.At(i) v := paramInfo{ typ: p.Type(), name: paramName(params, i), } s.params = append(s.params, v) } res := sig.Results() switch res.Len() { case 0: s.ret = "void" case 1: p := res.At(0) if isErrorType(p.Type()) { s.retParams = append(s.retParams, paramInfo{ typ: p.Type(), name: "error", }) s.ret = "BOOL" } else { name := p.Name() if name == "" || paramRE.MatchString(name) { name = "ret0_" } typ := p.Type() s.retParams = append(s.retParams, paramInfo{typ: typ, name: name}) s.ret = g.objcType(typ) } case 2: name := res.At(0).Name() if name == "" || paramRE.MatchString(name) { name = "ret0_" } s.retParams = append(s.retParams, paramInfo{ typ: res.At(0).Type(), name: name, }) if !isErrorType(res.At(1).Type()) { g.errorf("second result value must be of type error: %s", obj) return nil } s.retParams = append(s.retParams, paramInfo{ typ: res.At(1).Type(), name: "error", // TODO(hyangah): name collision check. }) s.ret = "BOOL" default: // TODO(hyangah): relax the constraint on multiple return params. g.errorf("too many result values: %s", obj) return nil } return s }
// On success, findObjects returns the list of objects named // spec.fromName matching the spec. On success, the result has exactly // one element unless spec.searchFor!="", in which case it has at least one // element. // func findObjects(info *loader.PackageInfo, spec *spec) ([]types.Object, error) { if spec.pkgMember == "" { if spec.searchFor == "" { panic(spec) } objects := searchDefs(&info.Info, spec.searchFor) if objects == nil { return nil, fmt.Errorf("no object %q declared in package %q", spec.searchFor, info.Pkg.Path()) } return objects, nil } pkgMember := info.Pkg.Scope().Lookup(spec.pkgMember) if pkgMember == nil { return nil, fmt.Errorf("package %q has no member %q", info.Pkg.Path(), spec.pkgMember) } var searchFunc *types.Func if spec.typeMember == "" { // package member if spec.searchFor == "" { return []types.Object{pkgMember}, nil } // Search within pkgMember, which must be a function. searchFunc, _ = pkgMember.(*types.Func) if searchFunc == nil { return nil, fmt.Errorf("cannot search for %q within %s %q", spec.searchFor, objectKind(pkgMember), pkgMember) } } else { // field/method of type // e.g. (encoding/json.Decoder).Decode // or ::x within it. tName, _ := pkgMember.(*types.TypeName) if tName == nil { return nil, fmt.Errorf("%s.%s is a %s, not a type", info.Pkg.Path(), pkgMember.Name(), objectKind(pkgMember)) } // search within named type. obj, _, _ := types.LookupFieldOrMethod(tName.Type(), true, info.Pkg, spec.typeMember) if obj == nil { return nil, fmt.Errorf("cannot find field or method %q of %s %s.%s", spec.typeMember, typeKind(tName.Type()), info.Pkg.Path(), tName.Name()) } if spec.searchFor == "" { // If it is an embedded field, return the type of the field. if v, ok := obj.(*types.Var); ok && v.Anonymous() { switch t := v.Type().(type) { case *types.Pointer: return []types.Object{t.Elem().(*types.Named).Obj()}, nil case *types.Named: return []types.Object{t.Obj()}, nil } } return []types.Object{obj}, nil } searchFunc, _ = obj.(*types.Func) if searchFunc == nil { return nil, fmt.Errorf("cannot search for local name %q within %s (%s.%s).%s; need a function", spec.searchFor, objectKind(obj), info.Pkg.Path(), tName.Name(), obj.Name()) } if isInterface(tName.Type()) { return nil, fmt.Errorf("cannot search for local name %q within abstract method (%s.%s).%s", spec.searchFor, info.Pkg.Path(), tName.Name(), searchFunc.Name()) } } // -- search within function or method -- decl := funcDecl(info, searchFunc) if decl == nil { return nil, fmt.Errorf("cannot find syntax for %s", searchFunc) // can't happen? } var objects []types.Object for _, obj := range searchDefs(&info.Info, spec.searchFor) { // We use positions, not scopes, to determine whether // the obj is within searchFunc. This is clumsy, but the // alternative, using the types.Scope tree, doesn't // account for non-lexical objects like fields and // interface methods. if decl.Pos() <= obj.Pos() && obj.Pos() < decl.End() && obj != searchFunc { objects = append(objects, obj) } } if objects == nil { return nil, fmt.Errorf("no local definition of %q within %s", spec.searchFor, searchFunc) } return objects, nil }