bind_test.go compares the generated Go files against golden files checked in the repository. The bind package formats some of the generated Go files, so any changes in the go formatter can break the tests. This change makes the test more robust by applying formatting based on the currently used go version. Since a golden file often includes multiple go files generated by the bind, the `gofmt` function splits the golden file using the gobindPreamble marker and then run format.Source for each chunk. In order to ease the golden file splitting, this CL also moves the gobindPreamble to the beginning of each generated file consistently. It turned out bind omits formatting for some go files (generated for reverse binding). That needs to be fixed but it is a much bigger fix. Thus, in this CL, we apply the formatting on the bind's output as well. This CL also updates the gobindPreamble to follow the style guide for generated code. https://golang.org/s/generatedcode Fixes golang/go#34619 Change-Id: Ia2957693154face2848e051ebbb2373e95d79593 Reviewed-on: https://go-review.googlesource.com/c/mobile/+/198322 Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Bryan C. Mills <bcmills@google.com>
594 lines
16 KiB
Go
594 lines
16 KiB
Go
// Copyright 2014 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.
|
|
|
|
package bind
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"go/types"
|
|
"strings"
|
|
)
|
|
|
|
type goGen struct {
|
|
*Generator
|
|
|
|
// imports is the list of imports, in the form
|
|
// "the/package/path"
|
|
//
|
|
// or
|
|
//
|
|
// name "the/package/path"
|
|
//
|
|
// in case of duplicates.
|
|
imports []string
|
|
// The set of taken import names.
|
|
importNames map[string]struct{}
|
|
// importMap is a map from packages to their names. The name of a package is the last
|
|
// segment of its path, with duplicates resolved by appending a underscore and a unique
|
|
// number.
|
|
importMap map[*types.Package]string
|
|
}
|
|
|
|
const (
|
|
goPreamble = gobindPreamble + `// Package main is an autogenerated binder stub for package %[1]s.
|
|
//
|
|
// autogenerated by gobind -lang=go %[2]s
|
|
package main
|
|
|
|
/*
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include "seq.h"
|
|
#include "%[1]s.h"
|
|
|
|
*/
|
|
import "C"
|
|
|
|
`
|
|
)
|
|
|
|
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 *goGen) genWrite(toVar, fromVar string, t types.Type, mode varMode) {
|
|
switch t := t.(type) {
|
|
case *types.Basic:
|
|
switch t.Kind() {
|
|
case types.String:
|
|
g.Printf("%s := encodeString(%s)\n", toVar, fromVar)
|
|
case types.Bool:
|
|
g.Printf("var %s C.%s = 0\n", toVar, g.cgoType(t))
|
|
g.Printf("if %s { %s = 1 }\n", fromVar, toVar)
|
|
default:
|
|
g.Printf("%s := C.%s(%s)\n", toVar, g.cgoType(t), fromVar)
|
|
}
|
|
case *types.Slice:
|
|
switch e := t.Elem().(type) {
|
|
case *types.Basic:
|
|
switch e.Kind() {
|
|
case types.Uint8: // Byte.
|
|
g.Printf("%s := fromSlice(%s, %v)\n", toVar, fromVar, mode == modeRetained)
|
|
default:
|
|
g.errorf("unsupported type: %s", t)
|
|
}
|
|
default:
|
|
g.errorf("unsupported type: %s", t)
|
|
}
|
|
case *types.Pointer:
|
|
// TODO(crawshaw): test *int
|
|
// TODO(crawshaw): test **Generator
|
|
switch t := t.Elem().(type) {
|
|
case *types.Named:
|
|
g.genToRefNum(toVar, fromVar)
|
|
default:
|
|
g.errorf("unsupported type %s", t)
|
|
}
|
|
case *types.Named:
|
|
switch u := t.Underlying().(type) {
|
|
case *types.Interface, *types.Pointer:
|
|
g.genToRefNum(toVar, fromVar)
|
|
default:
|
|
g.errorf("unsupported, direct named type %s: %s", t, u)
|
|
}
|
|
default:
|
|
g.errorf("unsupported type %s", t)
|
|
}
|
|
}
|
|
|
|
// genToRefNum generates Go code for converting a variable to its refnum.
|
|
// Note that the nil-check cannot be lifted into seq.ToRefNum, because a nil
|
|
// struct pointer does not convert to a nil interface.
|
|
func (g *goGen) genToRefNum(toVar, fromVar string) {
|
|
g.Printf("var %s C.int32_t = _seq.NullRefNum\n", toVar)
|
|
g.Printf("if %s != nil {\n", fromVar)
|
|
g.Printf(" %s = C.int32_t(_seq.ToRefNum(%s))\n", toVar, fromVar)
|
|
g.Printf("}\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) paramName(params *types.Tuple, pos int) string {
|
|
return basicParamName(params, pos)
|
|
}
|
|
|
|
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 (g *goGen) genStruct(obj *types.TypeName, T *types.Struct) {
|
|
fields := exportedFields(T)
|
|
methods := exportedMethodSet(types.NewPointer(obj.Type()))
|
|
|
|
for _, f := range fields {
|
|
if t := f.Type(); !g.isSupported(t) {
|
|
g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", obj.Name(), f.Name(), t)
|
|
continue
|
|
}
|
|
g.Printf("//export proxy%s_%s_%s_Set\n", g.pkgPrefix, obj.Name(), f.Name())
|
|
g.Printf("func proxy%s_%s_%s_Set(refnum C.int32_t, v C.%s) {\n", g.pkgPrefix, obj.Name(), f.Name(), g.cgoType(f.Type()))
|
|
g.Indent()
|
|
g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
|
|
g.genRead("_v", "v", f.Type(), modeRetained)
|
|
g.Printf("ref.Get().(*%s%s).%s = _v\n", g.pkgName(g.Pkg), obj.Name(), f.Name())
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
|
|
g.Printf("//export proxy%s_%s_%s_Get\n", g.pkgPrefix, obj.Name(), f.Name())
|
|
g.Printf("func proxy%s_%s_%s_Get(refnum C.int32_t) C.%s {\n", g.pkgPrefix, obj.Name(), f.Name(), g.cgoType(f.Type()))
|
|
g.Indent()
|
|
g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
|
|
g.Printf("v := ref.Get().(*%s%s).%s\n", g.pkgName(g.Pkg), obj.Name(), f.Name())
|
|
g.genWrite("_v", "v", f.Type(), modeRetained)
|
|
g.Printf("return _v\n")
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
}
|
|
|
|
for _, m := range methods {
|
|
if !g.isSigSupported(m.Type()) {
|
|
g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
|
|
continue
|
|
}
|
|
g.genFuncSignature(m, obj.Name())
|
|
g.Indent()
|
|
g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
|
|
g.Printf("v := ref.Get().(*%s%s)\n", g.pkgName(g.Pkg), obj.Name())
|
|
g.genFuncBody(m, "v.")
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
}
|
|
// Export constructor for ObjC and Java default no-arg constructors
|
|
g.Printf("//export new_%s_%s\n", g.Pkg.Name(), obj.Name())
|
|
g.Printf("func new_%s_%s() C.int32_t {\n", g.Pkg.Name(), obj.Name())
|
|
g.Indent()
|
|
g.Printf("return C.int32_t(_seq.ToRefNum(new(%s%s)))\n", g.pkgName(g.Pkg), obj.Name())
|
|
g.Outdent()
|
|
g.Printf("}\n")
|
|
}
|
|
|
|
func (g *goGen) genVar(o *types.Var) {
|
|
if t := o.Type(); !g.isSupported(t) {
|
|
g.Printf("// skipped variable %s with unsupported type %s\n\n", o.Name(), t)
|
|
return
|
|
}
|
|
// TODO(hyangah): non-struct pointer types (*int), struct type.
|
|
|
|
v := fmt.Sprintf("%s%s", g.pkgName(g.Pkg), o.Name())
|
|
|
|
// var I int
|
|
//
|
|
// func var_setI(v int)
|
|
g.Printf("//export var_set%s_%s\n", g.pkgPrefix, o.Name())
|
|
g.Printf("func var_set%s_%s(v C.%s) {\n", g.pkgPrefix, o.Name(), g.cgoType(o.Type()))
|
|
g.Indent()
|
|
g.genRead("_v", "v", o.Type(), modeRetained)
|
|
g.Printf("%s = _v\n", v)
|
|
g.Outdent()
|
|
g.Printf("}\n")
|
|
|
|
// func var_getI() int
|
|
g.Printf("//export var_get%s_%s\n", g.pkgPrefix, o.Name())
|
|
g.Printf("func var_get%s_%s() C.%s {\n", g.pkgPrefix, o.Name(), g.cgoType(o.Type()))
|
|
g.Indent()
|
|
g.Printf("v := %s\n", v)
|
|
g.genWrite("_v", "v", o.Type(), modeRetained)
|
|
g.Printf("return _v\n")
|
|
g.Outdent()
|
|
g.Printf("}\n")
|
|
}
|
|
|
|
func (g *goGen) genInterface(obj *types.TypeName) {
|
|
iface := obj.Type().(*types.Named).Underlying().(*types.Interface)
|
|
|
|
summary := makeIfaceSummary(iface)
|
|
|
|
// Define the entry points.
|
|
for _, m := range summary.callable {
|
|
if !g.isSigSupported(m.Type()) {
|
|
g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
|
|
continue
|
|
}
|
|
g.genFuncSignature(m, obj.Name())
|
|
g.Indent()
|
|
g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
|
|
g.Printf("v := ref.Get().(%s%s)\n", g.pkgName(g.Pkg), obj.Name())
|
|
g.genFuncBody(m, "v.")
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
}
|
|
|
|
// Define a proxy interface.
|
|
if !summary.implementable {
|
|
// The interface defines an unexported method or a method that
|
|
// uses an unexported type. We cannot generate a proxy object
|
|
// for such a type.
|
|
return
|
|
}
|
|
g.Printf("type proxy%s_%s _seq.Ref\n\n", g.pkgPrefix, obj.Name())
|
|
|
|
g.Printf("func (p *proxy%s_%s) Bind_proxy_refnum__() int32 {\n", g.pkgPrefix, obj.Name())
|
|
g.Indent()
|
|
g.Printf("return (*_seq.Ref)(p).Bind_IncNum()\n")
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
|
|
for _, m := range summary.callable {
|
|
if !g.isSigSupported(m.Type()) {
|
|
g.Printf("// skipped method %s.%s with unsupported parameter or result types\n", obj.Name(), m.Name())
|
|
continue
|
|
}
|
|
sig := m.Type().(*types.Signature)
|
|
params := sig.Params()
|
|
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 value, and optionally an error: %s.%s", obj.Name(), m.Name())
|
|
continue
|
|
}
|
|
|
|
g.Printf("func (p *proxy%s_%s) %s(", g.pkgPrefix, obj.Name(), m.Name())
|
|
for i := 0; i < params.Len(); i++ {
|
|
if i > 0 {
|
|
g.Printf(", ")
|
|
}
|
|
g.Printf("param_%s %s", g.paramName(params, i), g.typeString(params.At(i).Type()))
|
|
}
|
|
g.Printf(") ")
|
|
|
|
if res.Len() == 1 {
|
|
g.Printf(g.typeString(res.At(0).Type()))
|
|
} else if res.Len() == 2 {
|
|
g.Printf("(%s, error)", g.typeString(res.At(0).Type()))
|
|
}
|
|
g.Printf(" {\n")
|
|
g.Indent()
|
|
|
|
for i := 0; i < params.Len(); i++ {
|
|
pn := "param_" + g.paramName(params, i)
|
|
g.genWrite("_"+pn, pn, params.At(i).Type(), modeTransient)
|
|
}
|
|
|
|
if res.Len() > 0 {
|
|
g.Printf("res := ")
|
|
}
|
|
g.Printf("C.cproxy%s_%s_%s(C.int32_t(p.Bind_proxy_refnum__())", g.pkgPrefix, obj.Name(), m.Name())
|
|
for i := 0; i < params.Len(); i++ {
|
|
g.Printf(", _param_%s", g.paramName(params, i))
|
|
}
|
|
g.Printf(")\n")
|
|
var retName string
|
|
if res.Len() > 0 {
|
|
if res.Len() == 1 {
|
|
T := res.At(0).Type()
|
|
g.genRead("_res", "res", T, modeRetained)
|
|
retName = "_res"
|
|
} else {
|
|
var rvs []string
|
|
for i := 0; i < res.Len(); i++ {
|
|
rv := fmt.Sprintf("res_%d", i)
|
|
g.genRead(rv, fmt.Sprintf("res.r%d", i), res.At(i).Type(), modeRetained)
|
|
rvs = append(rvs, rv)
|
|
}
|
|
retName = strings.Join(rvs, ", ")
|
|
}
|
|
g.Printf("return %s\n", retName)
|
|
}
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
}
|
|
}
|
|
|
|
func (g *goGen) genRead(toVar, fromVar string, typ types.Type, mode varMode) {
|
|
switch t := typ.(type) {
|
|
case *types.Basic:
|
|
switch t.Kind() {
|
|
case types.String:
|
|
g.Printf("%s := decodeString(%s)\n", toVar, fromVar)
|
|
case types.Bool:
|
|
g.Printf("%s := %s != 0\n", toVar, fromVar)
|
|
default:
|
|
g.Printf("%s := %s(%s)\n", toVar, t.Underlying().String(), fromVar)
|
|
}
|
|
case *types.Slice:
|
|
switch e := t.Elem().(type) {
|
|
case *types.Basic:
|
|
switch e.Kind() {
|
|
case types.Uint8: // Byte.
|
|
g.Printf("%s := toSlice(%s, %v)\n", toVar, fromVar, mode == modeRetained)
|
|
default:
|
|
g.errorf("unsupported type: %s", t)
|
|
}
|
|
default:
|
|
g.errorf("unsupported type: %s", t)
|
|
}
|
|
case *types.Pointer:
|
|
switch u := t.Elem().(type) {
|
|
case *types.Named:
|
|
o := u.Obj()
|
|
oPkg := o.Pkg()
|
|
if !g.validPkg(oPkg) {
|
|
g.errorf("type %s is defined in %s, which is not bound", u, oPkg)
|
|
return
|
|
}
|
|
g.Printf("// Must be a Go object\n")
|
|
g.Printf("var %s *%s%s\n", toVar, g.pkgName(oPkg), o.Name())
|
|
g.Printf("if %s_ref := _seq.FromRefNum(int32(%s)); %s_ref != nil {\n", toVar, fromVar, toVar)
|
|
g.Printf(" %s = %s_ref.Get().(*%s%s)\n", toVar, toVar, g.pkgName(oPkg), o.Name())
|
|
g.Printf("}\n")
|
|
default:
|
|
g.errorf("unsupported pointer type %s", t)
|
|
}
|
|
case *types.Named:
|
|
switch t.Underlying().(type) {
|
|
case *types.Interface, *types.Pointer:
|
|
hasProxy := true
|
|
if iface, ok := t.Underlying().(*types.Interface); ok {
|
|
hasProxy = makeIfaceSummary(iface).implementable
|
|
}
|
|
pkgFirst := typePkgFirstElem(t)
|
|
isWrapper := pkgFirst == "Java" || pkgFirst == "ObjC"
|
|
o := t.Obj()
|
|
oPkg := o.Pkg()
|
|
if !isErrorType(t) && !g.validPkg(oPkg) && !isWrapper {
|
|
g.errorf("type %s is defined in %s, which is not bound", t, oPkg)
|
|
return
|
|
}
|
|
g.Printf("var %s %s\n", toVar, g.typeString(t))
|
|
g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", toVar, fromVar)
|
|
g.Printf("if %s_ref != nil {\n", toVar)
|
|
g.Printf(" if %s < 0 { // go object \n", fromVar)
|
|
g.Printf(" %s = %s_ref.Get().(%s%s)\n", toVar, toVar, g.pkgName(oPkg), o.Name())
|
|
if hasProxy {
|
|
g.Printf(" } else { // foreign object \n")
|
|
if isWrapper {
|
|
var clsName string
|
|
switch pkgFirst {
|
|
case "Java":
|
|
clsName = flattenName(classNameFor(t))
|
|
case "ObjC":
|
|
clsName = t.Obj().Name()
|
|
}
|
|
g.Printf(" %s = (*proxy_class_%s)(%s_ref)\n", toVar, clsName, toVar)
|
|
} else {
|
|
g.Printf(" %s = (*proxy%s_%s)(%s_ref)\n", toVar, pkgPrefix(oPkg), o.Name(), toVar)
|
|
}
|
|
}
|
|
g.Printf(" }\n")
|
|
g.Printf("}\n")
|
|
default:
|
|
g.errorf("unsupported named type %s", t)
|
|
}
|
|
default:
|
|
g.errorf("unsupported type: %s", typ)
|
|
}
|
|
}
|
|
|
|
func (g *goGen) typeString(typ types.Type) string {
|
|
pkg := g.Pkg
|
|
|
|
switch t := typ.(type) {
|
|
case *types.Named:
|
|
obj := t.Obj()
|
|
if obj.Pkg() == nil { // e.g. error type is *types.Named.
|
|
return types.TypeString(typ, types.RelativeTo(pkg))
|
|
}
|
|
oPkg := obj.Pkg()
|
|
if !g.validPkg(oPkg) && !isWrapperType(t) {
|
|
g.errorf("type %s is defined in %s, which is not bound", t, oPkg)
|
|
return "TODO"
|
|
}
|
|
|
|
switch t.Underlying().(type) {
|
|
case *types.Interface, *types.Struct:
|
|
return fmt.Sprintf("%s%s", g.pkgName(oPkg), types.TypeString(typ, types.RelativeTo(oPkg)))
|
|
default:
|
|
g.errorf("unsupported named type %s / %T", t, t)
|
|
}
|
|
case *types.Pointer:
|
|
switch t := t.Elem().(type) {
|
|
case *types.Named:
|
|
return fmt.Sprintf("*%s", g.typeString(t))
|
|
default:
|
|
g.errorf("not yet supported, pointer type %s / %T", t, t)
|
|
}
|
|
default:
|
|
return types.TypeString(typ, types.RelativeTo(pkg))
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// genPreamble generates the preamble. It is generated after everything
|
|
// else, where we know which bound packages to import.
|
|
func (g *goGen) genPreamble() {
|
|
pkgName := ""
|
|
pkgPath := ""
|
|
if g.Pkg != nil {
|
|
pkgName = g.Pkg.Name()
|
|
pkgPath = g.Pkg.Path()
|
|
} else {
|
|
pkgName = "universe"
|
|
}
|
|
g.Printf(goPreamble, pkgName, pkgPath)
|
|
g.Printf("import (\n")
|
|
g.Indent()
|
|
g.Printf("_seq \"golang.org/x/mobile/bind/seq\"\n")
|
|
for _, imp := range g.imports {
|
|
g.Printf("%s\n", imp)
|
|
}
|
|
g.Outdent()
|
|
g.Printf(")\n\n")
|
|
}
|
|
|
|
func (g *goGen) gen() error {
|
|
g.importNames = make(map[string]struct{})
|
|
g.importMap = make(map[*types.Package]string)
|
|
|
|
// Switch to a temporary buffer so the preamble can be
|
|
// written last.
|
|
oldBuf := g.Printer.Buf
|
|
newBuf := new(bytes.Buffer)
|
|
g.Printer.Buf = newBuf
|
|
g.Printf("// suppress the error if seq ends up unused\n")
|
|
g.Printf("var _ = _seq.FromRefNum\n")
|
|
|
|
for _, s := range g.structs {
|
|
g.genStruct(s.obj, s.t)
|
|
}
|
|
for _, intf := range g.interfaces {
|
|
g.genInterface(intf.obj)
|
|
}
|
|
for _, v := range g.vars {
|
|
g.genVar(v)
|
|
}
|
|
for _, f := range g.funcs {
|
|
g.genFunc(f)
|
|
}
|
|
// Switch to the original buffer, write the preamble
|
|
// and append the rest of the file.
|
|
g.Printer.Buf = oldBuf
|
|
g.genPreamble()
|
|
g.Printer.Buf.Write(newBuf.Bytes())
|
|
if len(g.err) > 0 {
|
|
return g.err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// pkgName retuns the package name and adds the package to the list of
|
|
// imports.
|
|
func (g *goGen) pkgName(pkg *types.Package) string {
|
|
// The error type has no package
|
|
if pkg == nil {
|
|
return ""
|
|
}
|
|
if name, exists := g.importMap[pkg]; exists {
|
|
return name + "."
|
|
}
|
|
i := 0
|
|
pname := pkg.Name()
|
|
name := pkg.Name()
|
|
for {
|
|
if _, exists := g.importNames[name]; !exists {
|
|
g.importNames[name] = struct{}{}
|
|
g.importMap[pkg] = name
|
|
var imp string
|
|
if pname != name {
|
|
imp = fmt.Sprintf("%s %q", name, pkg.Path())
|
|
} else {
|
|
imp = fmt.Sprintf("%q", pkg.Path())
|
|
}
|
|
g.imports = append(g.imports, imp)
|
|
break
|
|
}
|
|
i++
|
|
name = fmt.Sprintf("%s_%d", pname, i)
|
|
}
|
|
g.importMap[pkg] = name
|
|
return name + "."
|
|
}
|