// ArrayType = "[" int_lit "]" Type . // func (p *parser) parseArrayType() types.Type { // "[" already consumed and lookahead known not to be "]" lit := p.expect(scanner.Int) p.expect(']') elem := p.parseType() n, err := strconv.ParseInt(lit, 10, 64) if err != nil { p.error(err) } return types.NewArray(elem, n) }
// ArrayOrSliceType = "[" [ int ] "]" Type . func (p *parser) parseArrayOrSliceType(pkg *types.Package) types.Type { p.expect('[') if p.tok == ']' { p.next() return types.NewSlice(p.parseType(pkg)) } n := p.parseInt() p.expect(']') return types.NewArray(p.parseType(pkg), n) }
func ext۰reflect۰Value۰MapKeys(a *analysis, cgn *cgnode) { // Allocate an array for the result. obj := a.nextNode() a.addNodes(types.NewArray(a.reflectValueObj.Type(), 1), "reflect.MapKeys result") a.endObject(obj, cgn, nil) a.addressOf(a.funcResults(cgn.obj), obj) a.addConstraint(&rVMapKeysConstraint{ cgn: cgn, v: a.funcParams(cgn.obj), result: obj + 1, // result is stored in array elems }) }
// testMainSlice emits to fn code to construct a slice of type slice // (one of []testing.Internal{Test,Benchmark,Example}) for all // functions in this package whose name starts with prefix (one of // "Test", "Benchmark" or "Example") and whose type is appropriate. // It returns the slice value. // func testMainSlice(fn *Function, prefix string, slice types.Type) Value { tElem := slice.(*types.Slice).Elem() tFunc := tElem.Underlying().(*types.Struct).Field(1).Type() var testfuncs []*Function for name, mem := range fn.Pkg.Members { if fn, ok := mem.(*Function); ok && isTest(name, prefix) && types.IsIdentical(fn.Signature, tFunc) { testfuncs = append(testfuncs, fn) } } if testfuncs == nil { return nilConst(slice) } tString := types.Typ[types.String] tPtrString := types.NewPointer(tString) tPtrElem := types.NewPointer(tElem) tPtrFunc := types.NewPointer(tFunc) // Emit: array = new [n]testing.InternalTest tArray := types.NewArray(tElem, int64(len(testfuncs))) array := emitNew(fn, tArray, token.NoPos) array.Comment = "test main" for i, testfunc := range testfuncs { // Emit: pitem = &array[i] ia := &IndexAddr{X: array, Index: intConst(int64(i))} ia.setType(tPtrElem) pitem := fn.emit(ia) // Emit: pname = &pitem.Name fa := &FieldAddr{X: pitem, Field: 0} // .Name fa.setType(tPtrString) pname := fn.emit(fa) // Emit: *pname = "testfunc" emitStore(fn, pname, NewConst(exact.MakeString(testfunc.Name()), tString)) // Emit: pfunc = &pitem.F fa = &FieldAddr{X: pitem, Field: 1} // .F fa.setType(tPtrFunc) pfunc := fn.emit(fa) // Emit: *pfunc = testfunc emitStore(fn, pfunc, testfunc) } // Emit: slice array[:] sl := &Slice{X: array} sl.setType(slice) return fn.emit(sl) }
// ArrayOrSliceType = "[" [ int ] "]" Type . func (p *parser) parseArrayOrSliceType(pkg *types.Package) types.Type { p.expect('[') if p.tok == ']' { p.next() return types.NewSlice(p.parseType(pkg)) } lit := p.expect(scanner.Int) n, err := strconv.ParseInt(lit, 10, 0) if err != nil { p.error(err) } p.expect(']') return types.NewArray(p.parseType(pkg), n) }
// testMainSlice emits to fn code to construct a slice of type slice // (one of []testing.Internal{Test,Benchmark,Example}) for all // functions in testfuncs. It returns the slice value. // func testMainSlice(fn *Function, testfuncs []*Function, slice types.Type) Value { if testfuncs == nil { return nilConst(slice) } tElem := slice.(*types.Slice).Elem() tPtrString := types.NewPointer(tString) tPtrElem := types.NewPointer(tElem) tPtrFunc := types.NewPointer(funcField(slice)) // Emit: array = new [n]testing.InternalTest tArray := types.NewArray(tElem, int64(len(testfuncs))) array := emitNew(fn, tArray, token.NoPos) array.Comment = "test main" for i, testfunc := range testfuncs { // Emit: pitem = &array[i] ia := &IndexAddr{X: array, Index: intConst(int64(i))} ia.setType(tPtrElem) pitem := fn.emit(ia) // Emit: pname = &pitem.Name fa := &FieldAddr{X: pitem, Field: 0} // .Name fa.setType(tPtrString) pname := fn.emit(fa) // Emit: *pname = "testfunc" emitStore(fn, pname, stringConst(testfunc.Name())) // Emit: pfunc = &pitem.F fa = &FieldAddr{X: pitem, Field: 1} // .F fa.setType(tPtrFunc) pfunc := fn.emit(fa) // Emit: *pfunc = testfunc emitStore(fn, pfunc, testfunc) } // Emit: slice array[:] sl := &Slice{X: array} sl.setType(slice) return fn.emit(sl) }
// generate generates offline constraints for the entire program. // It returns the synthetic root of the callgraph. // func (a *analysis) generate() *cgnode { // Create a dummy node since we use the nodeid 0 for // non-pointerlike variables. a.addNodes(tInvalid, "(zero)") // Create the global node for panic values. a.panicNode = a.addNodes(tEface, "panic") // Create nodes and constraints for all methods of reflect.rtype. // (Shared contours are used by dynamic calls to reflect.Type // methods---typically just String().) if rtype := a.reflectRtypePtr; rtype != nil { a.genMethodsOf(rtype) } root := a.genRootCalls() // Create nodes and constraints for all methods of all types // that are dynamically accessible via reflection or interfaces. for _, T := range a.prog.TypesWithMethodSets() { a.genMethodsOf(T) } // Generate constraints for entire program. for len(a.genq) > 0 { cgn := a.genq[0] a.genq = a.genq[1:] a.genFunc(cgn) } // The runtime magically allocates os.Args; so should we. if os := a.prog.ImportedPackage("os"); os != nil { // In effect: os.Args = new([1]string)[:] obj := a.addNodes(types.NewArray(types.Typ[types.String], 1), "<command-line args>") a.endObject(obj, nil, "<command-line args>") a.addressOf(a.objectNode(nil, os.Var("Args")), obj) } return root }
// Common code for direct (inlined) and indirect calls to (reflect.Value).Call. func reflectCallImpl(a *analysis, cgn *cgnode, site *callsite, recv, arg nodeid, dotdotdot bool) nodeid { // Allocate []reflect.Value array for the result. ret := a.nextNode() a.addNodes(types.NewArray(a.reflectValueObj.Type(), 1), "rVCall.ret") a.endObject(ret, cgn, nil) // pts(targets) will be the set of possible call targets. site.targets = a.addOneNode(tInvalid, "rvCall.targets", nil) // All arguments are merged since they arrive in a slice. argelts := a.addOneNode(a.reflectValueObj.Type(), "rVCall.args", nil) a.load(argelts, arg, 1, 1) // slice elements a.addConstraint(&rVCallConstraint{ cgn: cgn, targets: site.targets, v: recv, arg: argelts, result: ret + 1, // results go into elements of ret dotdotdot: dotdotdot, }) return ret }
// sliceToArray returns the type representing the arrays to which // slice type slice points. func sliceToArray(slice types.Type) *types.Array { return types.NewArray(slice.Underlying().(*types.Slice).Elem(), 1) }
func (p *importer) typ() types.Type { // if the type was seen before, i is its index (>= 0) i := p.int() if i >= 0 { return p.typList[i] } // otherwise, i is the type tag (< 0) switch i { case arrayTag: t := new(types.Array) p.record(t) n := p.int64() *t = *types.NewArray(p.typ(), n) return t case sliceTag: t := new(types.Slice) p.record(t) *t = *types.NewSlice(p.typ()) return t case structTag: t := new(types.Struct) p.record(t) n := p.int() fields := make([]*types.Var, n) tags := make([]string, n) for i := range fields { fields[i] = p.field() tags[i] = p.string() } *t = *types.NewStruct(fields, tags) return t case pointerTag: t := new(types.Pointer) p.record(t) *t = *types.NewPointer(p.typ()) return t case signatureTag: t := new(types.Signature) p.record(t) *t = *p.signature() return t case interfaceTag: t := new(types.Interface) p.record(t) // read embedded interfaces embeddeds := make([]*types.Named, p.int()) for i := range embeddeds { embeddeds[i] = p.typ().(*types.Named) } // read methods methods := make([]*types.Func, p.int()) for i := range methods { pkg, name := p.qualifiedName() methods[i] = types.NewFunc(token.NoPos, pkg, name, p.typ().(*types.Signature)) } *t = *types.NewInterface(methods, embeddeds) return t case mapTag: t := new(types.Map) p.record(t) *t = *types.NewMap(p.typ(), p.typ()) return t case chanTag: t := new(types.Chan) p.record(t) *t = *types.NewChan(types.ChanDir(p.int()), p.typ()) return t case namedTag: // read type object name := p.string() pkg := p.pkg() scope := pkg.Scope() obj := scope.Lookup(name) // if the object doesn't exist yet, create and insert it if obj == nil { obj = types.NewTypeName(token.NoPos, pkg, name, nil) scope.Insert(obj) } // associate new named type with obj if it doesn't exist yet t0 := types.NewNamed(obj.(*types.TypeName), nil, nil) // but record the existing type, if any t := obj.Type().(*types.Named) p.record(t) // read underlying type t0.SetUnderlying(p.typ()) // read associated methods for i, n := 0, p.int(); i < n; i++ { t0.AddMethod(types.NewFunc(token.NoPos, pkg, p.string(), p.typ().(*types.Signature))) } return t default: panic(fmt.Sprintf("unexpected type tag %d", i)) } }
func (cdd *CDD) varDecl(w *bytes.Buffer, typ types.Type, global bool, name string, val ast.Expr) (acds []*CDD) { dim, acds := cdd.Type(w, typ) w.WriteByte(' ') w.WriteString(dimFuncPtr(name, dim)) constInit := true // true if C declaration can init value if global { cdd.copyDecl(w, ";\n") // Global variables may need declaration if val != nil { if i, ok := val.(*ast.Ident); !ok || i.Name != "nil" { constInit = cdd.exprValue(val) != nil } } } if constInit { w.WriteString(" = ") if val != nil { cdd.Expr(w, val, typ) } else { zeroVal(w, typ) } } w.WriteString(";\n") cdd.copyDef(w) if !constInit { w.Reset() // Runtime initialisation assign := false switch t := underlying(typ).(type) { case *types.Slice: switch vt := val.(type) { case *ast.CompositeLit: aname := "array" + cdd.gtc.uniqueId() var n int64 for _, elem := range vt.Elts { switch e := elem.(type) { case *ast.KeyValueExpr: val := cdd.exprValue(e.Key) if val == nil { panic("slice: composite literal with non-constant key") } m, ok := exact.Int64Val(val) if !ok { panic("slice: can't convert " + val.String() + " to int64") } m++ if m > n { n = m } default: n++ } } at := types.NewArray(t.Elem(), n) o := types.NewVar(vt.Lbrace, cdd.gtc.pkg, aname, at) cdd.gtc.pkg.Scope().Insert(o) acd := cdd.gtc.newCDD(o, VarDecl, cdd.il) av := *vt cdd.gtc.ti.Types[&av] = types.TypeAndValue{Type: at} // BUG: thread-unsafe acd.varDecl(new(bytes.Buffer), o.Type(), cdd.gtc.isGlobal(o), aname, &av) cdd.InitNext = acd acds = append(acds, acd) w.WriteByte('\t') w.WriteString(name) w.WriteString(" = ASLICE(") w.WriteString(strconv.FormatInt(at.Len(), 10)) w.WriteString(", ") w.WriteString(aname) w.WriteString(");\n") default: assign = true } case *types.Array: w.WriteByte('\t') w.WriteString("ACPY(") w.WriteString(name) w.WriteString(", ") switch val.(type) { case *ast.CompositeLit: w.WriteString("((") dim, _ := cdd.Type(w, t.Elem()) dim = append([]string{"[]"}, dim...) w.WriteString("(" + dimFuncPtr("", dim) + "))") cdd.Expr(w, val, typ) default: cdd.Expr(w, val, typ) } w.WriteString("));\n") case *types.Pointer: u, ok := val.(*ast.UnaryExpr) if !ok { assign = true break } c, ok := u.X.(*ast.CompositeLit) if !ok { assign = true break } cname := "cl" + cdd.gtc.uniqueId() ct := cdd.exprType(c) o := types.NewVar(c.Lbrace, cdd.gtc.pkg, cname, ct) cdd.gtc.pkg.Scope().Insert(o) acd := cdd.gtc.newCDD(o, VarDecl, cdd.il) acd.varDecl(new(bytes.Buffer), o.Type(), cdd.gtc.isGlobal(o), cname, c) cdd.InitNext = acd acds = append(acds, acd) w.WriteByte('\t') w.WriteString(name) w.WriteString(" = &") w.WriteString(cname) w.WriteString(";\n") default: assign = true } if assign { // Ordinary assignment gos to the init() function cdd.init = true w.WriteByte('\t') w.WriteString(name) w.WriteString(" = ") cdd.Expr(w, val, typ) w.WriteString(";\n") } cdd.copyInit(w) } return }