// pkgString returns a string representation of a package's exported interface. func pkgString(pkg *types.Package) string { var buf bytes.Buffer fmt.Fprintf(&buf, "package %s\n", pkg.Name()) scope := pkg.Scope() for _, name := range scope.Names() { if exported(name) { obj := scope.Lookup(name) buf.WriteString(obj.String()) switch obj := obj.(type) { case *types.Const: // For now only print constant values if they are not float // or complex. This permits comparing go/types results with // gc-generated gcimported package interfaces. info := obj.Type().Underlying().(*types.Basic).Info() if info&types.IsFloat == 0 && info&types.IsComplex == 0 { fmt.Fprintf(&buf, " = %s", obj.Val()) } case *types.TypeName: // Print associated methods. // Basic types (e.g., unsafe.Pointer) have *types.Basic // type rather than *types.Named; so we need to check. if typ, _ := obj.Type().(*types.Named); typ != nil { if n := typ.NumMethods(); n > 0 { // Sort methods by name so that we get the // same order independent of whether the // methods got imported or coming directly // for the source. // TODO(gri) This should probably be done // in go/types. list := make([]*types.Func, n) for i := 0; i < n; i++ { list[i] = typ.Method(i) } sort.Sort(byName(list)) buf.WriteString("\nmethods (\n") for _, m := range list { fmt.Fprintf(&buf, "\t%s\n", m) } buf.WriteString(")") } } } buf.WriteByte('\n') } } return buf.String() }
// NewPackageDef creates a new Def that represents a Go package. func (g *Grapher) NewPackageDef(pkgInfo *loader.PackageInfo, pkg *types.Package) (*Def, error) { var pkgDir string if len(pkgInfo.Files) > 0 { pkgDir = filepath.Dir(g.program.Fset.Position(pkgInfo.Files[0].Package).Filename) } return &Def{ Name: pkg.Name(), DefKey: &DefKey{PackageImportPath: pkg.Path(), Path: []string{}}, File: pkgDir, DefInfo: definfo.DefInfo{ Exported: true, PkgName: pkg.Name(), Kind: definfo.Package, }, }, nil }
func defaultFileName(lang string, pkg *types.Package) string { if *outdir == "" { return "" } switch lang { case "java": firstRune, size := utf8.DecodeRuneInString(pkg.Name()) className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:] return filepath.Join(*outdir, className+".java") case "go": return filepath.Join(*outdir, "go_"+pkg.Name()+".go") case "objc": firstRune, size := utf8.DecodeRuneInString(pkg.Name()) className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:] return filepath.Join(*outdir, "Go"+className+".m") } errorf("unknown target language: %q", lang) os.Exit(exitStatus) return "" }
func (p *exporter) pkg(pkg *types.Package) { if trace { p.tracef("package { ") defer p.tracef("} ") } if pkg == nil { panic("unexpected nil pkg") } // if the package was seen before, write its index (>= 0) if i, ok := p.pkgIndex[pkg]; ok { p.int(i) return } p.pkgIndex[pkg] = len(p.pkgIndex) // otherwise, write the package tag (< 0) and package data p.int(packageTag) p.string(pkg.Name()) p.string(pkg.Path()) }
// ExportData serializes the interface (exported package objects) // of package pkg and returns the corresponding data. The export // format is described elsewhere (TODO). func ExportData(pkg *types.Package) []byte { p := exporter{ data: append([]byte(magic), format()), pkgIndex: make(map[*types.Package]int), typIndex: make(map[types.Type]int), } // populate typIndex with predeclared types for _, t := range predeclared { p.typIndex[t] = len(p.typIndex) } if trace { p.tracef("export %s\n", pkg.Name()) defer p.tracef("\n") } p.string(version) p.pkg(pkg) // collect exported objects from package scope var list []types.Object scope := pkg.Scope() for _, name := range scope.Names() { if exported(name) { list = append(list, scope.Lookup(name)) } } // write objects p.int(len(list)) for _, obj := range list { p.obj(obj) } return p.data }
func testExportImport(t *testing.T, pkg0 *types.Package, path string) (size, gcsize int) { data := ExportData(pkg0) size = len(data) imports := make(map[string]*types.Package) n, pkg1, err := ImportData(imports, data) if err != nil { t.Errorf("package %s: import failed: %s", pkg0.Name(), err) return } if n != size { t.Errorf("package %s: not all input data consumed", pkg0.Name()) return } s0 := pkgString(pkg0) s1 := pkgString(pkg1) if s1 != s0 { t.Errorf("package %s: \nimport got:\n%s\nwant:\n%s\n", pkg0.Name(), s1, s0) } // If we have a standard library, compare also against the gcimported package. if path == "" { return // not std library } gcdata, err := gcExportData(path) if err != nil { if pkg0.Name() == "main" { return // no export data present for main package } t.Errorf("package %s: couldn't get export data: %s", pkg0.Name(), err) } gcsize = len(gcdata) imports = make(map[string]*types.Package) pkg2, err := gcImportData(imports, gcdata, path) if err != nil { t.Errorf("package %s: gcimport failed: %s", pkg0.Name(), err) return } s2 := pkgString(pkg2) if s2 != s0 { t.Errorf("package %s: \ngcimport got:\n%s\nwant:\n%s\n", pkg0.Name(), s2, s0) } return }
func (sym *symtab) addType(obj types.Object, t types.Type) { fn := sym.typename(t, nil) n := sym.typename(t, sym.pkg) var pkg *types.Package if obj != nil { pkg = obj.Pkg() } id := n if pkg != nil { id = pkg.Name() + "_" + n } kind := skType switch typ := t.(type) { case *types.Basic: kind |= skBasic styp := sym.symtype(typ) if styp == nil { panic(fmt.Errorf("builtin type not already known [%s]!", n)) } case *types.Array: sym.addArrayType(pkg, obj, t, kind, id, n) case *types.Slice: sym.addSliceType(pkg, obj, t, kind, id, n) case *types.Signature: sym.addSignatureType(pkg, obj, t, kind, id, n) case *types.Named: kind |= skNamed switch typ := typ.Underlying().(type) { case *types.Struct: sym.addStructType(pkg, obj, t, kind, id, n) case *types.Basic: bsym := sym.symtype(typ) sym.syms[fn] = &symbol{ gopkg: pkg, goobj: obj, gotyp: t, kind: kind | skBasic, id: id, goname: n, cgoname: "cgo_type_" + id, cpyname: "cpy_type_" + id, pyfmt: bsym.pyfmt, pybuf: bsym.pybuf, pysig: "object", c2py: "cgopy_cnv_c2py_" + id, py2c: "cgopy_cnv_py2c_" + id, pychk: fmt.Sprintf("cpy_func_%[1]s_check(%%s)", id), } case *types.Array: sym.addArrayType(pkg, obj, t, kind, id, n) case *types.Slice: sym.addSliceType(pkg, obj, t, kind, id, n) case *types.Signature: sym.addSignatureType(pkg, obj, t, kind, id, n) case *types.Pointer: sym.addPointerType(pkg, obj, t, kind, id, n) case *types.Interface: sym.addInterfaceType(pkg, obj, t, kind, id, n) default: panic(fmt.Errorf("unhandled named-type: [%T]\n%#v\n", obj, t)) } // add methods for i := 0; i < typ.NumMethods(); i++ { m := typ.Method(i) if !m.Exported() { continue } if true { mid := id + "_" + m.Name() mname := m.Name() sym.addMethod(pkg, m, m.Type(), skFunc, mid, mname) } } case *types.Pointer: sym.addPointerType(pkg, obj, t, kind, id, n) case *types.Map: sym.addMapType(pkg, obj, t, kind, id, n) default: panic(fmt.Errorf("unhandled obj [%T]\ntype [%#v]", obj, t)) } }
func (o *Object) setPkg(p *types.Package) { if p != nil { o.PkgPath = p.Path() o.PkgName = p.Name() } }
func (p *Processor) ProcessTypesPkg(typesPkg *types.Package) (*Package, error) { pkg := &Package{Name: typesPkg.Name()} p.processPackage(pkg, typesPkg) return pkg, nil }
func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) { // collect objects by kind var ( consts []*types.Const typem []*types.Named // non-interface types with methods typez []*types.TypeName // interfaces or types without methods vars []*types.Var funcs []*types.Func builtins []*types.Builtin methods = make(map[*types.Named][]*types.Selection) // method sets for named types ) scope := pkg.Scope() for _, name := range scope.Names() { obj := scope.Lookup(name) if obj.Exported() { // collect top-level exported and possibly filtered objects if filter == nil || filter(obj) { switch obj := obj.(type) { case *types.Const: consts = append(consts, obj) case *types.TypeName: // group into types with methods and types without if named, m := methodsFor(obj); named != nil { typem = append(typem, named) methods[named] = m } else { typez = append(typez, obj) } case *types.Var: vars = append(vars, obj) case *types.Func: funcs = append(funcs, obj) case *types.Builtin: // for unsafe.Sizeof, etc. builtins = append(builtins, obj) } } } else if filter == nil { // no filtering: collect top-level unexported types with methods if obj, _ := obj.(*types.TypeName); obj != nil { // see case *types.TypeName above if named, m := methodsFor(obj); named != nil { typem = append(typem, named) methods[named] = m } } } } p.printf("package %s // %q\n", pkg.Name(), pkg.Path()) p.printDecl("const", len(consts), func() { for _, obj := range consts { p.printObj(obj) p.print("\n") } }) p.printDecl("var", len(vars), func() { for _, obj := range vars { p.printObj(obj) p.print("\n") } }) p.printDecl("type", len(typez), func() { for _, obj := range typez { p.printf("%s ", obj.Name()) p.writeType(p.pkg, obj.Type().Underlying()) p.print("\n") } }) // non-interface types with methods for _, named := range typem { first := true if obj := named.Obj(); obj.Exported() { if first { p.print("\n") first = false } p.printf("type %s ", obj.Name()) p.writeType(p.pkg, named.Underlying()) p.print("\n") } for _, m := range methods[named] { if obj := m.Obj(); obj.Exported() { if first { p.print("\n") first = false } p.printFunc(m.Recv(), obj.(*types.Func)) p.print("\n") } } } if len(funcs) > 0 { p.print("\n") for _, obj := range funcs { p.printFunc(nil, obj) p.print("\n") } } // TODO(gri) better handling of builtins (package unsafe only) if len(builtins) > 0 { p.print("\n") for _, obj := range builtins { p.printf("func %s() // builtin\n", obj.Name()) } } p.print("\n") }