func initReflect(i *interpreter) { i.reflectPackage = &ssa.Package{ Prog: i.prog, Pkg: reflectTypesPackage, Members: make(map[string]ssa.Member), } // Clobber the type-checker's notion of reflect.Value's // underlying type so that it more closely matches the fake one // (at least in the number of fields---we lie about the type of // the rtype field). // // We must ensure that calls to (ssa.Value).Type() return the // fake type so that correct "shape" is used when allocating // variables, making zero values, loading, and storing. // // TODO(adonovan): obviously this is a hack. We need a cleaner // way to fake the reflect package (almost---DeepEqual is fine). // One approach would be not to even load its source code, but // provide fake source files. This would guarantee that no bad // information leaks into other packages. if r := i.prog.ImportedPackage("reflect"); r != nil { rV := r.Pkg.Scope().Lookup("Value").Type().(*types.Named) // delete bodies of the old methods mset := i.prog.MethodSets.MethodSet(rV) for j := 0; j < mset.Len(); j++ { i.prog.MethodValue(mset.At(j)).Blocks = nil } tEface := types.NewInterface(nil, nil).Complete() rV.SetUnderlying(types.NewStruct([]*types.Var{ types.NewField(token.NoPos, r.Pkg, "t", tEface, false), // a lie types.NewField(token.NoPos, r.Pkg, "v", tEface, false), }, nil)) } i.rtypeMethods = methodSet{ "Bits": newMethod(i.reflectPackage, rtypeType, "Bits"), "Elem": newMethod(i.reflectPackage, rtypeType, "Elem"), "Field": newMethod(i.reflectPackage, rtypeType, "Field"), "In": newMethod(i.reflectPackage, rtypeType, "In"), "Kind": newMethod(i.reflectPackage, rtypeType, "Kind"), "NumField": newMethod(i.reflectPackage, rtypeType, "NumField"), "NumIn": newMethod(i.reflectPackage, rtypeType, "NumIn"), "NumMethod": newMethod(i.reflectPackage, rtypeType, "NumMethod"), "NumOut": newMethod(i.reflectPackage, rtypeType, "NumOut"), "Out": newMethod(i.reflectPackage, rtypeType, "Out"), "Size": newMethod(i.reflectPackage, rtypeType, "Size"), "String": newMethod(i.reflectPackage, rtypeType, "String"), } i.errorMethods = methodSet{ "Error": newMethod(i.reflectPackage, errorType, "Error"), } }
// Field = Name Type [ string_lit ] . // func (p *parser) parseField(parent *types.Package) (*types.Var, string) { pkg, name := p.parseName(parent, true) typ := p.parseType(parent) anonymous := false if name == "" { // anonymous field - typ must be T or *T and T must be a type name switch typ := deref(typ).(type) { case *types.Basic: // basic types are named types pkg = nil // objects defined in Universe scope have no package name = typ.Name() case *types.Named: name = typ.Obj().Name() default: p.errorf("anonymous field expected") } anonymous = true } tag := "" if p.tok == scanner.String { s := p.expect(scanner.String) var err error tag, err = strconv.Unquote(s) if err != nil { p.errorf("invalid struct tag %s: %s", s, err) } } return types.NewField(token.NoPos, pkg, name, typ, anonymous), tag }
func (p *importer) field() *types.Var { pkg, name := p.qualifiedName() typ := p.typ() anonymous := false if name == "" { // anonymous field - typ must be T or *T and T must be a type name switch typ := deref(typ).(type) { case *types.Basic: // basic types are named types pkg = nil name = typ.Name() case *types.Named: obj := typ.Obj() name = obj.Name() // correct the field package for anonymous fields if exported(name) { pkg = p.pkgList[0] } default: panic("anonymous field expected") } anonymous = true } return types.NewField(token.NoPos, pkg, name, typ, anonymous) }
// Field = Name Type [ string_lit ] . // func (p *parser) parseField(parent *types.Package) (*types.Var, string) { pkg, name := p.parseName(parent, true) if name == "_" { // Blank fields should be package-qualified because they // are unexported identifiers, but gc does not qualify them. // Assuming that the ident belongs to the current package // causes types to change during re-exporting, leading // to spurious "can't assign A to B" errors from go/types. // As a workaround, pretend all blank fields belong // to the same unique dummy package. const blankpkg = "<_>" pkg = p.getPkg(blankpkg, blankpkg) } typ := p.parseType(parent) anonymous := false if name == "" { // anonymous field - typ must be T or *T and T must be a type name switch typ := deref(typ).(type) { case *types.Basic: // basic types are named types pkg = nil // objects defined in Universe scope have no package name = typ.Name() case *types.Named: name = typ.Obj().Name() default: p.errorf("anonymous field expected") } anonymous = true } tag := "" if p.tok == scanner.String { s := p.expect(scanner.String) var err error tag, err = strconv.Unquote(s) if err != nil { p.errorf("invalid struct tag %s: %s", s, err) } } return types.NewField(token.NoPos, pkg, name, typ, anonymous), tag }
func (p *importer) field(parent *types.Package) *types.Var { pkg, name := p.fieldName(parent) typ := p.typ(parent) anonymous := false if name == "" { // anonymous field - typ must be T or *T and T must be a type name switch typ := deref(typ).(type) { case *types.Basic: // basic types are named types pkg = nil // // objects defined in Universe scope have no package name = typ.Name() case *types.Named: name = typ.Obj().Name() default: panic("anonymous field expected") } anonymous = true } return types.NewField(token.NoPos, pkg, name, typ, anonymous) }
// Field = Name Type [string] . func (p *parser) parseField(pkg *types.Package) (field *types.Var, tag string) { name := p.parseName() typ := p.parseType(pkg) anon := false if name == "" { anon = true switch typ := deref(typ).(type) { case *types.Basic: name = typ.Name() case *types.Named: name = typ.Obj().Name() default: p.error("anonymous field expected") } } field = types.NewField(token.NoPos, pkg, name, typ, anon) if p.tok == scanner.String { tag = p.parseString() } return }
func (p *importer) field() *types.Var { pkg, name := p.fieldName() typ := p.typ() anonymous := false if name == "" { // anonymous field - typ must be T or *T and T must be a type name switch typ := deref(typ).(type) { case *types.Basic: // basic types are named types name = typ.Name() case *types.Named: pkg = p.pkgList[0] name = typ.Obj().Name() default: panic("anonymous field expected") } anonymous = true } return types.NewField(token.NoPos, pkg, name, typ, anonymous) }
// t is a tuple for representing parameters or return values of function. func (g *generator) parse(name string, t *types.Tuple) *args { ps := toList(t) var fields []*types.Var var tags []string imports := map[types.Object]*ast.SelectorExpr{} un := uniqueNames{} m := &args{} for _, p := range ps { n := p.Name() if n == "" { n = p.Type().String() if !validIdentifier(n) { n = "p" } } n = un.get(capitalize(n)) t := types.NewField(0, g.pkg, n, p.Type(), false) // Filter out context and error. switch p.Type().String() { case "golang.org/x/net/context.Context": ctxName := un.get("ctx") m.Args = append(m.Args, func(string) string { return ctxName }) m.CtxName = ctxName m.HasCtx = true m.Args2 = append(m.Args2, struct{ Name, Type string }{ctxName, types.TypeString(t.Type(), relativeTo(g.pkg))}) continue case "error": errName := un.get("err") m.Args = append(m.Args, func(string) string { return errName }) m.ErrName = errName m.HasErr = true m.Args2 = append(m.Args2, struct{ Name, Type string }{errName, types.TypeString(t.Type(), relativeTo(g.pkg))}) continue } m.Args2 = append(m.Args2, struct{ Name, Type string }{uncapitalize(n), types.TypeString(t.Type(), relativeTo(g.pkg))}) updateDeps(g.rev[p.Type()], g.info, imports) // Make sure all the names are unique. m.Args = append(m.Args, func(s string) string { return fmt.Sprintf("%s.%s", s, n) }) fields = append(fields, t) tags = append(tags, fmt.Sprintf(`json:"%s"`, toSnake(n))) } if !m.HasCtx { m.CtxName = un.get("ctx") } if !m.HasErr { m.ErrName = un.get("err") } imps := cleanImports(imports) m.StructDef = structDef{ Pkg: g.pkg.Name(), Imports: imps, Name: name, } for i, v := range fields { m.StructDef.Fields = append(m.StructDef.Fields, struct { Name string Tag string Type string }{ Name: v.Name(), Type: types.TypeString(v.Type(), relativeTo(g.pkg)), Tag: tags[i], }) } return m }