mirror of https://github.com/golang/go.git
cmd/fix: extend typechecker to use cgo types
If a file uses cgo, incorporate the types generated by running cgo. Update #23091 Change-Id: I10958fa7fd6027c2c96a9fd8a9658de35439719f Reviewed-on: https://go-review.googlesource.com/87616 Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
d162a297ed
commit
2dc025e4e1
|
|
@ -30,17 +30,19 @@ var cftypeFix = fix{
|
|||
// and similar for other *Ref types.
|
||||
// This fix finds nils initializing these types and replaces the nils with 0s.
|
||||
func cftypefix(f *ast.File) bool {
|
||||
return typefix(f, func(s string) bool {
|
||||
return strings.HasPrefix(s, "C.") && strings.HasSuffix(s, "Ref")
|
||||
var tc TypeConfig
|
||||
return typefix(f, &tc, func(s string) bool {
|
||||
return strings.HasPrefix(s, "C.") && strings.HasSuffix(s, "Ref") &&
|
||||
(s == "C.CFTypeRef" || tc.External[s[:len(s)-3]+"GetTypeID"] == "func() C.CFTypeID")
|
||||
})
|
||||
}
|
||||
|
||||
// typefix replaces nil with 0 for all nils whose type, when passed to badType, returns true.
|
||||
func typefix(f *ast.File, badType func(string) bool) bool {
|
||||
func typefix(f *ast.File, tc *TypeConfig, badType func(string) bool) bool {
|
||||
if !imports(f, "C") {
|
||||
return false
|
||||
}
|
||||
typeof, _ := typecheck(&TypeConfig{}, f)
|
||||
typeof, _ := typecheck(tc, f)
|
||||
|
||||
// step 1: Find all the nils with the offending types.
|
||||
// Compute their replacement.
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ var jniFix = fix{
|
|||
// and similar for subtypes of jobject.
|
||||
// This fix finds nils initializing these types and replaces the nils with 0s.
|
||||
func jnifix(f *ast.File) bool {
|
||||
return typefix(f, func(s string) bool {
|
||||
var tc TypeConfig
|
||||
return typefix(f, &tc, func(s string) bool {
|
||||
switch s {
|
||||
case "C.jobject":
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -7,9 +7,14 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
@ -74,6 +79,11 @@ type TypeConfig struct {
|
|||
Type map[string]*Type
|
||||
Var map[string]string
|
||||
Func map[string]string
|
||||
|
||||
// External maps from a name to its type.
|
||||
// It provides additional typings not present in the Go source itself.
|
||||
// For now, the only additional typings are those generated by cgo.
|
||||
External map[string]string
|
||||
}
|
||||
|
||||
// typeof returns the type of the given name, which may be of
|
||||
|
|
@ -140,6 +150,66 @@ func typecheck(cfg *TypeConfig, f *ast.File) (typeof map[interface{}]string, ass
|
|||
*cfg1 = *cfg // make copy so we can add locally
|
||||
copied := false
|
||||
|
||||
// If we import "C", add types of cgo objects.
|
||||
cfg.External = map[string]string{}
|
||||
if imports(f, "C") {
|
||||
// Run cgo on gofmtFile(f)
|
||||
// Parse, extract decls from _cgo_gotypes.go
|
||||
// Map _Ctype_* types to C.* types.
|
||||
err := func() error {
|
||||
txt, err := gofmtFile(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dir, err := ioutil.TempDir(os.TempDir(), "fix_cgo_typecheck")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(dir)
|
||||
err = ioutil.WriteFile(filepath.Join(dir, "in.go"), txt, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), "tool", "cgo", "-objdir", dir, "-srcdir", dir, "in.go")
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out, err := ioutil.ReadFile(filepath.Join(dir, "_cgo_gotypes.go"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cgo, err := parser.ParseFile(token.NewFileSet(), "cgo.go", out, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, decl := range cgo.Decls {
|
||||
fn, ok := decl.(*ast.FuncDecl)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(fn.Name.Name, "_Cfunc_") {
|
||||
var params, results []string
|
||||
for _, p := range fn.Type.Params.List {
|
||||
t := gofmt(p.Type)
|
||||
t = strings.Replace(t, "_Ctype_", "C.", -1)
|
||||
params = append(params, t)
|
||||
}
|
||||
for _, r := range fn.Type.Results.List {
|
||||
t := gofmt(r.Type)
|
||||
t = strings.Replace(t, "_Ctype_", "C.", -1)
|
||||
results = append(results, t)
|
||||
}
|
||||
cfg.External["C."+fn.Name.Name[7:]] = joinFunc(params, results)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
if err != nil {
|
||||
fmt.Printf("warning: no cgo types: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// gather function declarations
|
||||
for _, decl := range f.Decls {
|
||||
fn, ok := decl.(*ast.FuncDecl)
|
||||
|
|
@ -434,6 +504,9 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
|
|||
}
|
||||
// Otherwise, use type of function to determine arguments.
|
||||
t := typeof[n.Fun]
|
||||
if t == "" {
|
||||
t = cfg.External[gofmt(n.Fun)]
|
||||
}
|
||||
in, out := splitFunc(t)
|
||||
if in == nil && out == nil {
|
||||
return
|
||||
|
|
|
|||
Loading…
Reference in New Issue