func (g *goGen) typeString(typ types.Type) string { pkg := g.pkg switch t := typ.(type) { case *types.Named: obj := t.Obj() if obj.Pkg() == nil { // e.g. error type is *types.Named. return types.TypeString(typ, types.RelativeTo(pkg)) } if obj.Pkg() != g.pkg { g.errorf("type %s not defined in package %s", t, g.pkg) } switch t.Underlying().(type) { case *types.Interface, *types.Struct: return fmt.Sprintf("%s.%s", pkg.Name(), types.TypeString(typ, types.RelativeTo(pkg))) default: g.errorf("unsupported named type %s / %T", t, t) } case *types.Pointer: switch t := t.Elem().(type) { case *types.Named: return fmt.Sprintf("*%s", g.typeString(t)) default: g.errorf("not yet supported, pointer type %s / %T", t, t) } default: return types.TypeString(typ, types.RelativeTo(pkg)) } return "" }
func formatMember(obj types.Object, maxname int) string { 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.Pkg(), obj.Type()), obj.Val().String()) case *types.Func: fmt.Fprintf(&buf, " %s", types.TypeString(obj.Pkg(), obj.Type())) 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.Pkg(), obj.Type().Underlying())) } else { fmt.Fprintf(&buf, " %s", abbrev) } case *types.Var: fmt.Fprintf(&buf, " %s", types.TypeString(obj.Pkg(), obj.Type())) } return buf.String() }
//!+ func PrintSkeleton(pkg *types.Package, ifacename, concname string) error { obj := pkg.Scope().Lookup(ifacename) if obj == nil { return fmt.Errorf("%s.%s not found", pkg.Path(), ifacename) } if _, ok := obj.(*types.TypeName); !ok { return fmt.Errorf("%v is not a named type", obj) } iface, ok := obj.Type().Underlying().(*types.Interface) if !ok { return fmt.Errorf("type %v is a %T, not an interface", obj, obj.Type().Underlying()) } // Use first letter of type name as receiver parameter. if !isValidIdentifier(concname) { return fmt.Errorf("invalid concrete type name: %q", concname) } r, _ := utf8.DecodeRuneInString(concname) fmt.Printf("// *%s implements %s.%s.\n", concname, pkg.Path(), ifacename) fmt.Printf("type %s struct{}\n", concname) mset := types.NewMethodSet(iface) for i := 0; i < mset.Len(); i++ { meth := mset.At(i).Obj() sig := types.TypeString(meth.Type(), (*types.Package).Name) fmt.Printf("func (%c *%s) %s%s {\n\tpanic(\"unimplemented\")\n}\n", r, concname, meth.Name(), strings.TrimPrefix(sig, "func")) } return nil }
func TestDemo(ot *testing.T) { importPath := "github.com/bronze1man/kmg/kmgGoSource" kmgCmd.MustRun("kmg go test -i " + importPath) pkgDir := kmgConfig.DefaultEnv().MustGetPathFromImportPath(importPath) fset := token.NewFileSet() astPkgMap, err := parser.ParseDir(fset, pkgDir, nil, 0) if err != nil { panic(err) } astPkg := astPkgMap["kmgGoSource_test"] astFileList := []*ast.File{} for _, file := range astPkg.Files { astFileList = append(astFileList, file) } //os.Chdir(kmgConfig.DefaultEnv().ProjectPath) pkg, err := types.Check(pkgDir, fset, astFileList) if err != nil { panic(err) } funcA := pkg.Scope().Lookup("FuncA") recvPkg := types.NewPackage("github.com/bronze1man/kmg/kmgGoSource", "kmgGoSource") kmgDebug.Println(types.TypeString(recvPkg, funcA.Type())) funTypParams := funcA.Type().(*types.Signature).Params() for i := 0; i < funTypParams.Len(); i++ { kmgDebug.Println(funTypParams.At(i).Name()) kmgDebug.Println(funTypParams.At(i).Type().String()) } //for _,p:=range funcA.Type().(*types.Signature).Params(). //kmgDebug.Println(funcA.Type().(*types.Signature).Params().String()) }
func main() { flag.Parse() exitStatus := 0 importPaths := gotool.ImportPaths(flag.Args()) if len(importPaths) == 0 { importPaths = []string{"."} } for _, pkgPath := range importPaths { visitor := &visitor{ info: types.Info{ Types: make(map[ast.Expr]types.TypeAndValue), Defs: make(map[*ast.Ident]types.Object), Selections: make(map[*ast.SelectorExpr]*types.Selection), }, m: make(map[types.Type]map[string]int), skip: make(map[types.Type]struct{}), } fset, astFiles := check.ASTFilesForPackage(pkgPath, *loadTestFiles) imp := importer.New() // Preliminary cgo support. imp.Config = importer.Config{UseGcFallback: true} config := types.Config{Import: imp.Import} var err error visitor.pkg, err = config.Check(pkgPath, fset, astFiles, &visitor.info) if err != nil { fmt.Fprintf(os.Stderr, "%s: %v\n", pkgPath, err) continue } for _, f := range astFiles { ast.Walk(visitor, f) } for t := range visitor.m { if _, skip := visitor.skip[t]; skip { continue } for fieldName, v := range visitor.m[t] { if !*reportExported && ast.IsExported(fieldName) { continue } if v == 0 { field, _, _ := types.LookupFieldOrMethod(t, false, visitor.pkg, fieldName) if fieldName == "XMLName" { if named, ok := field.Type().(*types.Named); ok && named.Obj().Pkg().Path() == "encoding/xml" { continue } } pos := fset.Position(field.Pos()) fmt.Printf("%s: %s:%d:%d: %s.%s\n", pkgPath, pos.Filename, pos.Line, pos.Column, types.TypeString(t, nil), fieldName, ) exitStatus = 1 } } } } os.Exit(exitStatus) }
func typeString(ty types.Type, pkg *types.Package) string { ret := types.TypeString(ty, types.RelativeTo(pkg)) parts := strings.Split(ret, "/") prefix := "" if len(parts) > 1 { for _, r := range parts[0] { if r == '.' || unicode.IsLetter(r) { break } prefix += string(r) } } return prefix + parts[len(parts)-1] }
func (r *freevarsResult) display(printf printfFunc) { if len(r.refs) == 0 { printf(r.qpos, "No free identifiers.") } else { printf(r.qpos, "Free identifiers:") for _, ref := range r.refs { // Avoid printing "type T T". var typstr string if ref.kind != "type" { typstr = " " + types.TypeString(r.qpos.info.Pkg, ref.typ) } printf(ref.obj, "%s %s%s", ref.kind, ref.ref, typstr) } } }
// prettyFunc pretty-prints fn for the user interface. // TODO(adonovan): return HTML so we have more markup freedom. func prettyFunc(this *types.Package, fn *ssa.Function) string { if fn.Parent() != nil { return fmt.Sprintf("%s in %s", types.TypeString(fn.Signature, types.RelativeTo(this)), prettyFunc(this, fn.Parent())) } if fn.Synthetic != "" && fn.Name() == "init" { // (This is the actual initializer, not a declared 'func init'). if fn.Pkg.Pkg == this { return "package initializer" } return fmt.Sprintf("%q package initializer", fn.Pkg.Pkg.Path()) } return fn.RelString(this) }
// typeStr returns the type string to be used when using the // given type. It adds any needed import paths to the given // imports map (map from package path to package id). func typeStr(t types.Type, imports map[string]string) string { if t == nil { return "" } qualify := func(pkg *types.Package) string { if name := imports[pkg.Path()]; name != "" { return name } name := pkg.Name() // Make sure we're not duplicating the name. // TODO if we are, make a new non-duplicated version. for oldPkg, oldName := range imports { if oldName == name { panic(errgo.Newf("duplicate package name %s vs %s", pkg.Path(), oldPkg)) } } imports[pkg.Path()] = name return name } return types.TypeString(t, qualify) }
func loadStoreSuffix(T types.Type, hasParameters bool) string { if bt, ok := T.Underlying().(*types.Basic); ok { switch bt.Kind() { case types.Bool, types.Int8, types.Int16, types.Int64, types.Uint16, types.Uint64, types.Uintptr, types.Float32, types.Float64, types.Complex64, types.Complex128, types.String: return "_" + types.TypeString(T, nil /* TODO should be?: (*types.Package).Name*/) + "(" case types.Uint8: // to avoid "byte" return "_uint8(" case types.Int, types.Int32: // for int and to avoid "rune" return "_int32(" case types.Uint, types.Uint32: return "_uint32(" } } if _, ok := T.Underlying().(*types.Array); ok { ret := fmt.Sprintf("_object(%d", haxeStdSizes.Sizeof(T)) if hasParameters { ret += "," } return ret } if _, ok := T.Underlying().(*types.Struct); ok { ret := fmt.Sprintf("_object(%d", haxeStdSizes.Sizeof(T)) if hasParameters { ret += "," } return ret } return "(" // no suffix, so some dynamic type }
func printResult(res *rta.Result, from *types.Package) string { var buf bytes.Buffer writeSorted := func(ss []string) { sort.Strings(ss) for _, s := range ss { fmt.Fprintf(&buf, " %s\n", s) } } buf.WriteString("Dynamic calls\n") var edges []string callgraph.GraphVisitEdges(res.CallGraph, func(e *callgraph.Edge) error { if strings.Contains(e.Description(), "dynamic") { edges = append(edges, fmt.Sprintf("%s --> %s", e.Caller.Func.RelString(from), e.Callee.Func.RelString(from))) } return nil }) writeSorted(edges) buf.WriteString("Reachable functions\n") var reachable []string for f := range res.Reachable { reachable = append(reachable, f.RelString(from)) } writeSorted(reachable) buf.WriteString("Reflect types\n") var rtypes []string res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) { if value == false { // accessible to reflection rtypes = append(rtypes, types.TypeString(from, key)) } }) writeSorted(rtypes) return strings.TrimSpace(buf.String()) }
func relType(t types.Type, from *types.Package) string { return types.TypeString(t, types.RelativeTo(from)) }
// DIType maps a Go type to DIType debug metadata value. func (d *DIBuilder) DIType(t types.Type) llvm.Value { return d.typeDebugDescriptor(t, types.TypeString(nil, t)) }
// TypeString prints type T relative to the query position. func (qpos *QueryPos) TypeString(T types.Type) string { return types.TypeString(qpos.info.Pkg, T) }
func (a *analysis) namedType(obj *types.TypeName, implements map[*types.Named]implementsFacts) { qualifier := types.RelativeTo(obj.Pkg()) T := obj.Type().(*types.Named) v := &TypeInfoJSON{ Name: obj.Name(), Size: sizes.Sizeof(T), Align: sizes.Alignof(T), Methods: []anchorJSON{}, // (JS wants non-nil) } // addFact adds the fact "is implemented by T" (by) or // "implements T" (!by) to group. addFact := func(group *implGroupJSON, T types.Type, by bool) { Tobj := deref(T).(*types.Named).Obj() var byKind string if by { // Show underlying kind of implementing type, // e.g. "slice", "array", "struct". s := reflect.TypeOf(T.Underlying()).String() byKind = strings.ToLower(strings.TrimPrefix(s, "*types.")) } group.Facts = append(group.Facts, implFactJSON{ ByKind: byKind, Other: anchorJSON{ Href: a.posURL(Tobj.Pos(), len(Tobj.Name())), Text: types.TypeString(T, qualifier), }, }) } // IMPLEMENTS if r, ok := implements[T]; ok { if isInterface(T) { // "T is implemented by <conc>" ... // "T is implemented by <iface>"... // "T implements <iface>"... group := implGroupJSON{ Descr: types.TypeString(T, qualifier), } // Show concrete types first; use two passes. for _, sub := range r.to { if !isInterface(sub) { addFact(&group, sub, true) } } for _, sub := range r.to { if isInterface(sub) { addFact(&group, sub, true) } } for _, super := range r.from { addFact(&group, super, false) } v.ImplGroups = append(v.ImplGroups, group) } else { // T is concrete. if r.from != nil { // "T implements <iface>"... group := implGroupJSON{ Descr: types.TypeString(T, qualifier), } for _, super := range r.from { addFact(&group, super, false) } v.ImplGroups = append(v.ImplGroups, group) } if r.fromPtr != nil { // "*C implements <iface>"... group := implGroupJSON{ Descr: "*" + types.TypeString(T, qualifier), } for _, psuper := range r.fromPtr { addFact(&group, psuper, false) } v.ImplGroups = append(v.ImplGroups, group) } } } // METHOD SETS for _, sel := range typeutil.IntuitiveMethodSet(T, &a.prog.MethodSets) { meth := sel.Obj().(*types.Func) pos := meth.Pos() // may be 0 for error.Error v.Methods = append(v.Methods, anchorJSON{ Href: a.posURL(pos, len(meth.Name())), Text: types.SelectionString(sel, qualifier), }) } // Since there can be many specs per decl, we // can't attach the link to the keyword 'type' // (as we do with 'func'); we use the Ident. fi, offset := a.fileAndOffset(obj.Pos()) fi.addLink(aLink{ start: offset, end: offset + len(obj.Name()), title: fmt.Sprintf("type info for %s", obj.Name()), onclick: fmt.Sprintf("onClickTypeInfo(%d)", fi.addData(v)), }) // Add info for exported package-level types to the package info. if obj.Exported() && isPackageLevel(obj) { // TODO(adonovan): Path is not unique! // It is possible to declare a non-test package called x_test. a.result.pkgInfo(obj.Pkg().Path()).addType(v) } }
func (sym *symtab) typename(t types.Type, pkg *types.Package) string { if pkg == nil { return types.TypeString(t, nil) } return types.TypeString(t, types.RelativeTo(pkg)) }
func (s symbol) gofmt() string { return types.TypeString( s.GoType(), func(*types.Package) string { return s.pkgname() }, ) }
func relType(t types.Type, from *types.Package) string { return types.TypeString(from, t) }
func main() { flag.Parse() exitStatus := 0 importPaths := gotool.ImportPaths(flag.Args()) if len(importPaths) == 0 { importPaths = []string{"."} } ctx := build.Default for _, pkgPath := range importPaths { visitor := &visitor{ m: make(map[types.Type]map[string]int), skip: make(map[types.Type]struct{}), } loadcfg := loader.Config{ Build: &ctx, } rest, err := loadcfg.FromArgs([]string{pkgPath}, *loadTestFiles) if err != nil { fmt.Fprintf(os.Stderr, "could not parse arguments: %s", err) continue } if len(rest) > 0 { fmt.Fprintf(os.Stderr, "unhandled extra arguments: %v", rest) continue } program, err := loadcfg.Load() if err != nil { fmt.Fprintf(os.Stderr, "could not type check: %s", err) continue } pkg := program.InitialPackages()[0] visitor.prog = program visitor.pkg = pkg for _, f := range pkg.Files { ast.Walk(visitor, f) } for t := range visitor.m { if _, skip := visitor.skip[t]; skip { continue } for fieldName, v := range visitor.m[t] { if !*reportExported && ast.IsExported(fieldName) { continue } if v == 0 { field, _, _ := types.LookupFieldOrMethod(t, false, pkg.Pkg, fieldName) if fieldName == "XMLName" { if named, ok := field.Type().(*types.Named); ok && named.Obj().Pkg().Path() == "encoding/xml" { continue } } pos := program.Fset.Position(field.Pos()) fmt.Printf("%s: %s:%d:%d: %s.%s\n", pkgPath, pos.Filename, pos.Line, pos.Column, types.TypeString(t, nil), fieldName, ) exitStatus = 1 } } } } os.Exit(exitStatus) }
func (g *goGen) genFuncBody(f Func) { sig := f.Signature() results := sig.Results() for i := range results { if i > 0 { g.Printf(", ") } g.Printf("_gopy_%03d", i) } if len(results) > 0 { g.Printf(" := ") } g.Printf("%s.%s(", g.pkg.Name(), f.GoName()) args := sig.Params() for i, arg := range args { tail := "" if i+1 < len(args) { tail = ", " } head := arg.Name() if arg.needWrap() { head = fmt.Sprintf( "*(*%s)(unsafe.Pointer(%s))", types.TypeString( arg.GoType(), func(*types.Package) string { return g.pkg.Name() }, ), arg.Name(), ) } g.Printf("%s%s", head, tail) } g.Printf(")\n") if len(results) <= 0 { return } for i, res := range results { if !res.needWrap() { continue } g.Printf("cgopy_incref(unsafe.Pointer(&_gopy_%03d))\n", i) } g.Printf("return ") for i, res := range results { if i > 0 { g.Printf(", ") } // if needWrap(res.GoType()) { // g.Printf("") // } if res.needWrap() { g.Printf("%s(unsafe.Pointer(&", res.sym.cgoname) } g.Printf("_gopy_%03d", i) if res.needWrap() { g.Printf("))") } } g.Printf("\n") }
// TypeString prints type T relative to the query position. func (qpos *queryPos) typeString(T types.Type) string { return types.TypeString(T, types.RelativeTo(qpos.info.Pkg)) }
func getTypeString(t types.Type) string { return types.TypeString(t, func(*types.Package) string { return " " }) }