func encodeType(t types.Type) Type { t = t.Underlying() switch t.(type) { case *types.Basic: b := t.(*types.Basic) untyped := (b.Info() & types.IsUntyped) != 0 return NewBasic(basicKindString(b), untyped) case *types.Pointer: p := t.(*types.Pointer) pt := encodeType(p.Elem()) return NewPointer(pt) case *types.Array: a := t.(*types.Array) at := encodeType(a.Elem()) return NewArray(at, a.Len()) case *types.Slice: s := t.(*types.Slice) st := encodeType(s.Elem()) return NewSlice(st) case *types.Signature: sig := t.(*types.Signature) v := sig.Recv() var vt *Type if v != nil { t := encodeType(v.Type()) vt = &t } return NewSignature( sig.Variadic(), vt, tupleToSlice(sig.Params()), tupleToSlice(sig.Results())) case *types.Named: n := t.(*types.Named) return NewNamed( n.Obj().Pkg().Name(), n.Obj().Name(), n.Underlying()) case *types.Interface: i := t.(*types.Interface) if i.Empty() { return NewInterface() } else { return NewUnsupported("Interfaces") } case *types.Tuple: return NewUnsupported("Tuples") case *types.Map: return NewUnsupported("Maps") case *types.Chan: return NewUnsupported("Channels") case *types.Struct: return NewUnsupported("Structs") default: return NewUnsupported(t.String()) } }
// indirect(typ) assumes that typ is a pointer type, // or named alias thereof, and returns its base type. // Panic ensures if it is not a pointer. // func indirectType(ptr types.Type) types.Type { if v, ok := underlyingType(ptr).(*types.Pointer); ok { return v.Base } // When debugging it is convenient to comment out this line // and let it continue to print the (illegal) SSA form. panic("indirect() of non-pointer type: " + ptr.String()) return nil }
func makeImplementsType(T types.Type, fset *token.FileSet) serial.ImplementsType { var pos token.Pos if nt, ok := deref(T).(*types.Named); ok { // implementsResult.t may be non-named pos = nt.Obj().Pos() } return serial.ImplementsType{ Name: T.String(), Pos: fset.Position(pos).String(), Kind: typeKind(T), } }
func newVar(p *Package, typ types.Type, objname, name, doc string) *Var { sym := p.syms.symtype(typ) if sym == nil { panic(fmt.Errorf("could not find symbol for type [%s]!", typ.String())) } return &Var{ pkg: p, sym: sym, id: p.Name() + "_" + objname, doc: doc, name: name, } }
func (f *File) validResultType(typ types.Type) *Error { switch typ.(type) { default: name := typ.String() if named, ok := typ.(*types.Named); ok { name = named.Obj().Name() } return &Error{errors.New(fmt.Sprint("Invalid result type:", name)), 0} case *types.Basic: typ := typ.(*types.Basic) switch typ.Kind() { default: return &Error{errors.New(fmt.Sprint("Invalid basic type for result type :", typ.Info())), 0} case types.Bool: return nil case types.Int: return nil case types.Int8: return nil case types.Int16: return nil case types.Int32: return nil case types.Int64: return nil case types.Uint: return nil case types.Uint8: return nil case types.Uint16: return nil case types.Uint32: return nil case types.Uint64: return nil case types.Float32: return nil case types.Float64: return nil } } }
// writeSignature writes to w the signature sig in declaration syntax. // Derived from types.Signature.String(). // func writeSignature(w io.Writer, name string, sig *types.Signature, params []*Parameter) { io.WriteString(w, "func ") if sig.Recv != nil { io.WriteString(w, "(") if n := params[0].Name(); n != "" { io.WriteString(w, n) io.WriteString(w, " ") } io.WriteString(w, params[0].Type().String()) io.WriteString(w, ") ") params = params[1:] } io.WriteString(w, name) io.WriteString(w, "(") for i, v := range params { if i > 0 { io.WriteString(w, ", ") } io.WriteString(w, v.Name()) io.WriteString(w, " ") if sig.IsVariadic && i == len(params)-1 { io.WriteString(w, "...") io.WriteString(w, underlyingType(v.Type()).(*types.Slice).Elt.String()) } else { io.WriteString(w, v.Type().String()) } } io.WriteString(w, ")") if res := sig.Results; res != nil { io.WriteString(w, " ") var t types.Type if len(res) == 1 && res[0].Name == "" { t = res[0].Type } else { t = &types.Result{Values: res} } io.WriteString(w, t.String()) } }
// typeString returns a string representation of n. func typeString(typ types.Type) string { return filepath.ToSlash(typ.String()) }
// appendComponentsRecursive implements componentsOfType. // Recursion is required to correct handle structs and arrays, // which can contain arbitrary other types. func appendComponentsRecursive(arch *asmArch, t types.Type, cc []component, suffix string, off int) []component { s := t.String() size := int(arch.sizes.Sizeof(t)) kind := asmKindForType(t, size) cc = append(cc, newComponent(suffix, kind, s, off, size, suffix)) switch kind { case 8: if arch.ptrSize() == 4 { w1, w2 := "lo", "hi" if arch.bigEndian { w1, w2 = w2, w1 } cc = append(cc, newComponent(suffix+"_"+w1, 4, "half "+s, off, 4, suffix)) cc = append(cc, newComponent(suffix+"_"+w2, 4, "half "+s, off+4, 4, suffix)) } case asmEmptyInterface: cc = append(cc, newComponent(suffix+"_type", asmKind(arch.ptrSize()), "interface type", off, arch.ptrSize(), suffix)) cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize()), "interface data", off+arch.ptrSize(), arch.ptrSize(), suffix)) case asmInterface: cc = append(cc, newComponent(suffix+"_itable", asmKind(arch.ptrSize()), "interface itable", off, arch.ptrSize(), suffix)) cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize()), "interface data", off+arch.ptrSize(), arch.ptrSize(), suffix)) case asmSlice: cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize()), "slice base", off, arch.ptrSize(), suffix)) cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize()), "slice len", off+arch.ptrSize(), arch.intSize(), suffix)) cc = append(cc, newComponent(suffix+"_cap", asmKind(arch.intSize()), "slice cap", off+arch.ptrSize()+arch.intSize(), arch.intSize(), suffix)) case asmString: cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize()), "string base", off, arch.ptrSize(), suffix)) cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize()), "string len", off+arch.ptrSize(), arch.intSize(), suffix)) case asmComplex: fsize := size / 2 cc = append(cc, newComponent(suffix+"_real", asmKind(fsize), fmt.Sprintf("real(complex%d)", size*8), off, fsize, suffix)) cc = append(cc, newComponent(suffix+"_imag", asmKind(fsize), fmt.Sprintf("imag(complex%d)", size*8), off+fsize, fsize, suffix)) case asmStruct: tu := t.Underlying().(*types.Struct) fields := make([]*types.Var, tu.NumFields()) for i := 0; i < tu.NumFields(); i++ { fields[i] = tu.Field(i) } offsets := arch.sizes.Offsetsof(fields) for i, f := range fields { cc = appendComponentsRecursive(arch, f.Type(), cc, suffix+"_"+f.Name(), off+int(offsets[i])) } case asmArray: tu := t.Underlying().(*types.Array) elem := tu.Elem() // Calculate offset of each element array. fields := []*types.Var{ types.NewVar(token.NoPos, nil, "fake0", elem), types.NewVar(token.NoPos, nil, "fake1", elem), } offsets := arch.sizes.Offsetsof(fields) elemoff := int(offsets[1]) for i := 0; i < int(tu.Len()); i++ { cc = appendComponentsRecursive(arch, elem, cc, suffix+"_"+strconv.Itoa(i), i*elemoff) } } return cc }
func encodeType(t types.Type) Type { // First see if it's a Named type. If so, wrap in Named and recurse with the // underlying type. if n, isNamed := t.(*types.Named); isNamed { // When n.Obj().Pkg() is nil the Named type is defined in the universe. We // represent that with an empty package name slice. var pkgSegments []string = []string{} if n.Obj().Pkg() != nil { pkgSegments = strings.Split(n.Obj().Pkg().Path(), "/") } return NewNamed( pkgSegments, n.Obj().Name(), encodeType(n.Underlying())) } switch t.Underlying().(type) { case *types.Basic: b := t.(*types.Basic) untyped := (b.Info() & types.IsUntyped) != 0 return NewBasic(basicKindString(b), untyped) case *types.Pointer: p := t.(*types.Pointer) pt := encodeType(p.Elem()) return NewPointer(pt) case *types.Array: a := t.(*types.Array) at := encodeType(a.Elem()) return NewArray(at, a.Len()) case *types.Slice: s := t.(*types.Slice) st := encodeType(s.Elem()) return NewSlice(st) case *types.Signature: sig := t.(*types.Signature) v := sig.Recv() var vt *Type if v != nil { t := encodeType(v.Type()) vt = &t } return NewSignature( sig.Variadic(), vt, tupleToSlice(sig.Params()), tupleToSlice(sig.Results())) case *types.Interface: i := t.(*types.Interface) if i.Empty() { return NewInterface() } else { return NewUnsupported("Interfaces") } case *types.Struct: s := t.(*types.Struct) fields := []StructField{} for i := 0; i < s.NumFields(); i++ { f := s.Field(i) fields = append(fields, NewStructField(f.Name(), encodeType(f.Type()))) } return NewStruct(fields) case *types.Tuple: return NewUnsupported("Tuples") case *types.Map: return NewUnsupported("Maps") case *types.Chan: return NewUnsupported("Channels") default: return NewUnsupported(t.String()) } }
// walkType adds the type, and any necessary child types. func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *types.Type { // Most of the cases are underlying types of the named type. name := tcNameToName(in.String()) if useName != nil { name = *useName } switch t := in.(type) { case *tc.Struct: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Struct for i := 0; i < t.NumFields(); i++ { f := t.Field(i) m := types.Member{ Name: f.Name(), Embedded: f.Anonymous(), Tags: t.Tag(i), Type: b.walkType(u, nil, f.Type()), CommentLines: splitLines(b.priorCommentLines(f.Pos(), 1).Text()), } out.Members = append(out.Members, m) } return out case *tc.Map: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Map out.Elem = b.walkType(u, nil, t.Elem()) out.Key = b.walkType(u, nil, t.Key()) return out case *tc.Pointer: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Pointer out.Elem = b.walkType(u, nil, t.Elem()) return out case *tc.Slice: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Slice out.Elem = b.walkType(u, nil, t.Elem()) return out case *tc.Array: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Array out.Elem = b.walkType(u, nil, t.Elem()) // TODO: need to store array length, otherwise raw type name // cannot be properly written. return out case *tc.Chan: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Chan out.Elem = b.walkType(u, nil, t.Elem()) // TODO: need to store direction, otherwise raw type name // cannot be properly written. return out case *tc.Basic: out := u.Type(types.Name{ Package: "", Name: t.Name(), }) if out.Kind != types.Unknown { return out } out.Kind = types.Unsupported return out case *tc.Signature: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Func out.Signature = b.convertSignature(u, t) return out case *tc.Interface: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Interface t.Complete() for i := 0; i < t.NumMethods(); i++ { if out.Methods == nil { out.Methods = map[string]*types.Type{} } out.Methods[t.Method(i).Name()] = b.walkType(u, nil, t.Method(i).Type()) } return out case *tc.Named: switch t.Underlying().(type) { case *tc.Named, *tc.Basic, *tc.Map, *tc.Slice: name := tcNameToName(t.String()) out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Alias out.Underlying = b.walkType(u, nil, t.Underlying()) return out default: // tc package makes everything "named" with an // underlying anonymous type--we remove that annoying // "feature" for users. This flattens those types // together. name := tcNameToName(t.String()) if out := u.Type(name); out.Kind != types.Unknown { return out // short circuit if we've already made this. } out := b.walkType(u, &name, t.Underlying()) if len(out.Methods) == 0 { // If the underlying type didn't already add // methods, add them. (Interface types will // have already added methods.) for i := 0; i < t.NumMethods(); i++ { if out.Methods == nil { out.Methods = map[string]*types.Type{} } out.Methods[t.Method(i).Name()] = b.walkType(u, nil, t.Method(i).Type()) } } return out } default: out := u.Type(name) if out.Kind != types.Unknown { return out } out.Kind = types.Unsupported glog.Warningf("Making unsupported type entry %q for: %#v\n", out, t) return out } }
//Extract rpc services and methods by analysing type definitions func (g *Generator) Extract() error { rpcmethods := map[string]*RPCMethod{} for _, obj := range g.pkg.defs { if obj == nil { continue } DEFSWITCH: switch t := obj.Type().(type) { //as per "net/rpc" are we looking for methods with the following: // [x] the fn is a method (has receiver) // [x] the method's type is exported. // [x] the method is exported. // [x] the method has two arguments... // [x] both exported (or builtin) types. // [x] the method's second argument is a pointer. // [x] the method has return type error. case *types.Signature: //needs to be a method (have a receiver) and be exported if t.Recv() == nil || !obj.Exported() { break } //receiver must be named and exported var recvt types.Type if recvpt, ok := t.Recv().Type().(*types.Pointer); ok { recvt = recvpt.Elem() } else { recvt = t.Recv().Type() } recv, ok := recvt.(*types.Named) if ok { if !recv.Obj().Exported() { break } } //method must have two params if t.Params().Len() != 2 { break } //all param types must be exported or builtin for i := 0; i < t.Params().Len(); i++ { var paramt types.Type if parampt, ok := t.Params().At(i).Type().(*types.Pointer); ok { paramt = parampt.Elem() } else { //second arg must be a pointer if i == 1 { break DEFSWITCH } paramt = t.Params().At(i).Type() } //if param type is Named, it must be exported, else it must be buildin if paramnamedt, ok := paramt.(*types.Named); ok { if !paramnamedt.Obj().Exported() { break DEFSWITCH } } else if strings.Contains(paramt.String(), ".") { break DEFSWITCH } } //must have one result: error if t.Results().Len() != 1 || t.Results().At(0).Type().String() != "error" { break } rpcmethods[obj.Name()] = &RPCMethod{ input: t.Params().At(0).Type(), output: t.Params().At(1).Type().(*types.Pointer).Elem(), //this is checked above recv: recv, sig: t, } } } for n, rpcm := range rpcmethods { rpcs, ok := g.services[rpcm.recv.Obj().Name()] if !ok { rpcs = &RPCService{ methods: map[string]*RPCMethod{}, } g.services[rpcm.recv.Obj().Name()] = rpcs } rpcs.methods[n] = rpcm } log.Printf("%+v", g.services["Arith"].methods) return nil }
func validType(T types.Type) bool { return T != nil && T != types.Typ[types.Invalid] && !strings.Contains(T.String(), "invalid type") // good but not foolproof }
// hashType returns a hash for t such that // types.IsIdentical(x, y) => hashType(x) == hashType(y). func hashType(t types.Type) int { return hashString(t.String()) // TODO(gri): provide a better hash }
// Bar200 converts a type to a string. func Bar200(t types.Type) string { return t.String() }
func findMethod(prog *ssa.Program, meth *types.Func, typ types.Type) *ssa.Function { if meth != nil { fmt.Fprintf(os.Stderr, " ^ finding method for type: %s pkg: %s name: %s\n", typ.String(), meth.Pkg().Name(), meth.Name()) } return prog.LookupMethod(typ, meth.Pkg(), meth.Name()) }
func equalType(x, y types.Type) error { if reflect.TypeOf(x) != reflect.TypeOf(y) { return fmt.Errorf("unequal kinds: %T vs %T", x, y) } switch x := x.(type) { case *types.Interface: y := y.(*types.Interface) // TODO(gri): enable separate emission of Embedded interfaces // and ExplicitMethods then use this logic. // if x.NumEmbeddeds() != y.NumEmbeddeds() { // return fmt.Errorf("unequal number of embedded interfaces: %d vs %d", // x.NumEmbeddeds(), y.NumEmbeddeds()) // } // for i := 0; i < x.NumEmbeddeds(); i++ { // xi := x.Embedded(i) // yi := y.Embedded(i) // if xi.String() != yi.String() { // return fmt.Errorf("mismatched %th embedded interface: %s vs %s", // i, xi, yi) // } // } // if x.NumExplicitMethods() != y.NumExplicitMethods() { // return fmt.Errorf("unequal methods: %d vs %d", // x.NumExplicitMethods(), y.NumExplicitMethods()) // } // for i := 0; i < x.NumExplicitMethods(); i++ { // xm := x.ExplicitMethod(i) // ym := y.ExplicitMethod(i) // if xm.Name() != ym.Name() { // return fmt.Errorf("mismatched %th method: %s vs %s", i, xm, ym) // } // if err := equalType(xm.Type(), ym.Type()); err != nil { // return fmt.Errorf("mismatched %s method: %s", xm.Name(), err) // } // } if x.NumMethods() != y.NumMethods() { return fmt.Errorf("unequal methods: %d vs %d", x.NumMethods(), y.NumMethods()) } for i := 0; i < x.NumMethods(); i++ { xm := x.Method(i) ym := y.Method(i) if xm.Name() != ym.Name() { return fmt.Errorf("mismatched %dth method: %s vs %s", i, xm, ym) } if err := equalType(xm.Type(), ym.Type()); err != nil { return fmt.Errorf("mismatched %s method: %s", xm.Name(), err) } } case *types.Array: y := y.(*types.Array) if x.Len() != y.Len() { return fmt.Errorf("unequal array lengths: %d vs %d", x.Len(), y.Len()) } if err := equalType(x.Elem(), y.Elem()); err != nil { return fmt.Errorf("array elements: %s", err) } case *types.Basic: y := y.(*types.Basic) if x.Kind() != y.Kind() { return fmt.Errorf("unequal basic types: %s vs %s", x, y) } case *types.Chan: y := y.(*types.Chan) if x.Dir() != y.Dir() { return fmt.Errorf("unequal channel directions: %d vs %d", x.Dir(), y.Dir()) } if err := equalType(x.Elem(), y.Elem()); err != nil { return fmt.Errorf("channel elements: %s", err) } case *types.Map: y := y.(*types.Map) if err := equalType(x.Key(), y.Key()); err != nil { return fmt.Errorf("map keys: %s", err) } if err := equalType(x.Elem(), y.Elem()); err != nil { return fmt.Errorf("map values: %s", err) } case *types.Named: y := y.(*types.Named) if x.String() != y.String() { return fmt.Errorf("unequal named types: %s vs %s", x, y) } case *types.Pointer: y := y.(*types.Pointer) if err := equalType(x.Elem(), y.Elem()); err != nil { return fmt.Errorf("pointer elements: %s", err) } case *types.Signature: y := y.(*types.Signature) if err := equalType(x.Params(), y.Params()); err != nil { return fmt.Errorf("parameters: %s", err) } if err := equalType(x.Results(), y.Results()); err != nil { return fmt.Errorf("results: %s", err) } if x.Variadic() != y.Variadic() { return fmt.Errorf("unequal varidicity: %t vs %t", x.Variadic(), y.Variadic()) } if (x.Recv() != nil) != (y.Recv() != nil) { return fmt.Errorf("unequal receivers: %s vs %s", x.Recv(), y.Recv()) } if x.Recv() != nil { // TODO(adonovan): fix: this assertion fires for interface methods. // The type of the receiver of an interface method is a named type // if the Package was loaded from export data, or an unnamed (interface) // type if the Package was produced by type-checking ASTs. // if err := equalType(x.Recv().Type(), y.Recv().Type()); err != nil { // return fmt.Errorf("receiver: %s", err) // } } case *types.Slice: y := y.(*types.Slice) if err := equalType(x.Elem(), y.Elem()); err != nil { return fmt.Errorf("slice elements: %s", err) } case *types.Struct: y := y.(*types.Struct) if x.NumFields() != y.NumFields() { return fmt.Errorf("unequal struct fields: %d vs %d", x.NumFields(), y.NumFields()) } for i := 0; i < x.NumFields(); i++ { xf := x.Field(i) yf := y.Field(i) if xf.Name() != yf.Name() { return fmt.Errorf("mismatched fields: %s vs %s", xf, yf) } if err := equalType(xf.Type(), yf.Type()); err != nil { return fmt.Errorf("struct field %s: %s", xf.Name(), err) } if x.Tag(i) != y.Tag(i) { return fmt.Errorf("struct field %s has unequal tags: %q vs %q", xf.Name(), x.Tag(i), y.Tag(i)) } } case *types.Tuple: y := y.(*types.Tuple) if x.Len() != y.Len() { return fmt.Errorf("unequal tuple lengths: %d vs %d", x.Len(), y.Len()) } for i := 0; i < x.Len(); i++ { if err := equalType(x.At(i).Type(), y.At(i).Type()); err != nil { return fmt.Errorf("tuple element %d: %s", i, err) } } } return nil }
// isTargetType returns true if a given type is identical to the target // types to be checked. func (v *visitor) isTargetType(t types.Type) bool { // Cannot use types.Identical since t and targetType are // obtained from different programs(?). return t.String() == v.targetType.String() }