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