func createDef(obj types.Object, ident *ast.Ident, ctx *getDefinitionsContext, isType bool) *Definition { fullName := getFullName(obj, ctx, isType) if def, ok := ctx.defs[fullName]; ok { return def } def := new(Definition) def.Name = fullName def.Pkg = obj.Pkg() def.IsExported = obj.Exported() def.TypeOf = reflect.TypeOf(obj) def.SimpleName = obj.Name() def.Usages = make([]*Usage, 0) def.InterfacesDefs = make([]*Definition, 0) if ident != nil { position := ctx.fset.Position(ident.Pos()) def.File = position.Filename def.Line = position.Line def.Offset = position.Offset def.Col = position.Column } if !types.IsInterface(obj.Type()) { fillInterfaces(def, obj, ctx) } ctx.defs[def.Name] = def logDefinition(def, obj, ident, ctx) return def }
func (b *candidateCollector) asCandidate(obj types.Object) Candidate { objClass := classifyObject(obj) var typ types.Type switch objClass { case "const", "func", "var": typ = obj.Type() case "type": typ = obj.Type().Underlying() } var typStr string switch t := typ.(type) { case *types.Interface: typStr = "interface" case *types.Struct: typStr = "struct" default: if _, isBuiltin := obj.(*types.Builtin); isBuiltin { typStr = builtinTypes[obj.Name()] } else if t != nil { typStr = types.TypeString(t, b.qualify) } } return Candidate{ Class: objClass, Name: obj.Name(), Type: typStr, } }
func isStringer(obj types.Object) bool { switch obj := obj.(type) { case *types.Func: if obj.Name() != "String" { return false } sig, ok := obj.Type().(*types.Signature) if !ok { return false } if sig.Recv() == nil { return false } if sig.Params().Len() != 0 { return false } res := sig.Results() if res.Len() != 1 { return false } ret := res.At(0).Type() if ret != types.Universe.Lookup("string").Type() { return false } return true default: return false } return false }
func updateGetDefinitionsContext(ctx *getDefinitionsContext, def *Definition, ident *ast.Ident, obj types.Object) { switch obj.(type) { case *types.Var: //Processing vars later to be sure that all info about structs already filled ctx.vars = append(ctx.vars, newObjectWithIdent(obj, ident)) case *types.Func: //Processing funcs later to be sure that all info about interfaces already filled ctx.funcs = append(ctx.funcs, newObjectWithIdent(obj, ident)) case *types.TypeName: //If the underlying type is struct, then filling //positions of struct's fields (key) and struct name(value) //to map. Then we can extract struct name for fields when //will be analyze them. t := obj.(*types.TypeName) underlyingType := t.Type().Underlying() switch underlyingType.(type) { case *types.Struct: s := underlyingType.(*types.Struct) for i := 0; i < s.NumFields(); i++ { field := s.Field(i) ctx.structs[posToStr(ctx.fset, field.Pos())] = obj.Name() } } } //Check for interfaces underlyingType := obj.Type().Underlying() switch underlyingType.(type) { case *types.Interface: d := new(defWithInterface) d.def = def d.interfac = underlyingType.(*types.Interface) ctx.interfaces = append(ctx.interfaces, d) } }
// equalObj reports how x and y differ. They are assumed to belong to // different universes so cannot be compared directly. func equalObj(x, y types.Object) error { if reflect.TypeOf(x) != reflect.TypeOf(y) { return fmt.Errorf("%T vs %T", x, y) } xt := x.Type() yt := y.Type() switch x.(type) { case *types.Var, *types.Func: // ok case *types.Const: xval := x.(*types.Const).Val() yval := y.(*types.Const).Val() // Use string comparison for floating-point values since rounding is permitted. if constant.Compare(xval, token.NEQ, yval) && !(xval.Kind() == constant.Float && xval.String() == yval.String()) { return fmt.Errorf("unequal constants %s vs %s", xval, yval) } case *types.TypeName: xt = xt.Underlying() yt = yt.Underlying() default: return fmt.Errorf("unexpected %T", x) } return equalType(xt, yt) }
//getFullName is returning unique name of obj. func getFullName(obj types.Object, ctx *getDefinitionsContext, isType bool) string { if obj == nil { return "" } if isType { return obj.Type().String() } result := "" switch obj.(type) { case *types.Func: f := obj.(*types.Func) r := strings.NewReplacer("(", "", "*", "", ")", "") result = r.Replace(f.FullName()) default: if obj.Pkg() != nil { result += obj.Pkg().Path() result += "." } if packageName, ok := ctx.structs[posToStr(ctx.fset, obj.Pos())]; ok { result += packageName result += "." } result += obj.Name() } return result }
func (f *Function) addParamObj(obj types.Object) *Parameter { name := obj.Name() if name == "" { name = fmt.Sprintf("arg%d", len(f.Params)) } param := f.addParam(name, obj.Type(), obj.Pos()) param.object = obj return param }
// addSpilledParam declares a parameter that is pre-spilled to the // stack; the function body will load/store the spilled location. // Subsequent lifting will eliminate spills where possible. // func (f *Function) addSpilledParam(obj types.Object) { param := f.addParamObj(obj) spill := &Alloc{Comment: obj.Name()} spill.setType(types.NewPointer(obj.Type())) spill.setPos(obj.Pos()) f.objects[obj] = spill f.Locals = append(f.Locals, spill) f.emit(spill) f.emit(&Store{Addr: spill, Val: param}) }
func formatMember(obj types.Object, maxname int) string { qualifier := types.RelativeTo(obj.Pkg()) var buf bytes.Buffer fmt.Fprintf(&buf, "%-5s %-*s", tokenOf(obj), maxname, obj.Name()) switch obj := obj.(type) { case *types.Const: fmt.Fprintf(&buf, " %s = %s", types.TypeString(obj.Type(), qualifier), obj.Val().String()) case *types.Func: fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type(), qualifier)) case *types.TypeName: // Abbreviate long aggregate type names. var abbrev string switch t := obj.Type().Underlying().(type) { case *types.Interface: if t.NumMethods() > 1 { abbrev = "interface{...}" } case *types.Struct: if t.NumFields() > 1 { abbrev = "struct{...}" } } if abbrev == "" { fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type().Underlying(), qualifier)) } else { fmt.Fprintf(&buf, " %s", abbrev) } case *types.Var: fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type(), qualifier)) } return buf.String() }
func (p *exporter) obj(obj types.Object) { if trace { p.tracef("object %s {\n", obj.Name()) defer p.tracef("}\n") } switch obj := obj.(type) { case *types.Const: p.int(constTag) p.string(obj.Name()) p.typ(obj.Type()) p.value(obj.Val()) case *types.TypeName: p.int(typeTag) // name is written by corresponding named type p.typ(obj.Type().(*types.Named)) case *types.Var: p.int(varTag) p.string(obj.Name()) p.typ(obj.Type()) case *types.Func: p.int(funcTag) p.string(obj.Name()) p.typ(obj.Type()) default: panic(fmt.Sprintf("unexpected object type %T", obj)) } }
func (p *exporter) obj(obj types.Object) { switch obj := obj.(type) { case *types.Const: p.tag(constTag) p.pos(obj) p.qualifiedName(obj) p.typ(obj.Type()) p.value(obj.Val()) case *types.TypeName: p.tag(typeTag) p.typ(obj.Type()) case *types.Var: p.tag(varTag) p.pos(obj) p.qualifiedName(obj) p.typ(obj.Type()) case *types.Func: p.tag(funcTag) p.pos(obj) p.qualifiedName(obj) sig := obj.Type().(*types.Signature) p.paramList(sig.Params(), sig.Variadic()) p.paramList(sig.Results(), false) default: log.Fatalf("gcimporter: unexpected object %v (%T)", obj, obj) } }
func (w *Walker) emitObj(obj types.Object) { switch obj := obj.(type) { case *types.Const: w.emitf("const %s %s", obj.Name(), w.typeString(obj.Type())) w.emitf("const %s = %s", obj.Name(), obj.Val()) case *types.Var: w.emitf("var %s %s", obj.Name(), w.typeString(obj.Type())) case *types.TypeName: w.emitType(obj) case *types.Func: w.emitFunc(obj) default: panic("unknown object: " + obj.String()) } }
func addInterface(obj types.Object, ident *ast.Ident, ctx *getDefinitionsContext) { interfac := obj.Type().Underlying().(*types.Interface) def := createDef(obj, ident, ctx, true) updateGetDefinitionsContext(ctx, def, ident, obj) util.Debug("adding interface [%s] [%v] [%v] [%v]", def.Name, def.Pkg, obj.Type().Underlying(), obj.Type()) //Adding all methods of interface for i := 0; i < interfac.NumMethods(); i++ { f := interfac.Method(i) def := createDef(f, nil, ctx, false) util.Debug("\tadding method [%v] [%s]", f, def.Name) updateGetDefinitionsContext(ctx, def, ident, f) } }
func (p *printer) printObj(obj types.Object) { p.print(obj.Name()) typ, basic := obj.Type().Underlying().(*types.Basic) if basic && typ.Info()&types.IsUntyped != 0 { // don't write untyped types } else { p.print(" ") p.writeType(p.pkg, obj.Type()) } if obj, ok := obj.(*types.Const); ok { floatFmt := basic && typ.Info()&(types.IsFloat|types.IsComplex) != 0 p.print(" = ") p.print(valString(obj.Val(), floatFmt)) } }
func newFuncFrom(p *Package, parent string, obj types.Object, sig *types.Signature) (Func, error) { haserr := false res := sig.Results() var ret types.Type switch res.Len() { case 2: if !isErrorType(res.At(1).Type()) { return Func{}, fmt.Errorf( "bind: second result value must be of type error: %s", obj, ) } haserr = true ret = res.At(0).Type() case 1: if isErrorType(res.At(0).Type()) { haserr = true ret = nil } else { ret = res.At(0).Type() } case 0: ret = nil default: return Func{}, fmt.Errorf("bind: too many results to return: %v", obj) } id := obj.Pkg().Name() + "_" + obj.Name() if parent != "" { id = obj.Pkg().Name() + "_" + parent + "_" + obj.Name() } return Func{ pkg: p, sig: newSignatureFrom(p, sig), typ: obj.Type(), name: obj.Name(), id: id, doc: p.getDoc(parent, obj), ret: ret, err: haserr, }, nil }
func objectKind(obj types.Object) string { switch obj := obj.(type) { case *types.PkgName: return "imported package name" case *types.TypeName: return "type" case *types.Var: if obj.IsField() { return "field" } case *types.Func: if obj.Type().(*types.Signature).Recv() != nil { return "method" } } // label, func, var, const return strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types.")) }
func (sym *symtab) addSymbol(obj types.Object) { fn := types.ObjectString(obj, nil) n := obj.Name() pkg := obj.Pkg() id := n if pkg != nil { id = pkg.Name() + "_" + n } switch obj.(type) { case *types.Const: sym.syms[fn] = &symbol{ gopkg: pkg, goobj: obj, kind: skConst, id: id, goname: n, cgoname: "cgo_const_" + id, cpyname: "cpy_const_" + id, } sym.addType(obj, obj.Type()) case *types.Var: sym.syms[fn] = &symbol{ gopkg: pkg, goobj: obj, kind: skVar, id: id, goname: n, cgoname: "cgo_var_" + id, cpyname: "cpy_var_" + id, } sym.addType(obj, obj.Type()) case *types.Func: sym.syms[fn] = &symbol{ gopkg: pkg, goobj: obj, kind: skFunc, id: id, goname: n, cgoname: "cgo_func_" + id, cpyname: "cpy_func_" + id, } sig := obj.Type().Underlying().(*types.Signature) sym.processTuple(sig.Params()) sym.processTuple(sig.Results()) case *types.TypeName: sym.addType(obj, obj.Type()) default: panic(fmt.Errorf("gopy: handled object [%#v]", obj)) } }
func (w *Walker) emitObj(obj types.Object) { switch obj := obj.(type) { case *types.Const: w.emitf("const %s %s", obj.Name(), w.typeString(obj.Type())) x := obj.Val() short := x.String() exact := x.ExactString() if short == exact { w.emitf("const %s = %s", obj.Name(), short) } else { w.emitf("const %s = %s // %s", obj.Name(), short, exact) } case *types.Var: w.emitf("var %s %s", obj.Name(), w.typeString(obj.Type())) case *types.TypeName: w.emitType(obj) case *types.Func: w.emitFunc(obj) default: panic("unknown object: " + obj.String()) } }
// memberFromObject populates package pkg with a member for the // typechecker object obj. // // For objects from Go source code, syntax is the associated syntax // tree (for funcs and vars only); it will be used during the build // phase. // func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { name := obj.Name() switch obj := obj.(type) { case *types.TypeName: pkg.Members[name] = &Type{ object: obj, pkg: pkg, } case *types.Const: c := &NamedConst{ object: obj, Value: NewConst(obj.Val(), obj.Type()), pkg: pkg, } pkg.values[obj] = c.Value pkg.Members[name] = c case *types.Var: g := &Global{ Pkg: pkg, name: name, object: obj, typ: types.NewPointer(obj.Type()), // address pos: obj.Pos(), } pkg.values[obj] = g pkg.Members[name] = g case *types.Func: sig := obj.Type().(*types.Signature) if sig.Recv() == nil && name == "init" { pkg.ninit++ name = fmt.Sprintf("init#%d", pkg.ninit) } fn := &Function{ name: name, object: obj, Signature: sig, syntax: syntax, pos: obj.Pos(), Pkg: pkg, Prog: pkg.Prog, } if syntax == nil { fn.Synthetic = "loaded from gc object file" } pkg.values[obj] = fn if sig.Recv() == nil { pkg.Members[name] = fn // package-level function } default: // (incl. *types.Package) panic("unexpected Object type: " + obj.String()) } }
func (p *exporter) obj(obj types.Object) { switch obj := obj.(type) { case *types.Const: p.tag(constTag) p.pos(obj) p.qualifiedName(obj) p.typ(obj.Type()) p.value(obj.Val()) case *types.TypeName: p.tag(typeTag) p.typ(obj.Type()) case *types.Var: p.tag(varTag) p.pos(obj) p.qualifiedName(obj) p.typ(obj.Type()) case *types.Func: p.tag(funcTag) p.pos(obj) p.qualifiedName(obj) sig := obj.Type().(*types.Signature) p.paramList(sig.Params(), sig.Variadic()) p.paramList(sig.Results(), false) // Alias-related code. Keep for now. // case *types_Alias: // // make sure the original is exported before the alias // // (if the alias declaration was invalid, orig will be nil) // orig := original(obj) // if orig != nil && !p.reexported[orig] { // p.obj(orig) // p.reexported[orig] = true // } // p.tag(aliasTag) // p.pos(obj) // p.string(obj.Name()) // p.qualifiedName(orig) default: log.Fatalf("gcimporter: unexpected object %v (%T)", obj, obj) } }
// getDoc returns the doc string associated with types.Object // parent is the name of the containing scope ("" for global scope) func (p *Package) getDoc(parent string, o types.Object) string { n := o.Name() switch o.(type) { case *types.Const: for _, c := range p.doc.Consts { for _, cn := range c.Names { if n == cn { return c.Doc } } } case *types.Var: for _, v := range p.doc.Vars { for _, vn := range v.Names { if n == vn { return v.Doc } } } case *types.Func: doc := func() string { if o.Parent() == nil || (o.Parent() != nil && parent != "") { for _, typ := range p.doc.Types { if typ.Name != parent { continue } if o.Parent() == nil { for _, m := range typ.Methods { if m.Name == n { return m.Doc } } } else { for _, m := range typ.Funcs { if m.Name == n { return m.Doc } } } } } else { for _, f := range p.doc.Funcs { if n == f.Name { return f.Doc } } } return "" }() sig := o.Type().(*types.Signature) parseFn := func(tup *types.Tuple) []string { params := []string{} if tup == nil { return params } for i := 0; i < tup.Len(); i++ { paramVar := tup.At(i) paramType := p.syms.symtype(paramVar.Type()).pysig if paramVar.Name() != "" { paramType = fmt.Sprintf("%s %s", paramType, paramVar.Name()) } params = append(params, paramType) } return params } params := parseFn(sig.Params()) results := parseFn(sig.Results()) paramString := strings.Join(params, ", ") resultString := strings.Join(results, ", ") //FIXME(sbinet): add receiver for methods? docSig := fmt.Sprintf("%s(%s) %s", o.Name(), paramString, resultString) if doc != "" { doc = fmt.Sprintf("%s\n\n%s", docSig, doc) } else { doc = docSig } return doc case *types.TypeName: for _, t := range p.doc.Types { if n == t.Name { return t.Doc } } default: // TODO(sbinet) panic(fmt.Errorf("not yet supported: %v (%T)", o, o)) } return "" }
func sameObj(a, b types.Object) bool { // Because unnamed types are not canonicalized, we cannot simply compare types for // (pointer) identity. // Ideally we'd check equality of constant values as well, but this is good enough. return objTag(a) == objTag(b) && types.Identical(a.Type(), b.Type()) }
func (g *cpyGen) genStructMemberSetter(cpy Struct, i int, f types.Object) { var ( pkg = cpy.Package() ft = f.Type() self = newVar(pkg, cpy.GoType(), cpy.GoName(), "self", "") ifield = newVar(pkg, ft, f.Name(), "ret", "") cgo_fsetname = fmt.Sprintf("cgo_func_%[1]s_setter_%[2]d", cpy.sym.id, i+1) cpy_fsetname = fmt.Sprintf("cpy_func_%[1]s_setter_%[2]d", cpy.sym.id, i+1) ) g.decl.Printf("\n/* setter for %[1]s.%[2]s.%[3]s */\n", pkg.Name(), cpy.sym.goname, f.Name(), ) g.decl.Printf("static int\n") g.decl.Printf( "%[2]s(%[1]s *self, PyObject *value, void *closure);\n", cpy.sym.cpyname, cpy_fsetname, ) g.impl.Printf("\n/* setter for %[1]s.%[2]s.%[3]s */\n", pkg.Name(), cpy.sym.goname, f.Name(), ) g.impl.Printf("static int\n") g.impl.Printf( "%[2]s(%[1]s *self, PyObject *value, void *closure) {\n", cpy.sym.cpyname, cpy_fsetname, ) g.impl.Indent() ifield.genDecl(g.impl) g.impl.Printf("if (value == NULL) {\n") g.impl.Indent() g.impl.Printf( "PyErr_SetString(PyExc_TypeError, \"cannot delete '%[1]s' attribute\");\n", f.Name(), ) g.impl.Printf("return -1;\n") g.impl.Outdent() g.impl.Printf("}\n\n") g.impl.Printf("if (!%s) {\n", fmt.Sprintf(ifield.sym.pychk, "value")) g.impl.Indent() g.impl.Printf( "PyErr_SetString(PyExc_TypeError, \"invalid type for '%[1]s' attribute\");\n", f.Name(), ) g.impl.Printf("return -1;\n") g.impl.Outdent() g.impl.Printf("}\n\n") g.impl.Printf("if (!%[1]s(value, &c_ret)) {\n", ifield.sym.py2c) g.impl.Indent() g.impl.Printf("return -1;\n") g.impl.Outdent() g.impl.Printf("}\n\n") g.impl.Printf("%[1]s((%[2]s)(self->cgopy), c_%[3]s);\n", cgo_fsetname, self.CGoType(), ifield.Name(), ) g.impl.Printf("return 0;\n") g.impl.Outdent() g.impl.Printf("}\n\n") }
func (g *cpyGen) genStructMemberGetter(cpy Struct, i int, f types.Object) { pkg := cpy.Package() ft := f.Type() var ( cgo_fgetname = fmt.Sprintf("cgo_func_%[1]s_getter_%[2]d", cpy.sym.id, i+1) cpy_fgetname = fmt.Sprintf("cpy_func_%[1]s_getter_%[2]d", cpy.sym.id, i+1) ifield = newVar(pkg, ft, f.Name(), "ret", "") results = []*Var{ifield} ) if needWrapType(ft) { g.decl.Printf("\n/* wrapper for field %s.%s.%s */\n", pkg.Name(), cpy.GoName(), f.Name(), ) g.decl.Printf("typedef void* %[1]s_field_%d;\n", cpy.sym.cgoname, i+1) } g.decl.Printf("\n/* getter for %[1]s.%[2]s.%[3]s */\n", pkg.Name(), cpy.sym.goname, f.Name(), ) g.decl.Printf("static PyObject*\n") g.decl.Printf( "%[2]s(%[1]s *self, void *closure); /* %[3]s */\n", cpy.sym.cpyname, cpy_fgetname, f.Name(), ) g.impl.Printf("\n/* getter for %[1]s.%[2]s.%[3]s */\n", pkg.Name(), cpy.sym.goname, f.Name(), ) g.impl.Printf("static PyObject*\n") g.impl.Printf( "%[2]s(%[1]s *self, void *closure) /* %[3]s */ {\n", cpy.sym.cpyname, cpy_fgetname, f.Name(), ) g.impl.Indent() g.impl.Printf("PyObject *o = NULL;\n") ftname := g.pkg.syms.symtype(ft).cgoname if needWrapType(ft) { ftname = fmt.Sprintf("%[1]s_field_%d", cpy.sym.cgoname, i+1) } g.impl.Printf( "%[1]s c_ret = %[2]s(self->cgopy); /*wrap*/\n", ftname, cgo_fgetname, ) { format := []string{} funcArgs := []string{} switch len(results) { case 1: ret := results[0] ret.name = "ret" pyfmt, pyaddrs := ret.getArgBuildValue() format = append(format, pyfmt) funcArgs = append(funcArgs, pyaddrs...) default: panic("bind: impossible") } g.impl.Printf("o = Py_BuildValue(%q, %s);\n", strings.Join(format, ""), strings.Join(funcArgs, ", "), ) } g.impl.Printf("return o;\n") g.impl.Outdent() g.impl.Printf("}\n\n") }
// addNamedLocal creates a local variable, adds it to function f and // returns it. Its name and type are taken from obj. Subsequent // calls to f.lookup(obj) will return the same local. // func (f *Function) addNamedLocal(obj types.Object) *Alloc { l := f.addLocal(obj.Type(), obj.Pos()) l.Comment = obj.Name() f.objects[obj] = l return l }