aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/fix/typecheck.go
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2018-01-12 10:11:01 -0800
committerKeith Randall <khr@golang.org>2018-01-17 06:44:25 +0000
commit2dc025e4e171ee99d31d11efe5ccf53794e89020 (patch)
tree61e38e15ffad4dda98aba09c7034077246beb655 /src/cmd/fix/typecheck.go
parentd162a297ed216fb02ebe409ace2387c3a656de66 (diff)
downloadgo-2dc025e4e171ee99d31d11efe5ccf53794e89020.tar.xz
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>
Diffstat (limited to 'src/cmd/fix/typecheck.go')
-rw-r--r--src/cmd/fix/typecheck.go73
1 files changed, 73 insertions, 0 deletions
diff --git a/src/cmd/fix/typecheck.go b/src/cmd/fix/typecheck.go
index 58d915869d..a52a54202d 100644
--- a/src/cmd/fix/typecheck.go
+++ b/src/cmd/fix/typecheck.go
@@ -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