github.com/acrespo/mobile@v0.0.0-20190107162257-dc0771356504/bind/gengo.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package bind
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"go/types"
    11  	"strings"
    12  )
    13  
    14  type goGen struct {
    15  	*Generator
    16  
    17  	// imports is the list of imports, in the form
    18  	// "the/package/path"
    19  	//
    20  	// or
    21  	//
    22  	// name "the/package/path"
    23  	//
    24  	// in case of duplicates.
    25  	imports []string
    26  	// The set of taken import names.
    27  	importNames map[string]struct{}
    28  	// importMap is a map from packages to their names. The name of a package is the last
    29  	// segment of its path, with duplicates resolved by appending a underscore and a unique
    30  	// number.
    31  	importMap map[*types.Package]string
    32  }
    33  
    34  const (
    35  	goPreamble = `// Package main is an autogenerated binder stub for package %[1]s.
    36  //   gobind -lang=go %[2]s
    37  //
    38  // File is generated by gobind. Do not edit.
    39  package main
    40  
    41  /*
    42  #include <stdlib.h>
    43  #include <stdint.h>
    44  #include "seq.h"
    45  #include "%[1]s.h"
    46  
    47  */
    48  import "C"
    49  
    50  `
    51  )
    52  
    53  func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) {
    54  	sig := o.Type().(*types.Signature)
    55  	params := sig.Params()
    56  	for i := 0; i < params.Len(); i++ {
    57  		p := params.At(i)
    58  		pn := "param_" + g.paramName(params, i)
    59  		g.genRead("_"+pn, pn, p.Type(), modeTransient)
    60  	}
    61  
    62  	res := sig.Results()
    63  	if res.Len() > 2 || res.Len() == 2 && !isErrorType(res.At(1).Type()) {
    64  		g.errorf("functions and methods must return either zero or one values, and optionally an error")
    65  		return
    66  	}
    67  	if res.Len() > 0 {
    68  		for i := 0; i < res.Len(); i++ {
    69  			if i > 0 {
    70  				g.Printf(", ")
    71  			}
    72  			g.Printf("res_%d", i)
    73  		}
    74  		g.Printf(" := ")
    75  	}
    76  
    77  	g.Printf("%s%s(", selectorLHS, o.Name())
    78  	for i := 0; i < params.Len(); i++ {
    79  		if i > 0 {
    80  			g.Printf(", ")
    81  		}
    82  		g.Printf("_param_%s", g.paramName(params, i))
    83  	}
    84  	g.Printf(")\n")
    85  
    86  	for i := 0; i < res.Len(); i++ {
    87  		pn := fmt.Sprintf("res_%d", i)
    88  		g.genWrite("_"+pn, pn, res.At(i).Type(), modeRetained)
    89  	}
    90  	if res.Len() > 0 {
    91  		g.Printf("return ")
    92  		for i := 0; i < res.Len(); i++ {
    93  			if i > 0 {
    94  				g.Printf(", ")
    95  			}
    96  			g.Printf("_res_%d", i)
    97  		}
    98  		g.Printf("\n")
    99  	}
   100  }
   101  
   102  func (g *goGen) genWrite(toVar, fromVar string, t types.Type, mode varMode) {
   103  	switch t := t.(type) {
   104  	case *types.Basic:
   105  		switch t.Kind() {
   106  		case types.String:
   107  			g.Printf("%s := encodeString(%s)\n", toVar, fromVar)
   108  		case types.Bool:
   109  			g.Printf("var %s C.%s = 0\n", toVar, g.cgoType(t))
   110  			g.Printf("if %s { %s = 1 }\n", fromVar, toVar)
   111  		default:
   112  			g.Printf("%s := C.%s(%s)\n", toVar, g.cgoType(t), fromVar)
   113  		}
   114  	case *types.Slice:
   115  		switch e := t.Elem().(type) {
   116  		case *types.Basic:
   117  			switch e.Kind() {
   118  			case types.Uint8: // Byte.
   119  				g.Printf("%s := fromSlice(%s, %v)\n", toVar, fromVar, mode == modeRetained)
   120  			default:
   121  				g.errorf("unsupported type: %s", t)
   122  			}
   123  		default:
   124  			g.errorf("unsupported type: %s", t)
   125  		}
   126  	case *types.Pointer:
   127  		// TODO(crawshaw): test *int
   128  		// TODO(crawshaw): test **Generator
   129  		switch t := t.Elem().(type) {
   130  		case *types.Named:
   131  			g.genToRefNum(toVar, fromVar)
   132  		default:
   133  			g.errorf("unsupported type %s", t)
   134  		}
   135  	case *types.Named:
   136  		switch u := t.Underlying().(type) {
   137  		case *types.Interface, *types.Pointer:
   138  			g.genToRefNum(toVar, fromVar)
   139  		default:
   140  			g.errorf("unsupported, direct named type %s: %s", t, u)
   141  		}
   142  	default:
   143  		g.errorf("unsupported type %s", t)
   144  	}
   145  }
   146  
   147  // genToRefNum generates Go code for converting a variable to its refnum.
   148  // Note that the nil-check cannot be lifted into seq.ToRefNum, because a nil
   149  // struct pointer does not convert to a nil interface.
   150  func (g *goGen) genToRefNum(toVar, fromVar string) {
   151  	g.Printf("var %s C.int32_t = _seq.NullRefNum\n", toVar)
   152  	g.Printf("if %s != nil {\n", fromVar)
   153  	g.Printf("	%s = C.int32_t(_seq.ToRefNum(%s))\n", toVar, fromVar)
   154  	g.Printf("}\n")
   155  }
   156  
   157  func (g *goGen) genFuncSignature(o *types.Func, objName string) {
   158  	g.Printf("//export proxy%s_%s_%s\n", g.pkgPrefix, objName, o.Name())
   159  	g.Printf("func proxy%s_%s_%s(", g.pkgPrefix, objName, o.Name())
   160  	if objName != "" {
   161  		g.Printf("refnum C.int32_t")
   162  	}
   163  	sig := o.Type().(*types.Signature)
   164  	params := sig.Params()
   165  	for i := 0; i < params.Len(); i++ {
   166  		if objName != "" || i > 0 {
   167  			g.Printf(", ")
   168  		}
   169  		p := params.At(i)
   170  		g.Printf("param_%s C.%s", g.paramName(params, i), g.cgoType(p.Type()))
   171  	}
   172  	g.Printf(") ")
   173  	res := sig.Results()
   174  	if res.Len() > 0 {
   175  		g.Printf("(")
   176  		for i := 0; i < res.Len(); i++ {
   177  			if i > 0 {
   178  				g.Printf(", ")
   179  			}
   180  			g.Printf("C.%s", g.cgoType(res.At(i).Type()))
   181  		}
   182  		g.Printf(") ")
   183  	}
   184  	g.Printf("{\n")
   185  }
   186  
   187  func (g *goGen) paramName(params *types.Tuple, pos int) string {
   188  	return basicParamName(params, pos)
   189  }
   190  
   191  func (g *goGen) genFunc(o *types.Func) {
   192  	if !g.isSigSupported(o.Type()) {
   193  		g.Printf("// skipped function %s with unsupported parameter or result types\n", o.Name())
   194  		return
   195  	}
   196  	g.genFuncSignature(o, "")
   197  	g.Indent()
   198  	g.genFuncBody(o, g.pkgName(g.Pkg))
   199  	g.Outdent()
   200  	g.Printf("}\n\n")
   201  }
   202  
   203  func (g *goGen) genStruct(obj *types.TypeName, T *types.Struct) {
   204  	fields := exportedFields(T)
   205  	methods := exportedMethodSet(types.NewPointer(obj.Type()))
   206  
   207  	for _, f := range fields {
   208  		if t := f.Type(); !g.isSupported(t) {
   209  			g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", obj.Name(), f.Name(), t)
   210  			continue
   211  		}
   212  		g.Printf("//export proxy%s_%s_%s_Set\n", g.pkgPrefix, obj.Name(), f.Name())
   213  		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()))
   214  		g.Indent()
   215  		g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
   216  		g.genRead("_v", "v", f.Type(), modeRetained)
   217  		g.Printf("ref.Get().(*%s%s).%s = _v\n", g.pkgName(g.Pkg), obj.Name(), f.Name())
   218  		g.Outdent()
   219  		g.Printf("}\n\n")
   220  
   221  		g.Printf("//export proxy%s_%s_%s_Get\n", g.pkgPrefix, obj.Name(), f.Name())
   222  		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()))
   223  		g.Indent()
   224  		g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
   225  		g.Printf("v := ref.Get().(*%s%s).%s\n", g.pkgName(g.Pkg), obj.Name(), f.Name())
   226  		g.genWrite("_v", "v", f.Type(), modeRetained)
   227  		g.Printf("return _v\n")
   228  		g.Outdent()
   229  		g.Printf("}\n\n")
   230  	}
   231  
   232  	for _, m := range methods {
   233  		if !g.isSigSupported(m.Type()) {
   234  			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
   235  			continue
   236  		}
   237  		g.genFuncSignature(m, obj.Name())
   238  		g.Indent()
   239  		g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
   240  		g.Printf("v := ref.Get().(*%s%s)\n", g.pkgName(g.Pkg), obj.Name())
   241  		g.genFuncBody(m, "v.")
   242  		g.Outdent()
   243  		g.Printf("}\n\n")
   244  	}
   245  	// Export constructor for ObjC and Java default no-arg constructors
   246  	g.Printf("//export new_%s_%s\n", g.Pkg.Name(), obj.Name())
   247  	g.Printf("func new_%s_%s() C.int32_t {\n", g.Pkg.Name(), obj.Name())
   248  	g.Indent()
   249  	g.Printf("return C.int32_t(_seq.ToRefNum(new(%s%s)))\n", g.pkgName(g.Pkg), obj.Name())
   250  	g.Outdent()
   251  	g.Printf("}\n")
   252  }
   253  
   254  func (g *goGen) genVar(o *types.Var) {
   255  	if t := o.Type(); !g.isSupported(t) {
   256  		g.Printf("// skipped variable %s with unsupported type %s\n\n", o.Name(), t)
   257  		return
   258  	}
   259  	// TODO(hyangah): non-struct pointer types (*int), struct type.
   260  
   261  	v := fmt.Sprintf("%s%s", g.pkgName(g.Pkg), o.Name())
   262  
   263  	// var I int
   264  	//
   265  	// func var_setI(v int)
   266  	g.Printf("//export var_set%s_%s\n", g.pkgPrefix, o.Name())
   267  	g.Printf("func var_set%s_%s(v C.%s) {\n", g.pkgPrefix, o.Name(), g.cgoType(o.Type()))
   268  	g.Indent()
   269  	g.genRead("_v", "v", o.Type(), modeRetained)
   270  	g.Printf("%s = _v\n", v)
   271  	g.Outdent()
   272  	g.Printf("}\n")
   273  
   274  	// func var_getI() int
   275  	g.Printf("//export var_get%s_%s\n", g.pkgPrefix, o.Name())
   276  	g.Printf("func var_get%s_%s() C.%s {\n", g.pkgPrefix, o.Name(), g.cgoType(o.Type()))
   277  	g.Indent()
   278  	g.Printf("v := %s\n", v)
   279  	g.genWrite("_v", "v", o.Type(), modeRetained)
   280  	g.Printf("return _v\n")
   281  	g.Outdent()
   282  	g.Printf("}\n")
   283  }
   284  
   285  func (g *goGen) genInterface(obj *types.TypeName) {
   286  	iface := obj.Type().(*types.Named).Underlying().(*types.Interface)
   287  
   288  	summary := makeIfaceSummary(iface)
   289  
   290  	// Define the entry points.
   291  	for _, m := range summary.callable {
   292  		if !g.isSigSupported(m.Type()) {
   293  			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
   294  			continue
   295  		}
   296  		g.genFuncSignature(m, obj.Name())
   297  		g.Indent()
   298  		g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
   299  		g.Printf("v := ref.Get().(%s%s)\n", g.pkgName(g.Pkg), obj.Name())
   300  		g.genFuncBody(m, "v.")
   301  		g.Outdent()
   302  		g.Printf("}\n\n")
   303  	}
   304  
   305  	// Define a proxy interface.
   306  	if !summary.implementable {
   307  		// The interface defines an unexported method or a method that
   308  		// uses an unexported type. We cannot generate a proxy object
   309  		// for such a type.
   310  		return
   311  	}
   312  	g.Printf("type proxy%s_%s _seq.Ref\n\n", g.pkgPrefix, obj.Name())
   313  
   314  	g.Printf("func (p *proxy%s_%s) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }\n\n", g.pkgPrefix, obj.Name())
   315  
   316  	for _, m := range summary.callable {
   317  		if !g.isSigSupported(m.Type()) {
   318  			g.Printf("// skipped method %s.%s with unsupported parameter or result types\n", obj.Name(), m.Name())
   319  			continue
   320  		}
   321  		sig := m.Type().(*types.Signature)
   322  		params := sig.Params()
   323  		res := sig.Results()
   324  
   325  		if res.Len() > 2 ||
   326  			(res.Len() == 2 && !isErrorType(res.At(1).Type())) {
   327  			g.errorf("functions and methods must return either zero or one value, and optionally an error: %s.%s", obj.Name(), m.Name())
   328  			continue
   329  		}
   330  
   331  		g.Printf("func (p *proxy%s_%s) %s(", g.pkgPrefix, obj.Name(), m.Name())
   332  		for i := 0; i < params.Len(); i++ {
   333  			if i > 0 {
   334  				g.Printf(", ")
   335  			}
   336  			g.Printf("param_%s %s", g.paramName(params, i), g.typeString(params.At(i).Type()))
   337  		}
   338  		g.Printf(") ")
   339  
   340  		if res.Len() == 1 {
   341  			g.Printf(g.typeString(res.At(0).Type()))
   342  		} else if res.Len() == 2 {
   343  			g.Printf("(%s, error)", g.typeString(res.At(0).Type()))
   344  		}
   345  		g.Printf(" {\n")
   346  		g.Indent()
   347  
   348  		for i := 0; i < params.Len(); i++ {
   349  			pn := "param_" + g.paramName(params, i)
   350  			g.genWrite("_"+pn, pn, params.At(i).Type(), modeTransient)
   351  		}
   352  
   353  		if res.Len() > 0 {
   354  			g.Printf("res := ")
   355  		}
   356  		g.Printf("C.cproxy%s_%s_%s(C.int32_t(p.Bind_proxy_refnum__())", g.pkgPrefix, obj.Name(), m.Name())
   357  		for i := 0; i < params.Len(); i++ {
   358  			g.Printf(", _param_%s", g.paramName(params, i))
   359  		}
   360  		g.Printf(")\n")
   361  		var retName string
   362  		if res.Len() > 0 {
   363  			if res.Len() == 1 {
   364  				T := res.At(0).Type()
   365  				g.genRead("_res", "res", T, modeRetained)
   366  				retName = "_res"
   367  			} else {
   368  				var rvs []string
   369  				for i := 0; i < res.Len(); i++ {
   370  					rv := fmt.Sprintf("res_%d", i)
   371  					g.genRead(rv, fmt.Sprintf("res.r%d", i), res.At(i).Type(), modeRetained)
   372  					rvs = append(rvs, rv)
   373  				}
   374  				retName = strings.Join(rvs, ", ")
   375  			}
   376  			g.Printf("return %s\n", retName)
   377  		}
   378  		g.Outdent()
   379  		g.Printf("}\n\n")
   380  	}
   381  }
   382  
   383  func (g *goGen) genRead(toVar, fromVar string, typ types.Type, mode varMode) {
   384  	switch t := typ.(type) {
   385  	case *types.Basic:
   386  		switch t.Kind() {
   387  		case types.String:
   388  			g.Printf("%s := decodeString(%s)\n", toVar, fromVar)
   389  		case types.Bool:
   390  			g.Printf("%s := %s != 0\n", toVar, fromVar)
   391  		default:
   392  			g.Printf("%s := %s(%s)\n", toVar, t.Underlying().String(), fromVar)
   393  		}
   394  	case *types.Slice:
   395  		switch e := t.Elem().(type) {
   396  		case *types.Basic:
   397  			switch e.Kind() {
   398  			case types.Uint8: // Byte.
   399  				g.Printf("%s := toSlice(%s, %v)\n", toVar, fromVar, mode == modeRetained)
   400  			default:
   401  				g.errorf("unsupported type: %s", t)
   402  			}
   403  		default:
   404  			g.errorf("unsupported type: %s", t)
   405  		}
   406  	case *types.Pointer:
   407  		switch u := t.Elem().(type) {
   408  		case *types.Named:
   409  			o := u.Obj()
   410  			oPkg := o.Pkg()
   411  			if !g.validPkg(oPkg) {
   412  				g.errorf("type %s is defined in %s, which is not bound", u, oPkg)
   413  				return
   414  			}
   415  			g.Printf("// Must be a Go object\n")
   416  			g.Printf("var %s *%s%s\n", toVar, g.pkgName(oPkg), o.Name())
   417  			g.Printf("if %s_ref := _seq.FromRefNum(int32(%s)); %s_ref != nil {\n", toVar, fromVar, toVar)
   418  			g.Printf("  %s = %s_ref.Get().(*%s%s)\n", toVar, toVar, g.pkgName(oPkg), o.Name())
   419  			g.Printf("}\n")
   420  		default:
   421  			g.errorf("unsupported pointer type %s", t)
   422  		}
   423  	case *types.Named:
   424  		switch t.Underlying().(type) {
   425  		case *types.Interface, *types.Pointer:
   426  			hasProxy := true
   427  			if iface, ok := t.Underlying().(*types.Interface); ok {
   428  				hasProxy = makeIfaceSummary(iface).implementable
   429  			}
   430  			pkgFirst := typePkgFirstElem(t)
   431  			isWrapper := pkgFirst == "Java" || pkgFirst == "ObjC"
   432  			o := t.Obj()
   433  			oPkg := o.Pkg()
   434  			if !isErrorType(t) && !g.validPkg(oPkg) && !isWrapper {
   435  				g.errorf("type %s is defined in %s, which is not bound", t, oPkg)
   436  				return
   437  			}
   438  			g.Printf("var %s %s\n", toVar, g.typeString(t))
   439  			g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", toVar, fromVar)
   440  			g.Printf("if %s_ref != nil {\n", toVar)
   441  			g.Printf("	if %s < 0 { // go object \n", fromVar)
   442  			g.Printf("  	 %s = %s_ref.Get().(%s%s)\n", toVar, toVar, g.pkgName(oPkg), o.Name())
   443  			if hasProxy {
   444  				g.Printf("	} else { // foreign object \n")
   445  				if isWrapper {
   446  					var clsName string
   447  					switch pkgFirst {
   448  					case "Java":
   449  						clsName = flattenName(classNameFor(t))
   450  					case "ObjC":
   451  						clsName = t.Obj().Name()
   452  					}
   453  					g.Printf("	   %s = (*proxy_class_%s)(%s_ref)\n", toVar, clsName, toVar)
   454  				} else {
   455  					g.Printf("	   %s = (*proxy%s_%s)(%s_ref)\n", toVar, pkgPrefix(oPkg), o.Name(), toVar)
   456  				}
   457  			}
   458  			g.Printf("	}\n")
   459  			g.Printf("}\n")
   460  		default:
   461  			g.errorf("unsupported named type %s", t)
   462  		}
   463  	default:
   464  		g.errorf("unsupported type: %s", typ)
   465  	}
   466  }
   467  
   468  func (g *goGen) typeString(typ types.Type) string {
   469  	pkg := g.Pkg
   470  
   471  	switch t := typ.(type) {
   472  	case *types.Named:
   473  		obj := t.Obj()
   474  		if obj.Pkg() == nil { // e.g. error type is *types.Named.
   475  			return types.TypeString(typ, types.RelativeTo(pkg))
   476  		}
   477  		oPkg := obj.Pkg()
   478  		if !g.validPkg(oPkg) && !isWrapperType(t) {
   479  			g.errorf("type %s is defined in %s, which is not bound", t, oPkg)
   480  			return "TODO"
   481  		}
   482  
   483  		switch t.Underlying().(type) {
   484  		case *types.Interface, *types.Struct:
   485  			return fmt.Sprintf("%s%s", g.pkgName(oPkg), types.TypeString(typ, types.RelativeTo(oPkg)))
   486  		default:
   487  			g.errorf("unsupported named type %s / %T", t, t)
   488  		}
   489  	case *types.Pointer:
   490  		switch t := t.Elem().(type) {
   491  		case *types.Named:
   492  			return fmt.Sprintf("*%s", g.typeString(t))
   493  		default:
   494  			g.errorf("not yet supported, pointer type %s / %T", t, t)
   495  		}
   496  	default:
   497  		return types.TypeString(typ, types.RelativeTo(pkg))
   498  	}
   499  	return ""
   500  }
   501  
   502  // genPreamble generates the preamble. It is generated after everything
   503  // else, where we know which bound packages to import.
   504  func (g *goGen) genPreamble() {
   505  	pkgName := ""
   506  	pkgPath := ""
   507  	if g.Pkg != nil {
   508  		pkgName = g.Pkg.Name()
   509  		pkgPath = g.Pkg.Path()
   510  	} else {
   511  		pkgName = "universe"
   512  	}
   513  	g.Printf(goPreamble, pkgName, pkgPath)
   514  	g.Printf("import (\n")
   515  	g.Indent()
   516  	g.Printf("_seq \"golang.org/x/mobile/bind/seq\"\n")
   517  	for _, imp := range g.imports {
   518  		g.Printf("%s\n", imp)
   519  	}
   520  	g.Outdent()
   521  	g.Printf(")\n\n")
   522  }
   523  
   524  func (g *goGen) gen() error {
   525  	g.importNames = make(map[string]struct{})
   526  	g.importMap = make(map[*types.Package]string)
   527  
   528  	// Switch to a temporary buffer so the preamble can be
   529  	// written last.
   530  	oldBuf := g.Printer.Buf
   531  	newBuf := new(bytes.Buffer)
   532  	g.Printer.Buf = newBuf
   533  	g.Printf("// suppress the error if seq ends up unused\n")
   534  	g.Printf("var _ = _seq.FromRefNum\n")
   535  
   536  	for _, s := range g.structs {
   537  		g.genStruct(s.obj, s.t)
   538  	}
   539  	for _, intf := range g.interfaces {
   540  		g.genInterface(intf.obj)
   541  	}
   542  	for _, v := range g.vars {
   543  		g.genVar(v)
   544  	}
   545  	for _, f := range g.funcs {
   546  		g.genFunc(f)
   547  	}
   548  	// Switch to the original buffer, write the preamble
   549  	// and append the rest of the file.
   550  	g.Printer.Buf = oldBuf
   551  	g.genPreamble()
   552  	g.Printer.Buf.Write(newBuf.Bytes())
   553  	if len(g.err) > 0 {
   554  		return g.err
   555  	}
   556  	return nil
   557  }
   558  
   559  // pkgName retuns the package name and adds the package to the list of
   560  // imports.
   561  func (g *goGen) pkgName(pkg *types.Package) string {
   562  	// The error type has no package
   563  	if pkg == nil {
   564  		return ""
   565  	}
   566  	if name, exists := g.importMap[pkg]; exists {
   567  		return name + "."
   568  	}
   569  	i := 0
   570  	pname := pkg.Name()
   571  	name := pkg.Name()
   572  	for {
   573  		if _, exists := g.importNames[name]; !exists {
   574  			g.importNames[name] = struct{}{}
   575  			g.importMap[pkg] = name
   576  			var imp string
   577  			if pname != name {
   578  				imp = fmt.Sprintf("%s %q", name, pkg.Path())
   579  			} else {
   580  				imp = fmt.Sprintf("%q", pkg.Path())
   581  			}
   582  			g.imports = append(g.imports, imp)
   583  			break
   584  		}
   585  		i++
   586  		name = fmt.Sprintf("%s_%d", pname, i)
   587  	}
   588  	g.importMap[pkg] = name
   589  	return name + "."
   590  }