github.com/MrKrisYu/mobile@v0.0.0-20230923092425-9be92a9aeacc/bind/gen.go (about)

     1  // Copyright 2015 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/ast"
    11  	"go/token"
    12  	"go/types"
    13  	"io"
    14  	"regexp"
    15  	"strings"
    16  	"unicode"
    17  	"unicode/utf8"
    18  )
    19  
    20  type (
    21  	ErrorList []error
    22  
    23  	// varMode describes the lifetime of an argument or
    24  	// return value. Modes are used to guide the conversion
    25  	// of string and byte slice values across the language
    26  	// barrier. The same conversion mode must be used for
    27  	// both the conversion before a foreign call and the
    28  	// corresponding conversion after the call.
    29  	// See the mode* constants for a description of
    30  	// each mode.
    31  	varMode int
    32  )
    33  
    34  const (
    35  	// modeTransient are for function arguments that
    36  	// are not used after the function returns.
    37  	// Transient byte slices don't need copying
    38  	// when passed across the language barrier.
    39  	modeTransient varMode = iota
    40  	// modeRetained are for returned values and for function
    41  	// arguments that are used after the function returns.
    42  	// Retained byte slices need an intermediate copy.
    43  	modeRetained
    44  )
    45  
    46  func (list ErrorList) Error() string {
    47  	buf := new(bytes.Buffer)
    48  	for i, err := range list {
    49  		if i > 0 {
    50  			buf.WriteRune('\n')
    51  		}
    52  		io.WriteString(buf, err.Error())
    53  	}
    54  	return buf.String()
    55  }
    56  
    57  // interfaceInfo comes from Init and collects the auxiliary information
    58  // needed to generate bindings for an exported Go interface in a bound
    59  // package.
    60  type interfaceInfo struct {
    61  	obj     *types.TypeName
    62  	t       *types.Interface
    63  	summary ifaceSummary
    64  }
    65  
    66  // structInfo comes from Init and collects the auxiliary information
    67  // needed to generate bindings for an exported Go struct in a bound
    68  // package.
    69  type structInfo struct {
    70  	obj *types.TypeName
    71  	t   *types.Struct
    72  }
    73  
    74  // Generator contains the common Go package information
    75  // needed for the specific Go, Java, ObjC generators.
    76  //
    77  // After setting Printer, Fset, AllPkg, Pkg, the Init
    78  // method is used to initialize the auxiliary information
    79  // about the package to be generated, Pkg.
    80  type Generator struct {
    81  	*Printer
    82  	Fset   *token.FileSet
    83  	AllPkg []*types.Package
    84  	Files  []*ast.File
    85  	Pkg    *types.Package
    86  	err    ErrorList
    87  
    88  	// fields set by init.
    89  	pkgName   string
    90  	pkgPrefix string
    91  	funcs     []*types.Func
    92  	constants []*types.Const
    93  	vars      []*types.Var
    94  
    95  	interfaces []interfaceInfo
    96  	structs    []structInfo
    97  	otherNames []*types.TypeName
    98  	// allIntf contains interfaces from all bound packages.
    99  	allIntf []interfaceInfo
   100  
   101  	docs pkgDocs
   102  }
   103  
   104  // A pkgDocs maps the name of each exported package-level declaration to its extracted documentation.
   105  type pkgDocs map[string]*pkgDoc
   106  
   107  type pkgDoc struct {
   108  	doc string
   109  	// Struct or interface fields and methods.
   110  	members map[string]string
   111  }
   112  
   113  // pkgPrefix returns a prefix that disambiguates symbol names for binding
   114  // multiple packages.
   115  //
   116  // TODO(elias.naur): Avoid (and test) name clashes from multiple packages
   117  // with the same name. Perhaps use the index from the order the package is
   118  // generated.
   119  func pkgPrefix(pkg *types.Package) string {
   120  	// The error type has no package
   121  	if pkg == nil {
   122  		return ""
   123  	}
   124  	return pkg.Name()
   125  }
   126  
   127  func (g *Generator) Init() {
   128  	if g.Pkg != nil {
   129  		g.pkgName = g.Pkg.Name()
   130  	}
   131  	g.pkgPrefix = pkgPrefix(g.Pkg)
   132  
   133  	if g.Pkg != nil {
   134  		g.parseDocs()
   135  		scope := g.Pkg.Scope()
   136  		hasExported := false
   137  		for _, name := range scope.Names() {
   138  			obj := scope.Lookup(name)
   139  			if !obj.Exported() {
   140  				continue
   141  			}
   142  			hasExported = true
   143  			switch obj := obj.(type) {
   144  			case *types.Func:
   145  				if isCallable(obj) {
   146  					g.funcs = append(g.funcs, obj)
   147  				}
   148  			case *types.TypeName:
   149  				named, ok := obj.Type().(*types.Named)
   150  				if !ok {
   151  					continue
   152  				}
   153  				switch t := named.Underlying().(type) {
   154  				case *types.Struct:
   155  					g.structs = append(g.structs, structInfo{obj, t})
   156  				case *types.Interface:
   157  					g.interfaces = append(g.interfaces, interfaceInfo{obj, t, makeIfaceSummary(t)})
   158  				default:
   159  					g.otherNames = append(g.otherNames, obj)
   160  				}
   161  			case *types.Const:
   162  				g.constants = append(g.constants, obj)
   163  			case *types.Var:
   164  				g.vars = append(g.vars, obj)
   165  			default:
   166  				g.errorf("unsupported exported type for %s: %T", obj.Name(), obj)
   167  			}
   168  		}
   169  		if !hasExported {
   170  			g.errorf("no exported names in the package %q", g.Pkg.Path())
   171  		}
   172  	} else {
   173  		// Bind the single supported type from the universe scope, error.
   174  		errType := types.Universe.Lookup("error").(*types.TypeName)
   175  		t := errType.Type().Underlying().(*types.Interface)
   176  		g.interfaces = append(g.interfaces, interfaceInfo{errType, t, makeIfaceSummary(t)})
   177  	}
   178  	for _, p := range g.AllPkg {
   179  		scope := p.Scope()
   180  		for _, name := range scope.Names() {
   181  			obj := scope.Lookup(name)
   182  			if !obj.Exported() {
   183  				continue
   184  			}
   185  			if obj, ok := obj.(*types.TypeName); ok {
   186  				named, ok := obj.Type().(*types.Named)
   187  				if !ok {
   188  					continue
   189  				}
   190  				if t, ok := named.Underlying().(*types.Interface); ok {
   191  					g.allIntf = append(g.allIntf, interfaceInfo{obj, t, makeIfaceSummary(t)})
   192  				}
   193  			}
   194  		}
   195  	}
   196  }
   197  
   198  // parseDocs extracts documentation from a package in a form useful for lookups.
   199  func (g *Generator) parseDocs() {
   200  	d := make(pkgDocs)
   201  	for _, f := range g.Files {
   202  		for _, decl := range f.Decls {
   203  			switch decl := decl.(type) {
   204  			case *ast.GenDecl:
   205  				for _, spec := range decl.Specs {
   206  					switch spec := spec.(type) {
   207  					case *ast.TypeSpec:
   208  						d.addType(spec, decl.Doc)
   209  					case *ast.ValueSpec:
   210  						d.addValue(spec, decl.Doc)
   211  					}
   212  				}
   213  			case *ast.FuncDecl:
   214  				d.addFunc(decl)
   215  			}
   216  		}
   217  	}
   218  	g.docs = d
   219  }
   220  
   221  func (d pkgDocs) addValue(t *ast.ValueSpec, outerDoc *ast.CommentGroup) {
   222  	for _, n := range t.Names {
   223  		if !ast.IsExported(n.Name) {
   224  			continue
   225  		}
   226  		doc := t.Doc
   227  		if doc == nil {
   228  			doc = outerDoc
   229  		}
   230  		if doc != nil {
   231  			d[n.Name] = &pkgDoc{doc: doc.Text()}
   232  		}
   233  	}
   234  }
   235  
   236  func (d pkgDocs) addFunc(f *ast.FuncDecl) {
   237  	doc := f.Doc
   238  	if doc == nil {
   239  		return
   240  	}
   241  	fn := f.Name.Name
   242  	if !ast.IsExported(fn) {
   243  		return
   244  	}
   245  	if r := f.Recv; r != nil {
   246  		// f is a method.
   247  		n := typeName(r.List[0].Type)
   248  		pd, exists := d[n]
   249  		if !exists {
   250  			pd = &pkgDoc{members: make(map[string]string)}
   251  			d[n] = pd
   252  		}
   253  		pd.members[fn] = doc.Text()
   254  	} else {
   255  		// f is a function.
   256  		d[fn] = &pkgDoc{doc: doc.Text()}
   257  	}
   258  }
   259  
   260  func (d pkgDocs) addType(t *ast.TypeSpec, outerDoc *ast.CommentGroup) {
   261  	if !ast.IsExported(t.Name.Name) {
   262  		return
   263  	}
   264  	doc := t.Doc
   265  	if doc == nil {
   266  		doc = outerDoc
   267  	}
   268  	pd := d[t.Name.Name]
   269  	pd = &pkgDoc{members: make(map[string]string)}
   270  	d[t.Name.Name] = pd
   271  	if doc != nil {
   272  		pd.doc = doc.Text()
   273  	}
   274  	var fields *ast.FieldList
   275  	switch t := t.Type.(type) {
   276  	case *ast.StructType:
   277  		fields = t.Fields
   278  	case *ast.InterfaceType:
   279  		fields = t.Methods
   280  	}
   281  	if fields != nil {
   282  		for _, field := range fields.List {
   283  			if field.Doc != nil {
   284  				if field.Names == nil {
   285  					// Anonymous field. Extract name from its type.
   286  					if n := typeName(field.Type); ast.IsExported(n) {
   287  						pd.members[n] = field.Doc.Text()
   288  					}
   289  				}
   290  				for _, n := range field.Names {
   291  					if ast.IsExported(n.Name) {
   292  						pd.members[n.Name] = field.Doc.Text()
   293  					}
   294  				}
   295  			}
   296  		}
   297  	}
   298  }
   299  
   300  // typeName returns the type name T for expressions on the
   301  // T, *T, **T (etc.) form.
   302  func typeName(t ast.Expr) string {
   303  	switch t := t.(type) {
   304  	case *ast.StarExpr:
   305  		return typeName(t.X)
   306  	case *ast.Ident:
   307  		return t.Name
   308  	case *ast.SelectorExpr:
   309  		return t.Sel.Name
   310  	default:
   311  		return ""
   312  	}
   313  }
   314  
   315  func (d *pkgDoc) Doc() string {
   316  	if d == nil {
   317  		return ""
   318  	}
   319  	return d.doc
   320  }
   321  
   322  func (d *pkgDoc) Member(n string) string {
   323  	if d == nil {
   324  		return ""
   325  	}
   326  	return d.members[n]
   327  }
   328  
   329  // constructorType returns the type T for a function of the forms:
   330  //
   331  // func NewT...(...) *T
   332  // func NewT...(...) (*T, error)
   333  func (g *Generator) constructorType(f *types.Func) *types.TypeName {
   334  	sig := f.Type().(*types.Signature)
   335  	res := sig.Results()
   336  	if res.Len() != 1 && !(res.Len() == 2 && isErrorType(res.At(1).Type())) {
   337  		return nil
   338  	}
   339  	rt := res.At(0).Type()
   340  	pt, ok := rt.(*types.Pointer)
   341  	if !ok {
   342  		return nil
   343  	}
   344  	nt, ok := pt.Elem().(*types.Named)
   345  	if !ok {
   346  		return nil
   347  	}
   348  	obj := nt.Obj()
   349  	if !strings.HasPrefix(f.Name(), "New"+obj.Name()) {
   350  		return nil
   351  	}
   352  	return obj
   353  }
   354  
   355  func toCFlag(v bool) int {
   356  	if v {
   357  		return 1
   358  	}
   359  	return 0
   360  }
   361  
   362  func (g *Generator) errorf(format string, args ...interface{}) {
   363  	g.err = append(g.err, fmt.Errorf(format, args...))
   364  }
   365  
   366  // cgoType returns the name of a Cgo type suitable for converting a value of
   367  // the given type.
   368  func (g *Generator) cgoType(t types.Type) string {
   369  	switch t := t.(type) {
   370  	case *types.Basic:
   371  		switch t.Kind() {
   372  		case types.Bool, types.UntypedBool:
   373  			return "char"
   374  		case types.Int:
   375  			return "nint"
   376  		case types.Int8:
   377  			return "int8_t"
   378  		case types.Int16:
   379  			return "int16_t"
   380  		case types.Int32, types.UntypedRune: // types.Rune
   381  			return "int32_t"
   382  		case types.Int64, types.UntypedInt:
   383  			return "int64_t"
   384  		case types.Uint8: // types.Byte
   385  			return "uint8_t"
   386  		// TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64:
   387  		case types.Float32:
   388  			return "float"
   389  		case types.Float64, types.UntypedFloat:
   390  			return "double"
   391  		case types.String:
   392  			return "nstring"
   393  		default:
   394  			g.errorf("unsupported basic type: %s", t)
   395  		}
   396  	case *types.Slice:
   397  		switch e := t.Elem().(type) {
   398  		case *types.Basic:
   399  			switch e.Kind() {
   400  			case types.Uint8: // Byte.
   401  				return "nbyteslice"
   402  			default:
   403  				g.errorf("unsupported slice type: %s", t)
   404  			}
   405  		default:
   406  			g.errorf("unsupported slice type: %s", t)
   407  		}
   408  	case *types.Pointer:
   409  		if _, ok := t.Elem().(*types.Named); ok {
   410  			return g.cgoType(t.Elem())
   411  		}
   412  		g.errorf("unsupported pointer to type: %s", t)
   413  	case *types.Named:
   414  		return "int32_t"
   415  	default:
   416  		g.errorf("unsupported type: %s", t)
   417  	}
   418  	return "TODO"
   419  }
   420  
   421  func (g *Generator) genInterfaceMethodSignature(m *types.Func, iName string, header bool, g_paramName func(*types.Tuple, int) string) {
   422  	sig := m.Type().(*types.Signature)
   423  	params := sig.Params()
   424  	res := sig.Results()
   425  
   426  	if res.Len() == 0 {
   427  		g.Printf("void ")
   428  	} else {
   429  		if res.Len() == 1 {
   430  			g.Printf("%s ", g.cgoType(res.At(0).Type()))
   431  		} else {
   432  			if header {
   433  				g.Printf("typedef struct cproxy%s_%s_%s_return {\n", g.pkgPrefix, iName, m.Name())
   434  				g.Indent()
   435  				for i := 0; i < res.Len(); i++ {
   436  					t := res.At(i).Type()
   437  					g.Printf("%s r%d;\n", g.cgoType(t), i)
   438  				}
   439  				g.Outdent()
   440  				g.Printf("} cproxy%s_%s_%s_return;\n", g.pkgPrefix, iName, m.Name())
   441  			}
   442  			g.Printf("struct cproxy%s_%s_%s_return ", g.pkgPrefix, iName, m.Name())
   443  		}
   444  	}
   445  	g.Printf("cproxy%s_%s_%s(int32_t refnum", g.pkgPrefix, iName, m.Name())
   446  	for i := 0; i < params.Len(); i++ {
   447  		t := params.At(i).Type()
   448  		g.Printf(", %s %s", g.cgoType(t), g_paramName(params, i))
   449  	}
   450  	g.Printf(")")
   451  	if header {
   452  		g.Printf(";\n")
   453  	} else {
   454  		g.Printf(" {\n")
   455  	}
   456  }
   457  
   458  func (g *Generator) validPkg(pkg *types.Package) bool {
   459  	for _, p := range g.AllPkg {
   460  		if p == pkg {
   461  			return true
   462  		}
   463  	}
   464  	return false
   465  }
   466  
   467  // isSigSupported reports whether the generators can handle a given
   468  // function signature.
   469  func (g *Generator) isSigSupported(t types.Type) bool {
   470  	sig := t.(*types.Signature)
   471  	params := sig.Params()
   472  	for i := 0; i < params.Len(); i++ {
   473  		if !g.isSupported(params.At(i).Type()) {
   474  			return false
   475  		}
   476  	}
   477  	res := sig.Results()
   478  	for i := 0; i < res.Len(); i++ {
   479  		if !g.isSupported(res.At(i).Type()) {
   480  			return false
   481  		}
   482  	}
   483  	return true
   484  }
   485  
   486  // isSupported reports whether the generators can handle the type.
   487  func (g *Generator) isSupported(t types.Type) bool {
   488  	if isErrorType(t) || isWrapperType(t) {
   489  		return true
   490  	}
   491  	switch t := t.(type) {
   492  	case *types.Basic:
   493  		switch t.Kind() {
   494  		case types.Bool, types.UntypedBool,
   495  			types.Int,
   496  			types.Int8, types.Uint8, // types.Byte
   497  			types.Int16,
   498  			types.Int32, types.UntypedRune, // types.Rune
   499  			types.Int64, types.UntypedInt,
   500  			types.Float32,
   501  			types.Float64, types.UntypedFloat,
   502  			types.String, types.UntypedString:
   503  			return true
   504  		}
   505  		return false
   506  	case *types.Slice:
   507  		switch e := t.Elem().(type) {
   508  		case *types.Basic:
   509  			return e.Kind() == types.Uint8
   510  		}
   511  	case *types.Pointer:
   512  		switch t := t.Elem().(type) {
   513  		case *types.Named:
   514  			return g.validPkg(t.Obj().Pkg())
   515  		}
   516  	case *types.Named:
   517  		switch t.Underlying().(type) {
   518  		case *types.Interface, *types.Pointer:
   519  			return g.validPkg(t.Obj().Pkg())
   520  		}
   521  	}
   522  	return false
   523  }
   524  
   525  var paramRE = regexp.MustCompile(`^p[0-9]*$`)
   526  
   527  // basicParamName replaces incompatible name with a p0-pN name.
   528  // Missing names, or existing names of the form p[0-9] are incompatible.
   529  func basicParamName(params *types.Tuple, pos int) string {
   530  	name := params.At(pos).Name()
   531  	if name == "" || name[0] == '_' || paramRE.MatchString(name) {
   532  		name = fmt.Sprintf("p%d", pos)
   533  	}
   534  	return name
   535  }
   536  
   537  func lowerFirst(s string) string {
   538  	if s == "" {
   539  		return ""
   540  	}
   541  
   542  	var conv []rune
   543  	for len(s) > 0 {
   544  		r, n := utf8.DecodeRuneInString(s)
   545  		if !unicode.IsUpper(r) {
   546  			if l := len(conv); l > 1 {
   547  				conv[l-1] = unicode.ToUpper(conv[l-1])
   548  			}
   549  			return string(conv) + s
   550  		}
   551  		conv = append(conv, unicode.ToLower(r))
   552  		s = s[n:]
   553  	}
   554  	return string(conv)
   555  }
   556  
   557  // newNameSanitizer returns a functions that replaces all dashes and dots
   558  // with underscores, as well as avoiding reserved words by suffixing such
   559  // identifiers with underscores.
   560  func newNameSanitizer(res []string) func(s string) string {
   561  	reserved := make(map[string]bool)
   562  	for _, word := range res {
   563  		reserved[word] = true
   564  	}
   565  	symbols := strings.NewReplacer(
   566  		"-", "_",
   567  		".", "_",
   568  	)
   569  	return func(s string) string {
   570  		if reserved[s] {
   571  			return s + "_"
   572  		}
   573  		return symbols.Replace(s)
   574  	}
   575  }