...
Run Format

Source file src/cmd/cgo/godefs.go

Documentation: cmd/cgo

  // Copyright 2011 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  package main
  
  import (
  	"bytes"
  	"fmt"
  	"go/ast"
  	"go/printer"
  	"go/token"
  	"os"
  	"path/filepath"
  	"strings"
  )
  
  // godefs returns the output for -godefs mode.
  func (p *Package) godefs(f *File, srcfile string) string {
  	var buf bytes.Buffer
  
  	fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n")
  	fmt.Fprintf(&buf, "// %s %s\n", filepath.Base(os.Args[0]), strings.Join(os.Args[1:], " "))
  	fmt.Fprintf(&buf, "\n")
  
  	override := make(map[string]string)
  
  	// Allow source file to specify override mappings.
  	// For example, the socket data structures refer
  	// to in_addr and in_addr6 structs but we want to be
  	// able to treat them as byte arrays, so the godefs
  	// inputs in package syscall say
  	//
  	//	// +godefs map struct_in_addr [4]byte
  	//	// +godefs map struct_in_addr6 [16]byte
  	//
  	for _, g := range f.Comments {
  		for _, c := range g.List {
  			i := strings.Index(c.Text, "+godefs map")
  			if i < 0 {
  				continue
  			}
  			s := strings.TrimSpace(c.Text[i+len("+godefs map"):])
  			i = strings.Index(s, " ")
  			if i < 0 {
  				fmt.Fprintf(os.Stderr, "invalid +godefs map comment: %s\n", c.Text)
  				continue
  			}
  			override["_Ctype_"+strings.TrimSpace(s[:i])] = strings.TrimSpace(s[i:])
  		}
  	}
  	for _, n := range f.Name {
  		if s := override[n.Go]; s != "" {
  			override[n.Mangle] = s
  		}
  	}
  
  	// Otherwise, if the source file says type T C.whatever,
  	// use "T" as the mangling of C.whatever,
  	// except in the definition (handled at end of function).
  	refName := make(map[*ast.Expr]*Name)
  	for _, r := range f.Ref {
  		refName[r.Expr] = r.Name
  	}
  	for _, d := range f.AST.Decls {
  		d, ok := d.(*ast.GenDecl)
  		if !ok || d.Tok != token.TYPE {
  			continue
  		}
  		for _, s := range d.Specs {
  			s := s.(*ast.TypeSpec)
  			n := refName[&s.Type]
  			if n != nil && n.Mangle != "" {
  				override[n.Mangle] = s.Name.Name
  			}
  		}
  	}
  
  	// Extend overrides using typedefs:
  	// If we know that C.xxx should format as T
  	// and xxx is a typedef for yyy, make C.yyy format as T.
  	for typ, def := range typedef {
  		if new := override[typ]; new != "" {
  			if id, ok := def.Go.(*ast.Ident); ok {
  				override[id.Name] = new
  			}
  		}
  	}
  
  	// Apply overrides.
  	for old, new := range override {
  		if id := goIdent[old]; id != nil {
  			id.Name = new
  		}
  	}
  
  	// Any names still using the _C syntax are not going to compile,
  	// although in general we don't know whether they all made it
  	// into the file, so we can't warn here.
  	//
  	// The most common case is union types, which begin with
  	// _Ctype_union and for which typedef[name] is a Go byte
  	// array of the appropriate size (such as [4]byte).
  	// Substitute those union types with byte arrays.
  	for name, id := range goIdent {
  		if id.Name == name && strings.Contains(name, "_Ctype_union") {
  			if def := typedef[name]; def != nil {
  				id.Name = gofmt(def)
  			}
  		}
  	}
  
  	conf.Fprint(&buf, fset, f.AST)
  
  	return buf.String()
  }
  
  var gofmtBuf bytes.Buffer
  
  // gofmt returns the gofmt-formatted string for an AST node.
  func gofmt(n interface{}) string {
  	gofmtBuf.Reset()
  	err := printer.Fprint(&gofmtBuf, fset, n)
  	if err != nil {
  		return "<" + err.Error() + ">"
  	}
  	return gofmtBuf.String()
  }
  

View as plain text