github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/cgo/cgo.go (about)

     1  // Package cgo implements CGo by modifying a loaded AST. It does this by parsing
     2  // the `import "C"` statements found in the source code with libclang and
     3  // generating stub function and global declarations.
     4  //
     5  // There are a few advantages to modifying the AST directly instead of doing CGo
     6  // as a preprocessing step, with the main advantage being that debug information
     7  // is kept intact as much as possible.
     8  package cgo
     9  
    10  // This file extracts the `import "C"` statement from the source and modifies
    11  // the AST for CGo. It does not use libclang directly: see libclang.go for the C
    12  // source file parsing.
    13  
    14  import (
    15  	"fmt"
    16  	"go/ast"
    17  	"go/parser"
    18  	"go/scanner"
    19  	"go/token"
    20  	"path/filepath"
    21  	"strconv"
    22  	"strings"
    23  
    24  	"github.com/google/shlex"
    25  	"golang.org/x/tools/go/ast/astutil"
    26  )
    27  
    28  // Function that's only defined in Go 1.22.
    29  var setASTFileFields = func(f *ast.File, start, end token.Pos) {
    30  }
    31  
    32  // cgoPackage holds all CGo-related information of a package.
    33  type cgoPackage struct {
    34  	generated       *ast.File
    35  	packageName     string
    36  	cgoFiles        []*ast.File
    37  	generatedPos    token.Pos
    38  	errors          []error
    39  	currentDir      string // current working directory
    40  	packageDir      string // full path to the package to process
    41  	importPath      string
    42  	fset            *token.FileSet
    43  	tokenFiles      map[string]*token.File
    44  	definedGlobally map[string]ast.Node
    45  	anonDecls       map[interface{}]string
    46  	cflags          []string // CFlags from #cgo lines
    47  	ldflags         []string // LDFlags from #cgo lines
    48  	visitedFiles    map[string][]byte
    49  	cgoHeaders      []string
    50  }
    51  
    52  // cgoFile holds information only for a single Go file (with one or more
    53  // `import "C"` statements).
    54  type cgoFile struct {
    55  	*cgoPackage
    56  	file    *ast.File
    57  	index   int
    58  	defined map[string]ast.Node
    59  	names   map[string]clangCursor
    60  }
    61  
    62  // elaboratedTypeInfo contains some information about an elaborated type
    63  // (struct, union) found in the C AST.
    64  type elaboratedTypeInfo struct {
    65  	typeExpr   *ast.StructType
    66  	pos        token.Pos
    67  	bitfields  []bitfieldInfo
    68  	unionSize  int64 // union size in bytes, nonzero when union getters/setters should be created
    69  	unionAlign int64 // union alignment in bytes
    70  }
    71  
    72  // bitfieldInfo contains information about a single bitfield in a struct. It
    73  // keeps information about the start, end, and the special (renamed) base field
    74  // of this bitfield.
    75  type bitfieldInfo struct {
    76  	field    *ast.Field
    77  	name     string
    78  	pos      token.Pos
    79  	startBit int64
    80  	endBit   int64 // may be 0 meaning "until the end of the field"
    81  }
    82  
    83  // cgoAliases list type aliases between Go and C, for types that are equivalent
    84  // in both languages. See addTypeAliases.
    85  var cgoAliases = map[string]string{
    86  	"C.int8_t":    "int8",
    87  	"C.int16_t":   "int16",
    88  	"C.int32_t":   "int32",
    89  	"C.int64_t":   "int64",
    90  	"C.uint8_t":   "uint8",
    91  	"C.uint16_t":  "uint16",
    92  	"C.uint32_t":  "uint32",
    93  	"C.uint64_t":  "uint64",
    94  	"C.uintptr_t": "uintptr",
    95  	"C.float":     "float32",
    96  	"C.double":    "float64",
    97  	"C._Bool":     "bool",
    98  }
    99  
   100  // builtinAliases are handled specially because they only exist on the Go side
   101  // of CGo, not on the CGo side (they're prefixed with "_Cgo_" there).
   102  var builtinAliases = []string{
   103  	"char",
   104  	"schar",
   105  	"uchar",
   106  	"short",
   107  	"ushort",
   108  	"int",
   109  	"uint",
   110  	"long",
   111  	"ulong",
   112  	"longlong",
   113  	"ulonglong",
   114  }
   115  
   116  // builtinAliasTypedefs lists some C types with ambiguous sizes that must be
   117  // retrieved somehow from C. This is done by adding some typedefs to get the
   118  // size of each type.
   119  const builtinAliasTypedefs = `
   120  # 1 "<cgo>"
   121  typedef char                _Cgo_char;
   122  typedef signed char         _Cgo_schar;
   123  typedef unsigned char       _Cgo_uchar;
   124  typedef short               _Cgo_short;
   125  typedef unsigned short      _Cgo_ushort;
   126  typedef int                 _Cgo_int;
   127  typedef unsigned int        _Cgo_uint;
   128  typedef long                _Cgo_long;
   129  typedef unsigned long       _Cgo_ulong;
   130  typedef long long           _Cgo_longlong;
   131  typedef unsigned long long  _Cgo_ulonglong;
   132  `
   133  
   134  // First part of the generated Go file. Written here as Go because that's much
   135  // easier than constructing the entire AST in memory.
   136  // The string/bytes functions below implement C.CString etc. To make sure the
   137  // runtime doesn't need to know the C int type, lengths are converted to uintptr
   138  // first.
   139  // These functions will be modified to get a "C." prefix, so the source below
   140  // doesn't reflect the final AST.
   141  const generatedGoFilePrefix = `
   142  import "unsafe"
   143  
   144  var _ unsafe.Pointer
   145  
   146  //go:linkname C.CString runtime.cgo_CString
   147  func CString(string) *C.char
   148  
   149  //go:linkname C.GoString runtime.cgo_GoString
   150  func GoString(*C.char) string
   151  
   152  //go:linkname C.__GoStringN runtime.cgo_GoStringN
   153  func __GoStringN(*C.char, uintptr) string
   154  
   155  func GoStringN(cstr *C.char, length C.int) string {
   156  	return C.__GoStringN(cstr, uintptr(length))
   157  }
   158  
   159  //go:linkname C.__GoBytes runtime.cgo_GoBytes
   160  func __GoBytes(unsafe.Pointer, uintptr) []byte
   161  
   162  func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
   163  	return C.__GoBytes(ptr, uintptr(length))
   164  }
   165  `
   166  
   167  // Process extracts `import "C"` statements from the AST, parses the comment
   168  // with libclang, and modifies the AST to use this information. It returns a
   169  // newly created *ast.File that should be added to the list of to-be-parsed
   170  // files, the CGo header snippets that should be compiled (for inline
   171  // functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
   172  // hashes of the accessed C header files. If there is one or more error, it
   173  // returns these in the []error slice but still modifies the AST.
   174  func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cflags []string) ([]*ast.File, []string, []string, []string, map[string][]byte, []error) {
   175  	p := &cgoPackage{
   176  		packageName:     files[0].Name.Name,
   177  		currentDir:      dir,
   178  		importPath:      importPath,
   179  		fset:            fset,
   180  		tokenFiles:      map[string]*token.File{},
   181  		definedGlobally: map[string]ast.Node{},
   182  		anonDecls:       map[interface{}]string{},
   183  		visitedFiles:    map[string][]byte{},
   184  	}
   185  
   186  	// Add a new location for the following file.
   187  	generatedTokenPos := p.fset.AddFile(dir+"/!cgo.go", -1, 0)
   188  	generatedTokenPos.SetLines([]int{0})
   189  	p.generatedPos = generatedTokenPos.Pos(0)
   190  
   191  	// Find the absolute path for this package.
   192  	packagePath, err := filepath.Abs(fset.File(files[0].Pos()).Name())
   193  	if err != nil {
   194  		return nil, nil, nil, nil, nil, []error{
   195  			scanner.Error{
   196  				Pos: fset.Position(files[0].Pos()),
   197  				Msg: "cgo: cannot find absolute path: " + err.Error(), // TODO: wrap this error
   198  			},
   199  		}
   200  	}
   201  	p.packageDir = filepath.Dir(packagePath)
   202  
   203  	// Construct a new in-memory AST for CGo declarations of this package.
   204  	// The first part is written as Go code that is then parsed, but more code
   205  	// is added later to the AST to declare functions, globals, etc.
   206  	goCode := "package " + files[0].Name.Name + "\n\n" + generatedGoFilePrefix
   207  	p.generated, err = parser.ParseFile(fset, dir+"/!cgo.go", goCode, parser.ParseComments)
   208  	if err != nil {
   209  		// This is always a bug in the cgo package.
   210  		panic("unexpected error: " + err.Error())
   211  	}
   212  	p.cgoFiles = append(p.cgoFiles, p.generated)
   213  	// If the Comments field is not set to nil, the go/format package will get
   214  	// confused about where comments should go.
   215  	p.generated.Comments = nil
   216  	// Adjust some of the functions in there.
   217  	for _, decl := range p.generated.Decls {
   218  		switch decl := decl.(type) {
   219  		case *ast.FuncDecl:
   220  			switch decl.Name.Name {
   221  			case "CString", "GoString", "GoStringN", "__GoStringN", "GoBytes", "__GoBytes":
   222  				// Adjust the name to have a "C." prefix so it is correctly
   223  				// resolved.
   224  				decl.Name.Name = "C." + decl.Name.Name
   225  			}
   226  		}
   227  	}
   228  	// Patch some types, for example *C.char in C.CString.
   229  	cf := p.newCGoFile(nil, -1) // dummy *cgoFile for the walker
   230  	astutil.Apply(p.generated, func(cursor *astutil.Cursor) bool {
   231  		return cf.walker(cursor, nil)
   232  	}, nil)
   233  
   234  	// Find `import "C"` C fragments in the file.
   235  	p.cgoHeaders = make([]string, len(files)) // combined CGo header fragment for each file
   236  	for i, f := range files {
   237  		var cgoHeader string
   238  		for i := 0; i < len(f.Decls); i++ {
   239  			decl := f.Decls[i]
   240  			genDecl, ok := decl.(*ast.GenDecl)
   241  			if !ok {
   242  				continue
   243  			}
   244  			if len(genDecl.Specs) != 1 {
   245  				continue
   246  			}
   247  			spec, ok := genDecl.Specs[0].(*ast.ImportSpec)
   248  			if !ok {
   249  				continue
   250  			}
   251  			path, err := strconv.Unquote(spec.Path.Value)
   252  			if err != nil {
   253  				// This should not happen. An import path that is not properly
   254  				// quoted should not exist in a correct AST.
   255  				panic("could not parse import path: " + err.Error())
   256  			}
   257  			if path != "C" {
   258  				continue
   259  			}
   260  
   261  			// Remove this import declaration.
   262  			f.Decls = append(f.Decls[:i], f.Decls[i+1:]...)
   263  			i--
   264  
   265  			if genDecl.Doc == nil {
   266  				continue
   267  			}
   268  
   269  			// Iterate through all parts of the CGo header. Note that every //
   270  			// line is a new comment.
   271  			position := fset.Position(genDecl.Doc.Pos())
   272  			fragment := fmt.Sprintf("# %d %#v\n", position.Line, position.Filename)
   273  			for _, comment := range genDecl.Doc.List {
   274  				// Find all #cgo lines, extract and use their contents, and
   275  				// replace the lines with spaces (to preserve locations).
   276  				c := p.parseCGoPreprocessorLines(comment.Text, comment.Slash)
   277  
   278  				// Change the comment (which is still in Go syntax, with // and
   279  				// /* */ ) to a regular string by replacing the start/end
   280  				// markers of comments with spaces.
   281  				// It is similar to the Text() method but differs in that it
   282  				// doesn't strip anything and tries to keep all offsets correct
   283  				// by adding spaces and newlines where necessary.
   284  				if c[1] == '/' { /* comment */
   285  					c = "  " + c[2:]
   286  				} else { // comment
   287  					c = "  " + c[2:len(c)-2]
   288  				}
   289  				fragment += c + "\n"
   290  			}
   291  			cgoHeader += fragment
   292  		}
   293  
   294  		p.cgoHeaders[i] = cgoHeader
   295  	}
   296  
   297  	// Define CFlags that will be used while parsing the package.
   298  	// Disable _FORTIFY_SOURCE as it causes problems on macOS.
   299  	// Note that it is only disabled for memcpy (etc) calls made from Go, which
   300  	// have better alternatives anyway.
   301  	cflagsForCGo := append([]string{"-D_FORTIFY_SOURCE=0"}, cflags...)
   302  	cflagsForCGo = append(cflagsForCGo, p.cflags...)
   303  
   304  	// Retrieve types such as C.int, C.longlong, etc from C.
   305  	p.newCGoFile(nil, -1).readNames(builtinAliasTypedefs, cflagsForCGo, "", func(names map[string]clangCursor) {
   306  		gen := &ast.GenDecl{
   307  			TokPos: token.NoPos,
   308  			Tok:    token.TYPE,
   309  		}
   310  		for _, name := range builtinAliases {
   311  			typeSpec := p.getIntegerType("C."+name, names["_Cgo_"+name])
   312  			gen.Specs = append(gen.Specs, typeSpec)
   313  		}
   314  		p.generated.Decls = append(p.generated.Decls, gen)
   315  	})
   316  
   317  	// Process CGo imports for each file.
   318  	for i, f := range files {
   319  		cf := p.newCGoFile(f, i)
   320  		// These types are aliased with the corresponding types in C. For
   321  		// example, float in C is always float32 in Go.
   322  		cf.names["float"] = clangCursor{}
   323  		cf.names["double"] = clangCursor{}
   324  		cf.names["_Bool"] = clangCursor{}
   325  		// Now read all the names (identifies) that C defines in the header
   326  		// snippet.
   327  		cf.readNames(p.cgoHeaders[i], cflagsForCGo, filepath.Base(fset.File(f.Pos()).Name()), func(names map[string]clangCursor) {
   328  			for _, name := range builtinAliases {
   329  				// Names such as C.int should not be obtained from C.
   330  				// This works around an issue in picolibc that has `#define int`
   331  				// in a header file.
   332  				delete(names, name)
   333  			}
   334  			astutil.Apply(f, func(cursor *astutil.Cursor) bool {
   335  				return cf.walker(cursor, names)
   336  			}, nil)
   337  		})
   338  	}
   339  
   340  	// Print the newly generated in-memory AST, for debugging.
   341  	//ast.Print(fset, p.generated)
   342  
   343  	return p.cgoFiles, p.cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
   344  }
   345  
   346  func (p *cgoPackage) newCGoFile(file *ast.File, index int) *cgoFile {
   347  	return &cgoFile{
   348  		cgoPackage: p,
   349  		file:       file,
   350  		index:      index,
   351  		defined:    make(map[string]ast.Node),
   352  		names:      make(map[string]clangCursor),
   353  	}
   354  }
   355  
   356  // makePathsAbsolute converts some common path compiler flags (-I, -L) from
   357  // relative flags into absolute flags, if they are relative. This is necessary
   358  // because the C compiler is usually not invoked from the package path.
   359  func (p *cgoPackage) makePathsAbsolute(args []string) {
   360  	nextIsPath := false
   361  	for i, arg := range args {
   362  		if nextIsPath {
   363  			if !filepath.IsAbs(arg) {
   364  				args[i] = filepath.Join(p.packageDir, arg)
   365  			}
   366  		}
   367  		if arg == "-I" || arg == "-L" {
   368  			nextIsPath = true
   369  			continue
   370  		}
   371  		if strings.HasPrefix(arg, "-I") || strings.HasPrefix(arg, "-L") {
   372  			path := arg[2:]
   373  			if !filepath.IsAbs(path) {
   374  				args[i] = arg[:2] + filepath.Join(p.packageDir, path)
   375  			}
   376  		}
   377  	}
   378  }
   379  
   380  // parseCGoPreprocessorLines reads #cgo pseudo-preprocessor lines in the source
   381  // text (import "C" fragment), stores their information such as CFLAGS, and
   382  // returns the same text but with those #cgo lines replaced by spaces (to keep
   383  // position offsets the same).
   384  func (p *cgoPackage) parseCGoPreprocessorLines(text string, pos token.Pos) string {
   385  	for {
   386  		// Extract the #cgo line, and replace it with spaces.
   387  		// Replacing with spaces makes sure that error locations are
   388  		// still correct, while not interfering with parsing in any way.
   389  		lineStart := strings.Index(text, "#cgo ")
   390  		if lineStart < 0 {
   391  			break
   392  		}
   393  		lineLen := strings.IndexByte(text[lineStart:], '\n')
   394  		if lineLen < 0 {
   395  			lineLen = len(text) - lineStart
   396  		}
   397  		lineEnd := lineStart + lineLen
   398  		line := text[lineStart:lineEnd]
   399  		spaces := make([]byte, len(line))
   400  		for i := range spaces {
   401  			spaces[i] = ' '
   402  		}
   403  		text = text[:lineStart] + string(spaces) + text[lineEnd:]
   404  
   405  		// Get the text before the colon in the #cgo directive.
   406  		colon := strings.IndexByte(line, ':')
   407  		if colon < 0 {
   408  			p.addErrorAfter(pos, text[:lineStart], "missing colon in #cgo line")
   409  			continue
   410  		}
   411  
   412  		// Extract the fields before the colon. These fields are a list
   413  		// of build tags and the C environment variable.
   414  		fields := strings.Fields(line[4:colon])
   415  		if len(fields) == 0 {
   416  			p.addErrorAfter(pos, text[:lineStart+colon-1], "invalid #cgo line")
   417  			continue
   418  		}
   419  
   420  		if len(fields) > 1 {
   421  			p.addErrorAfter(pos, text[:lineStart+5], "not implemented: build constraints in #cgo line")
   422  			continue
   423  		}
   424  
   425  		name := fields[len(fields)-1]
   426  		value := line[colon+1:]
   427  		switch name {
   428  		case "CFLAGS":
   429  			flags, err := shlex.Split(value)
   430  			if err != nil {
   431  				// TODO: find the exact location where the error happened.
   432  				p.addErrorAfter(pos, text[:lineStart+colon+1], "failed to parse flags in #cgo line: "+err.Error())
   433  				continue
   434  			}
   435  			if err := checkCompilerFlags(name, flags); err != nil {
   436  				p.addErrorAfter(pos, text[:lineStart+colon+1], err.Error())
   437  				continue
   438  			}
   439  			p.makePathsAbsolute(flags)
   440  			p.cflags = append(p.cflags, flags...)
   441  		case "LDFLAGS":
   442  			flags, err := shlex.Split(value)
   443  			if err != nil {
   444  				// TODO: find the exact location where the error happened.
   445  				p.addErrorAfter(pos, text[:lineStart+colon+1], "failed to parse flags in #cgo line: "+err.Error())
   446  				continue
   447  			}
   448  			if err := checkLinkerFlags(name, flags); err != nil {
   449  				p.addErrorAfter(pos, text[:lineStart+colon+1], err.Error())
   450  				continue
   451  			}
   452  			p.makePathsAbsolute(flags)
   453  			p.ldflags = append(p.ldflags, flags...)
   454  		default:
   455  			startPos := strings.LastIndex(line[4:colon], name) + 4
   456  			p.addErrorAfter(pos, text[:lineStart+startPos], "invalid #cgo line: "+name)
   457  			continue
   458  		}
   459  	}
   460  	return text
   461  }
   462  
   463  // makeUnionField creates a new struct from an existing *elaboratedTypeInfo,
   464  // that has just a single field that must be accessed through special accessors.
   465  // It returns nil when there is an error. In case of an error, that error has
   466  // already been added to the list of errors using p.addError.
   467  func (p *cgoPackage) makeUnionField(typ *elaboratedTypeInfo) *ast.StructType {
   468  	unionFieldTypeName, ok := map[int64]string{
   469  		1: "uint8",
   470  		2: "uint16",
   471  		4: "uint32",
   472  		8: "uint64",
   473  	}[typ.unionAlign]
   474  	if !ok {
   475  		p.addError(typ.typeExpr.Struct, fmt.Sprintf("expected union alignment to be one of 1, 2, 4, or 8, but got %d", typ.unionAlign))
   476  		return nil
   477  	}
   478  	var unionFieldType ast.Expr = &ast.Ident{
   479  		NamePos: token.NoPos,
   480  		Name:    unionFieldTypeName,
   481  	}
   482  	if typ.unionSize != typ.unionAlign {
   483  		// A plain struct{uintX} isn't enough, we have to make a
   484  		// struct{[N]uintX} to make the union big enough.
   485  		if typ.unionSize/typ.unionAlign*typ.unionAlign != typ.unionSize {
   486  			p.addError(typ.typeExpr.Struct, fmt.Sprintf("union alignment (%d) must be a multiple of union alignment (%d)", typ.unionSize, typ.unionAlign))
   487  			return nil
   488  		}
   489  		unionFieldType = &ast.ArrayType{
   490  			Len: &ast.BasicLit{
   491  				Kind:  token.INT,
   492  				Value: strconv.FormatInt(typ.unionSize/typ.unionAlign, 10),
   493  			},
   494  			Elt: unionFieldType,
   495  		}
   496  	}
   497  	return &ast.StructType{
   498  		Struct: typ.typeExpr.Struct,
   499  		Fields: &ast.FieldList{
   500  			Opening: typ.typeExpr.Fields.Opening,
   501  			List: []*ast.Field{{
   502  				Names: []*ast.Ident{
   503  					{
   504  						NamePos: typ.typeExpr.Fields.Opening,
   505  						Name:    "$union",
   506  					},
   507  				},
   508  				Type: unionFieldType,
   509  			}},
   510  			Closing: typ.typeExpr.Fields.Closing,
   511  		},
   512  	}
   513  }
   514  
   515  // createUnionAccessor creates a function that returns a typed pointer to a
   516  // union field for each field in a union. For example:
   517  //
   518  //	func (union *C.union_1) unionfield_d() *float64 {
   519  //	    return (*float64)(unsafe.Pointer(&union.$union))
   520  //	}
   521  //
   522  // Where C.union_1 is defined as:
   523  //
   524  //	type C.union_1 struct{
   525  //	    $union uint64
   526  //	}
   527  //
   528  // The returned pointer can be used to get or set the field, or get the pointer
   529  // to a subfield.
   530  func (p *cgoPackage) createUnionAccessor(field *ast.Field, typeName string) {
   531  	if len(field.Names) != 1 {
   532  		panic("number of names in union field must be exactly 1")
   533  	}
   534  	fieldName := field.Names[0]
   535  	pos := fieldName.NamePos
   536  
   537  	// The method receiver.
   538  	receiver := &ast.SelectorExpr{
   539  		X: &ast.Ident{
   540  			NamePos: pos,
   541  			Name:    "union",
   542  			Obj:     nil,
   543  		},
   544  		Sel: &ast.Ident{
   545  			NamePos: pos,
   546  			Name:    "$union",
   547  		},
   548  	}
   549  
   550  	// Get the address of the $union field.
   551  	receiverPtr := &ast.UnaryExpr{
   552  		Op: token.AND,
   553  		X:  receiver,
   554  	}
   555  
   556  	// Cast to unsafe.Pointer.
   557  	sourcePointer := &ast.CallExpr{
   558  		Fun: &ast.SelectorExpr{
   559  			X:   &ast.Ident{Name: "unsafe"},
   560  			Sel: &ast.Ident{Name: "Pointer"},
   561  		},
   562  		Args: []ast.Expr{receiverPtr},
   563  	}
   564  
   565  	// Cast to the target pointer type.
   566  	targetPointer := &ast.CallExpr{
   567  		Lparen: pos,
   568  		Fun: &ast.ParenExpr{
   569  			Lparen: pos,
   570  			X: &ast.StarExpr{
   571  				X: field.Type,
   572  			},
   573  			Rparen: pos,
   574  		},
   575  		Args:   []ast.Expr{sourcePointer},
   576  		Rparen: pos,
   577  	}
   578  
   579  	// Create the accessor function.
   580  	accessor := &ast.FuncDecl{
   581  		Recv: &ast.FieldList{
   582  			Opening: pos,
   583  			List: []*ast.Field{
   584  				{
   585  					Names: []*ast.Ident{
   586  						{
   587  							NamePos: pos,
   588  							Name:    "union",
   589  						},
   590  					},
   591  					Type: &ast.StarExpr{
   592  						Star: pos,
   593  						X: &ast.Ident{
   594  							NamePos: pos,
   595  							Name:    typeName,
   596  							Obj:     nil,
   597  						},
   598  					},
   599  				},
   600  			},
   601  			Closing: pos,
   602  		},
   603  		Name: &ast.Ident{
   604  			NamePos: pos,
   605  			Name:    "unionfield_" + fieldName.Name,
   606  		},
   607  		Type: &ast.FuncType{
   608  			Func: pos,
   609  			Params: &ast.FieldList{
   610  				Opening: pos,
   611  				Closing: pos,
   612  			},
   613  			Results: &ast.FieldList{
   614  				List: []*ast.Field{
   615  					{
   616  						Type: &ast.StarExpr{
   617  							Star: pos,
   618  							X:    field.Type,
   619  						},
   620  					},
   621  				},
   622  			},
   623  		},
   624  		Body: &ast.BlockStmt{
   625  			Lbrace: pos,
   626  			List: []ast.Stmt{
   627  				&ast.ReturnStmt{
   628  					Return: pos,
   629  					Results: []ast.Expr{
   630  						targetPointer,
   631  					},
   632  				},
   633  			},
   634  			Rbrace: pos,
   635  		},
   636  	}
   637  	p.generated.Decls = append(p.generated.Decls, accessor)
   638  }
   639  
   640  // createBitfieldGetter creates a bitfield getter function like the following:
   641  //
   642  //	func (s *C.struct_foo) bitfield_b() byte {
   643  //	    return (s.__bitfield_1 >> 5) & 0x1
   644  //	}
   645  func (p *cgoPackage) createBitfieldGetter(bitfield bitfieldInfo, typeName string) {
   646  	// The value to return from the getter.
   647  	// Not complete: this is just an expression to get the complete field.
   648  	var result ast.Expr = &ast.SelectorExpr{
   649  		X: &ast.Ident{
   650  			NamePos: bitfield.pos,
   651  			Name:    "s",
   652  			Obj:     nil,
   653  		},
   654  		Sel: &ast.Ident{
   655  			NamePos: bitfield.pos,
   656  			Name:    bitfield.field.Names[0].Name,
   657  		},
   658  	}
   659  	if bitfield.startBit != 0 {
   660  		// Shift to the right by .startBit so that fields that come before are
   661  		// shifted off.
   662  		result = &ast.BinaryExpr{
   663  			X:     result,
   664  			OpPos: bitfield.pos,
   665  			Op:    token.SHR,
   666  			Y: &ast.BasicLit{
   667  				ValuePos: bitfield.pos,
   668  				Kind:     token.INT,
   669  				Value:    strconv.FormatInt(bitfield.startBit, 10),
   670  			},
   671  		}
   672  	}
   673  	if bitfield.endBit != 0 {
   674  		// Mask off the high bits so that fields that come after this field are
   675  		// masked off.
   676  		and := (uint64(1) << uint64(bitfield.endBit-bitfield.startBit)) - 1
   677  		result = &ast.BinaryExpr{
   678  			X:     result,
   679  			OpPos: bitfield.pos,
   680  			Op:    token.AND,
   681  			Y: &ast.BasicLit{
   682  				ValuePos: bitfield.pos,
   683  				Kind:     token.INT,
   684  				Value:    "0x" + strconv.FormatUint(and, 16),
   685  			},
   686  		}
   687  	}
   688  
   689  	// Create the getter function.
   690  	getter := &ast.FuncDecl{
   691  		Recv: &ast.FieldList{
   692  			Opening: bitfield.pos,
   693  			List: []*ast.Field{
   694  				{
   695  					Names: []*ast.Ident{
   696  						{
   697  							NamePos: bitfield.pos,
   698  							Name:    "s",
   699  							Obj: &ast.Object{
   700  								Kind: ast.Var,
   701  								Name: "s",
   702  								Decl: nil,
   703  							},
   704  						},
   705  					},
   706  					Type: &ast.StarExpr{
   707  						Star: bitfield.pos,
   708  						X: &ast.Ident{
   709  							NamePos: bitfield.pos,
   710  							Name:    typeName,
   711  							Obj:     nil,
   712  						},
   713  					},
   714  				},
   715  			},
   716  			Closing: bitfield.pos,
   717  		},
   718  		Name: &ast.Ident{
   719  			NamePos: bitfield.pos,
   720  			Name:    "bitfield_" + bitfield.name,
   721  		},
   722  		Type: &ast.FuncType{
   723  			Func: bitfield.pos,
   724  			Params: &ast.FieldList{
   725  				Opening: bitfield.pos,
   726  				Closing: bitfield.pos,
   727  			},
   728  			Results: &ast.FieldList{
   729  				List: []*ast.Field{
   730  					{
   731  						Type: bitfield.field.Type,
   732  					},
   733  				},
   734  			},
   735  		},
   736  		Body: &ast.BlockStmt{
   737  			Lbrace: bitfield.pos,
   738  			List: []ast.Stmt{
   739  				&ast.ReturnStmt{
   740  					Return: bitfield.pos,
   741  					Results: []ast.Expr{
   742  						result,
   743  					},
   744  				},
   745  			},
   746  			Rbrace: bitfield.pos,
   747  		},
   748  	}
   749  	p.generated.Decls = append(p.generated.Decls, getter)
   750  }
   751  
   752  // createBitfieldSetter creates a bitfield setter function like the following:
   753  //
   754  //	func (s *C.struct_foo) set_bitfield_b(value byte) {
   755  //	    s.__bitfield_1 = s.__bitfield_1 ^ 0x60 | ((value & 1) << 5)
   756  //	}
   757  //
   758  // Or the following:
   759  //
   760  //	func (s *C.struct_foo) set_bitfield_c(value byte) {
   761  //	    s.__bitfield_1 = s.__bitfield_1 & 0x3f | (value << 6)
   762  //	}
   763  func (p *cgoPackage) createBitfieldSetter(bitfield bitfieldInfo, typeName string) {
   764  	// The full field with all bitfields.
   765  	var field ast.Expr = &ast.SelectorExpr{
   766  		X: &ast.Ident{
   767  			NamePos: bitfield.pos,
   768  			Name:    "s",
   769  			Obj:     nil,
   770  		},
   771  		Sel: &ast.Ident{
   772  			NamePos: bitfield.pos,
   773  			Name:    bitfield.field.Names[0].Name,
   774  		},
   775  	}
   776  	// The value to insert into the field.
   777  	var valueToInsert ast.Expr = &ast.Ident{
   778  		NamePos: bitfield.pos,
   779  		Name:    "value",
   780  	}
   781  
   782  	if bitfield.endBit != 0 {
   783  		// Make sure the value is in range with a mask.
   784  		valueToInsert = &ast.BinaryExpr{
   785  			X:     valueToInsert,
   786  			OpPos: bitfield.pos,
   787  			Op:    token.AND,
   788  			Y: &ast.BasicLit{
   789  				ValuePos: bitfield.pos,
   790  				Kind:     token.INT,
   791  				Value:    "0x" + strconv.FormatUint((uint64(1)<<uint64(bitfield.endBit-bitfield.startBit))-1, 16),
   792  			},
   793  		}
   794  		// Create a mask for the AND NOT operation.
   795  		mask := ((uint64(1) << uint64(bitfield.endBit-bitfield.startBit)) - 1) << uint64(bitfield.startBit)
   796  		// Zero the bits in the field that will soon be inserted.
   797  		field = &ast.BinaryExpr{
   798  			X:     field,
   799  			OpPos: bitfield.pos,
   800  			Op:    token.AND_NOT,
   801  			Y: &ast.BasicLit{
   802  				ValuePos: bitfield.pos,
   803  				Kind:     token.INT,
   804  				Value:    "0x" + strconv.FormatUint(mask, 16),
   805  			},
   806  		}
   807  	} else { // bitfield.endBit == 0
   808  		// We don't know exactly how many high bits should be zeroed. So we do
   809  		// something different: keep the low bits with a mask and OR the new
   810  		// value with it.
   811  		mask := (uint64(1) << uint64(bitfield.startBit)) - 1
   812  		// Extract the lower bits.
   813  		field = &ast.BinaryExpr{
   814  			X:     field,
   815  			OpPos: bitfield.pos,
   816  			Op:    token.AND,
   817  			Y: &ast.BasicLit{
   818  				ValuePos: bitfield.pos,
   819  				Kind:     token.INT,
   820  				Value:    "0x" + strconv.FormatUint(mask, 16),
   821  			},
   822  		}
   823  	}
   824  
   825  	// Bitwise OR with the new value (after the new value has been shifted).
   826  	field = &ast.BinaryExpr{
   827  		X:     field,
   828  		OpPos: bitfield.pos,
   829  		Op:    token.OR,
   830  		Y: &ast.BinaryExpr{
   831  			X:     valueToInsert,
   832  			OpPos: bitfield.pos,
   833  			Op:    token.SHL,
   834  			Y: &ast.BasicLit{
   835  				ValuePos: bitfield.pos,
   836  				Kind:     token.INT,
   837  				Value:    strconv.FormatInt(bitfield.startBit, 10),
   838  			},
   839  		},
   840  	}
   841  
   842  	// Create the setter function.
   843  	setter := &ast.FuncDecl{
   844  		Recv: &ast.FieldList{
   845  			Opening: bitfield.pos,
   846  			List: []*ast.Field{
   847  				{
   848  					Names: []*ast.Ident{
   849  						{
   850  							NamePos: bitfield.pos,
   851  							Name:    "s",
   852  							Obj: &ast.Object{
   853  								Kind: ast.Var,
   854  								Name: "s",
   855  								Decl: nil,
   856  							},
   857  						},
   858  					},
   859  					Type: &ast.StarExpr{
   860  						Star: bitfield.pos,
   861  						X: &ast.Ident{
   862  							NamePos: bitfield.pos,
   863  							Name:    typeName,
   864  							Obj:     nil,
   865  						},
   866  					},
   867  				},
   868  			},
   869  			Closing: bitfield.pos,
   870  		},
   871  		Name: &ast.Ident{
   872  			NamePos: bitfield.pos,
   873  			Name:    "set_bitfield_" + bitfield.name,
   874  		},
   875  		Type: &ast.FuncType{
   876  			Func: bitfield.pos,
   877  			Params: &ast.FieldList{
   878  				Opening: bitfield.pos,
   879  				List: []*ast.Field{
   880  					{
   881  						Names: []*ast.Ident{
   882  							{
   883  								NamePos: bitfield.pos,
   884  								Name:    "value",
   885  								Obj:     nil,
   886  							},
   887  						},
   888  						Type: bitfield.field.Type,
   889  					},
   890  				},
   891  				Closing: bitfield.pos,
   892  			},
   893  		},
   894  		Body: &ast.BlockStmt{
   895  			Lbrace: bitfield.pos,
   896  			List: []ast.Stmt{
   897  				&ast.AssignStmt{
   898  					Lhs: []ast.Expr{
   899  						&ast.SelectorExpr{
   900  							X: &ast.Ident{
   901  								NamePos: bitfield.pos,
   902  								Name:    "s",
   903  								Obj:     nil,
   904  							},
   905  							Sel: &ast.Ident{
   906  								NamePos: bitfield.pos,
   907  								Name:    bitfield.field.Names[0].Name,
   908  							},
   909  						},
   910  					},
   911  					TokPos: bitfield.pos,
   912  					Tok:    token.ASSIGN,
   913  					Rhs: []ast.Expr{
   914  						field,
   915  					},
   916  				},
   917  			},
   918  			Rbrace: bitfield.pos,
   919  		},
   920  	}
   921  	p.generated.Decls = append(p.generated.Decls, setter)
   922  }
   923  
   924  // isEquivalentAST returns whether the given two AST nodes are equivalent as far
   925  // as CGo is concerned. This is used to check that C types, globals, etc defined
   926  // in different CGo header snippets are actually the same type (and probably
   927  // even defined in the same header file, just in different translation units).
   928  func (p *cgoPackage) isEquivalentAST(a, b ast.Node) bool {
   929  	switch node := a.(type) {
   930  	case *ast.ArrayType:
   931  		b, ok := b.(*ast.ArrayType)
   932  		if !ok {
   933  			return false
   934  		}
   935  		if !p.isEquivalentAST(node.Len, b.Len) {
   936  			return false
   937  		}
   938  		return p.isEquivalentAST(node.Elt, b.Elt)
   939  	case *ast.BasicLit:
   940  		b, ok := b.(*ast.BasicLit)
   941  		if !ok {
   942  			return false
   943  		}
   944  		// Note: this comparison is not correct in general ("1e2" equals "100"),
   945  		// but is correct for its use in the cgo package.
   946  		return node.Value == b.Value
   947  	case *ast.CommentGroup:
   948  		b, ok := b.(*ast.CommentGroup)
   949  		if !ok {
   950  			return false
   951  		}
   952  		if len(node.List) != len(b.List) {
   953  			return false
   954  		}
   955  		for i, c := range node.List {
   956  			if c.Text != b.List[i].Text {
   957  				return false
   958  			}
   959  		}
   960  		return true
   961  	case *ast.FieldList:
   962  		b, ok := b.(*ast.FieldList)
   963  		if !ok {
   964  			return false
   965  		}
   966  		if node == nil || b == nil {
   967  			return node == b
   968  		}
   969  		if len(node.List) != len(b.List) {
   970  			return false
   971  		}
   972  		for i, f := range node.List {
   973  			if !p.isEquivalentAST(f, b.List[i]) {
   974  				return false
   975  			}
   976  		}
   977  		return true
   978  	case *ast.Field:
   979  		b, ok := b.(*ast.Field)
   980  		if !ok {
   981  			return false
   982  		}
   983  		if !p.isEquivalentAST(node.Type, b.Type) {
   984  			return false
   985  		}
   986  		if len(node.Names) != len(b.Names) {
   987  			return false
   988  		}
   989  		for i, name := range node.Names {
   990  			if name.Name != b.Names[i].Name {
   991  				return false
   992  			}
   993  		}
   994  		return true
   995  	case *ast.FuncDecl:
   996  		b, ok := b.(*ast.FuncDecl)
   997  		if !ok {
   998  			return false
   999  		}
  1000  		if node.Name.Name != b.Name.Name {
  1001  			return false
  1002  		}
  1003  		if node.Doc != b.Doc {
  1004  			if !p.isEquivalentAST(node.Doc, b.Doc) {
  1005  				return false
  1006  			}
  1007  		}
  1008  		if node.Recv != b.Recv {
  1009  			if !p.isEquivalentAST(node.Recv, b.Recv) {
  1010  				return false
  1011  			}
  1012  		}
  1013  		if !p.isEquivalentAST(node.Type.Params, b.Type.Params) {
  1014  			return false
  1015  		}
  1016  		return p.isEquivalentAST(node.Type.Results, b.Type.Results)
  1017  	case *ast.GenDecl:
  1018  		b, ok := b.(*ast.GenDecl)
  1019  		if !ok {
  1020  			return false
  1021  		}
  1022  		if node.Doc != b.Doc {
  1023  			if !p.isEquivalentAST(node.Doc, b.Doc) {
  1024  				return false
  1025  			}
  1026  		}
  1027  		if len(node.Specs) != len(b.Specs) {
  1028  			return false
  1029  		}
  1030  		for i, s := range node.Specs {
  1031  			if !p.isEquivalentAST(s, b.Specs[i]) {
  1032  				return false
  1033  			}
  1034  		}
  1035  		return true
  1036  	case *ast.Ident:
  1037  		b, ok := b.(*ast.Ident)
  1038  		if !ok {
  1039  			return false
  1040  		}
  1041  		return node.Name == b.Name
  1042  	case *ast.SelectorExpr:
  1043  		b, ok := b.(*ast.SelectorExpr)
  1044  		if !ok {
  1045  			return false
  1046  		}
  1047  		if !p.isEquivalentAST(node.Sel, b.Sel) {
  1048  			return false
  1049  		}
  1050  		return p.isEquivalentAST(node.X, b.X)
  1051  	case *ast.StarExpr:
  1052  		b, ok := b.(*ast.StarExpr)
  1053  		if !ok {
  1054  			return false
  1055  		}
  1056  		return p.isEquivalentAST(node.X, b.X)
  1057  	case *ast.StructType:
  1058  		b, ok := b.(*ast.StructType)
  1059  		if !ok {
  1060  			return false
  1061  		}
  1062  		return p.isEquivalentAST(node.Fields, b.Fields)
  1063  	case *ast.TypeSpec:
  1064  		b, ok := b.(*ast.TypeSpec)
  1065  		if !ok {
  1066  			return false
  1067  		}
  1068  		if node.Name.Name != b.Name.Name {
  1069  			return false
  1070  		}
  1071  		if node.Assign.IsValid() != b.Assign.IsValid() {
  1072  			return false
  1073  		}
  1074  		return p.isEquivalentAST(node.Type, b.Type)
  1075  	case *ast.ValueSpec:
  1076  		b, ok := b.(*ast.ValueSpec)
  1077  		if !ok {
  1078  			return false
  1079  		}
  1080  		if len(node.Names) != len(b.Names) {
  1081  			return false
  1082  		}
  1083  		for i, name := range node.Names {
  1084  			if name.Name != b.Names[i].Name {
  1085  				return false
  1086  			}
  1087  		}
  1088  		if node.Type != b.Type && !p.isEquivalentAST(node.Type, b.Type) {
  1089  			return false
  1090  		}
  1091  		if len(node.Values) != len(b.Values) {
  1092  			return false
  1093  		}
  1094  		for i, value := range node.Values {
  1095  			if !p.isEquivalentAST(value, b.Values[i]) {
  1096  				return false
  1097  			}
  1098  		}
  1099  		return true
  1100  	case nil:
  1101  		p.addError(token.NoPos, "internal error: AST node is nil")
  1102  		return true
  1103  	default:
  1104  		p.addError(a.Pos(), fmt.Sprintf("internal error: unknown AST node: %T", a))
  1105  		return true
  1106  	}
  1107  }
  1108  
  1109  // getPos returns node.Pos(), and tries to obtain a closely related position if
  1110  // that fails.
  1111  func getPos(node ast.Node) token.Pos {
  1112  	pos := node.Pos()
  1113  	if pos.IsValid() {
  1114  		return pos
  1115  	}
  1116  	if decl, ok := node.(*ast.GenDecl); ok {
  1117  		// *ast.GenDecl often doesn't have TokPos defined, so look at the first
  1118  		// spec.
  1119  		return getPos(decl.Specs[0])
  1120  	}
  1121  	return token.NoPos
  1122  }
  1123  
  1124  // getUnnamedDeclName creates a name (with the given prefix) for the given C
  1125  // declaration. This is used for structs, unions, and enums that are often
  1126  // defined without a name and used in a typedef.
  1127  func (p *cgoPackage) getUnnamedDeclName(prefix string, itf interface{}) string {
  1128  	if name, ok := p.anonDecls[itf]; ok {
  1129  		return name
  1130  	}
  1131  	name := prefix + strconv.Itoa(len(p.anonDecls))
  1132  	p.anonDecls[itf] = name
  1133  	return name
  1134  }
  1135  
  1136  // getASTDeclName will declare the given C AST node (if not already defined) and
  1137  // will return its name, in the form of C.foo.
  1138  func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) string {
  1139  	// Some types are defined in stdint.h and map directly to a particular Go
  1140  	// type.
  1141  	if alias := cgoAliases["C."+name]; alias != "" {
  1142  		return alias
  1143  	}
  1144  	node := f.getASTDeclNode(name, found, iscall)
  1145  	if node, ok := node.(*ast.FuncDecl); ok {
  1146  		if !iscall {
  1147  			return node.Name.Name + "$funcaddr"
  1148  		}
  1149  		return node.Name.Name
  1150  	}
  1151  	return "C." + name
  1152  }
  1153  
  1154  // getASTDeclNode will declare the given C AST node (if not already defined) and
  1155  // returns it.
  1156  func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) ast.Node {
  1157  	if node, ok := f.defined[name]; ok {
  1158  		// Declaration was found in the current file, so return it immediately.
  1159  		return node
  1160  	}
  1161  
  1162  	if node, ok := f.definedGlobally[name]; ok {
  1163  		// Declaration was previously created, but not for the current file. It
  1164  		// may be different (because it comes from a different CGo snippet), so
  1165  		// we need to check whether the AST for this definition is equivalent.
  1166  		f.defined[name] = nil
  1167  		newNode, _ := f.createASTNode(name, found)
  1168  		if !f.isEquivalentAST(node, newNode) {
  1169  			// It's not. Return a nice error with both locations.
  1170  			// Original cgo reports an error like
  1171  			//   cgo: inconsistent definitions for C.myint
  1172  			// which is far less helpful.
  1173  			f.addError(getPos(node), name+" defined previously at "+f.fset.Position(getPos(newNode)).String()+" with a different type")
  1174  		}
  1175  		f.defined[name] = node
  1176  		return node
  1177  	}
  1178  
  1179  	// The declaration has no AST node. Create it now.
  1180  	f.defined[name] = nil
  1181  	node, extra := f.createASTNode(name, found)
  1182  	f.defined[name] = node
  1183  	switch node := node.(type) {
  1184  	case *ast.FuncDecl:
  1185  		if strings.HasPrefix(node.Doc.List[0].Text, "//export _Cgo_static_") {
  1186  			// Static function. Only accessible in the current Go file.
  1187  			globalName := strings.TrimPrefix(node.Doc.List[0].Text, "//export ")
  1188  			// Make an alias. Normally this is done using the alias function
  1189  			// attribute, but MacOS for some reason doesn't support this (even
  1190  			// though the linker has support for aliases in the form of N_INDR).
  1191  			// Therefore, create an actual function for MacOS.
  1192  			var params []string
  1193  			for _, param := range node.Type.Params.List {
  1194  				params = append(params, param.Names[0].Name)
  1195  			}
  1196  			callInst := fmt.Sprintf("%s(%s);", name, strings.Join(params, ", "))
  1197  			if node.Type.Results != nil {
  1198  				callInst = "return " + callInst
  1199  			}
  1200  			aliasDeclaration := fmt.Sprintf(`
  1201  #ifdef __APPLE__
  1202  %s {
  1203  	%s
  1204  }
  1205  #else
  1206  extern __typeof(%s) %s __attribute__((alias(%#v)));
  1207  #endif
  1208  `, extra.(string), callInst, name, globalName, name)
  1209  			f.cgoHeaders[f.index] += "\n\n" + aliasDeclaration
  1210  		} else {
  1211  			// Regular (non-static) function.
  1212  			f.definedGlobally[name] = node
  1213  		}
  1214  		f.generated.Decls = append(f.generated.Decls, node)
  1215  		// Also add a declaration like the following:
  1216  		//   var C.foo$funcaddr unsafe.Pointer
  1217  		f.generated.Decls = append(f.generated.Decls, &ast.GenDecl{
  1218  			Tok: token.VAR,
  1219  			Specs: []ast.Spec{
  1220  				&ast.ValueSpec{
  1221  					Names: []*ast.Ident{{Name: node.Name.Name + "$funcaddr"}},
  1222  					Type: &ast.SelectorExpr{
  1223  						X:   &ast.Ident{Name: "unsafe"},
  1224  						Sel: &ast.Ident{Name: "Pointer"},
  1225  					},
  1226  				},
  1227  			},
  1228  		})
  1229  	case *ast.GenDecl:
  1230  		f.definedGlobally[name] = node
  1231  		f.generated.Decls = append(f.generated.Decls, node)
  1232  	case *ast.TypeSpec:
  1233  		f.definedGlobally[name] = node
  1234  		f.generated.Decls = append(f.generated.Decls, &ast.GenDecl{
  1235  			Tok:   token.TYPE,
  1236  			Specs: []ast.Spec{node},
  1237  		})
  1238  	case nil:
  1239  		// Node may be nil in case of an error. In that case, just don't add it
  1240  		// as a declaration.
  1241  	default:
  1242  		panic("unexpected AST node")
  1243  	}
  1244  
  1245  	// If this is a struct or union it may need bitfields or union accessor
  1246  	// methods.
  1247  	switch elaboratedType := extra.(type) {
  1248  	case *elaboratedTypeInfo:
  1249  		// Add struct bitfields.
  1250  		for _, bitfield := range elaboratedType.bitfields {
  1251  			f.createBitfieldGetter(bitfield, "C."+name)
  1252  			f.createBitfieldSetter(bitfield, "C."+name)
  1253  		}
  1254  		if elaboratedType.unionSize != 0 {
  1255  			// Create union getters/setters.
  1256  			for _, field := range elaboratedType.typeExpr.Fields.List {
  1257  				if len(field.Names) != 1 {
  1258  					f.addError(elaboratedType.pos, fmt.Sprintf("union must have field with a single name, it has %d names", len(field.Names)))
  1259  					continue
  1260  				}
  1261  				f.createUnionAccessor(field, "C."+name)
  1262  			}
  1263  		}
  1264  	}
  1265  
  1266  	return node
  1267  }
  1268  
  1269  // walker replaces all "C".<something> expressions to literal "C.<something>"
  1270  // expressions. Such expressions are impossible to write in Go (a dot cannot be
  1271  // used in the middle of a name) so in practice all C identifiers live in a
  1272  // separate namespace (no _Cgo_ hacks like in gc).
  1273  func (f *cgoFile) walker(cursor *astutil.Cursor, names map[string]clangCursor) bool {
  1274  	switch node := cursor.Node().(type) {
  1275  	case *ast.CallExpr:
  1276  		fun, ok := node.Fun.(*ast.SelectorExpr)
  1277  		if !ok {
  1278  			return true
  1279  		}
  1280  		x, ok := fun.X.(*ast.Ident)
  1281  		if !ok {
  1282  			return true
  1283  		}
  1284  		if found, ok := names[fun.Sel.Name]; ok && x.Name == "C" {
  1285  			node.Fun = &ast.Ident{
  1286  				NamePos: x.NamePos,
  1287  				Name:    f.getASTDeclName(fun.Sel.Name, found, true),
  1288  			}
  1289  		}
  1290  	case *ast.SelectorExpr:
  1291  		x, ok := node.X.(*ast.Ident)
  1292  		if !ok {
  1293  			return true
  1294  		}
  1295  		if x.Name == "C" {
  1296  			name := "C." + node.Sel.Name
  1297  			if found, ok := names[node.Sel.Name]; ok {
  1298  				name = f.getASTDeclName(node.Sel.Name, found, false)
  1299  			}
  1300  			cursor.Replace(&ast.Ident{
  1301  				NamePos: x.NamePos,
  1302  				Name:    name,
  1303  			})
  1304  		}
  1305  	}
  1306  	return true
  1307  }
  1308  
  1309  // renameFieldKeywords renames all reserved words in Go to some other field name
  1310  // with a "_" prefix. For example, it renames `type` to `_type`.
  1311  //
  1312  // See: https://golang.org/cmd/cgo/#hdr-Go_references_to_C
  1313  func renameFieldKeywords(fieldList *ast.FieldList) {
  1314  	renameFieldName(fieldList, "type")
  1315  }
  1316  
  1317  // renameFieldName renames a given field name to a name with a "_" prepended. It
  1318  // makes sure to do the same thing for any field sharing the same name.
  1319  func renameFieldName(fieldList *ast.FieldList, name string) {
  1320  	var ident *ast.Ident
  1321  	for _, f := range fieldList.List {
  1322  		for _, n := range f.Names {
  1323  			if n.Name == name {
  1324  				ident = n
  1325  			}
  1326  		}
  1327  	}
  1328  	if ident == nil {
  1329  		return
  1330  	}
  1331  	renameFieldName(fieldList, "_"+name)
  1332  	ident.Name = "_" + ident.Name
  1333  }