// lookup returns the address of the named variable identified by obj // that is local to function f or one of its enclosing functions. // If escaping, the reference comes from a potentially escaping pointer // expression and the referent must be heap-allocated. // func (f *Function) lookup(obj types.Object, escaping bool) Value { if v, ok := f.objects[obj]; ok { if alloc, ok := v.(*Alloc); ok && escaping { alloc.Heap = true } return v // function-local var (address) } // Definition must be in an enclosing function; // plumb it through intervening closures. if f.parent == nil { panic("no ssa.Value for " + obj.String()) } outer := f.parent.lookup(obj, true) // escaping v := &FreeVar{ name: obj.Name(), typ: outer.Type(), pos: outer.Pos(), outer: outer, parent: f, } f.objects[obj] = v f.FreeVars = append(f.FreeVars, v) return v }
// 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 (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 (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()) } }
func formatNode(n ast.Node, obj types.Object, prog *loader.Program) string { var nc ast.Node // Render a copy of the node with no documentation. // We emit the documentation ourself. switch n := n.(type) { case *ast.FuncDecl: cp := *n cp.Doc = nil // Don't print the whole function body cp.Body = nil nc = &cp case *ast.GenDecl: cp := *n cp.Doc = nil if len(n.Specs) > 0 { // Only print this one type, not all the types in the // gendecl switch n.Specs[0].(type) { case *ast.TypeSpec: spec := findTypeSpec(n, obj.Pos()) if spec != nil { specCp := *spec if *showUnexportedFields == false { trimUnexportedElems(&specCp) } specCp.Doc = nil cp.Specs = []ast.Spec{&specCp} } cp.Lparen = 0 cp.Rparen = 0 case *ast.ValueSpec: spec := findVarSpec(n, obj.Pos()) if spec != nil { specCp := *spec specCp.Doc = nil cp.Specs = []ast.Spec{&specCp} } cp.Lparen = 0 cp.Rparen = 0 } } nc = &cp case *ast.Field: // Not supported by go/printer // TODO(dominikh): Methods in interfaces are syntactically // represented as fields. Using types.Object.String for those // causes them to look different from real functions. // go/printer doesn't include the import paths in names, while // Object.String does. Fix that. return obj.String() default: return obj.String() } buf := &bytes.Buffer{} cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8} err := cfg.Fprint(buf, prog.Fset, nc) if err != nil { return obj.String() } return buf.String() }