// generate generates offline constraints for the entire program. func (a *analysis) generate() { start("Constraint generation") if a.log != nil { fmt.Fprintln(a.log, "==== Generating constraints") } // 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() if a.config.BuildCallGraph { a.result.CallGraph = callgraph.New(root.fn) } // Create nodes and constraints for all methods of all types // that are dynamically accessible via reflection or interfaces. for _, T := range a.prog.RuntimeTypes() { 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)[:] T := types.NewSlice(types.Typ[types.String]) obj := a.addNodes(sliceToArray(T), "<command-line args>") a.endObject(obj, nil, "<command-line args>") a.addressOf(T, a.objectNode(nil, os.Var("Args")), obj) } // Discard generation state, to avoid confusion after node renumbering. a.panicNode = 0 a.globalval = nil a.localval = nil a.localobj = nil stop("Constraint generation") }
// createParams creates parameters for wrapper method fn based on its // Signature.Params, which do not include the receiver. // start is the index of the first regular parameter to use. // func createParams(fn *Function, start int) { var last *Parameter tparams := fn.Signature.Params() for i, n := start, tparams.Len(); i < n; i++ { last = fn.addParamObj(tparams.At(i)) } if fn.Signature.Variadic() { last.typ = types.NewSlice(last.typ) } }
// Type = // BasicType | TypeName | ArrayType | SliceType | StructType | // PointerType | FuncType | InterfaceType | MapType | ChanType | // "(" Type ")" . // // BasicType = ident . // TypeName = ExportedName . // SliceType = "[" "]" Type . // PointerType = "*" Type . // FuncType = "func" Signature . // func (p *parser) parseType() types.Type { switch p.tok { case scanner.Ident: switch p.lit { default: return p.parseBasicType() case "struct": return p.parseStructType() case "func": // FuncType p.next() return p.parseSignature(nil) case "interface": return p.parseInterfaceType() case "map": return p.parseMapType() case "chan": return p.parseChanType() } case '@': // TypeName pkg, name := p.parseExportedName() return declTypeName(pkg, name).Type() case '[': p.next() // look ahead if p.tok == ']' { // SliceType p.next() return types.NewSlice(p.parseType()) } return p.parseArrayType() case '*': // PointerType p.next() return types.NewPointer(p.parseType()) case '<': return p.parseChanType() case '(': // "(" Type ")" p.next() typ := p.parseType() p.expect(')') return typ } p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit) return nil }
// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] . // func (p *parser) parseParameter() (par *types.Var, isVariadic bool) { _, name := p.parseName(false) // remove gc-specific parameter numbering if i := strings.Index(name, "·"); i >= 0 { name = name[:i] } if p.tok == '.' { p.expectSpecial("...") isVariadic = true } typ := p.parseType() if isVariadic { typ = types.NewSlice(typ) } // ignore argument tag (e.g. "noescape") if p.tok == scanner.String { p.next() } // TODO(gri) should we provide a package? par = types.NewVar(token.NoPos, nil, name, typ) return }
func ext۰reflect۰SliceOf(fr *frame, args []value) value { // Signature: func (t reflect.rtype) Type return makeReflectType(rtype{types.NewSlice(args[0].(iface).v.(rtype).t)}) }