func (x *exporter) export(pkg *types.Package) error { x.pkg = pkg x.writeFunc = true exportsFile := packageExportsFile(x.context, pkg.Path()) err := os.MkdirAll(filepath.Dir(exportsFile), 0755) if err != nil && !os.IsExist(err) { return err } f2, err := os.Create(exportsFile) if err != nil { return err } defer f2.Close() x.writer = f2 x.write("package %s\n", pkg.Name()) for _, imp := range pkg.Imports() { x.write("\timport %s \"%s\"\n", imp.Name(), imp.Path()) } for _, n := range pkg.Scope().Names() { if obj := pkg.Scope().Lookup(n); obj != nil { x.exportObject(obj) } } x.write("$$") return nil }
func describePackage(o *Oracle, qpos *QueryPos, path []ast.Node) (*describePackageResult, error) { var description string var pkg *types.Package switch n := path[0].(type) { case *ast.ImportSpec: var pkgname *types.PkgName if n.Name != nil { pkgname = qpos.info.Defs[n.Name].(*types.PkgName) } else if p := qpos.info.Implicits[n]; p != nil { pkgname = p.(*types.PkgName) } description = fmt.Sprintf("import of package %q", pkgname.Pkg().Path()) pkg = pkgname.Pkg() case *ast.Ident: if _, isDef := path[1].(*ast.File); isDef { // e.g. package id pkg = qpos.info.Pkg description = fmt.Sprintf("definition of package %q", pkg.Path()) } else { // e.g. import id "..." // or id.F() pkg = qpos.info.ObjectOf(n).Pkg() description = fmt.Sprintf("reference to package %q", pkg.Path()) } default: // Unreachable? return nil, fmt.Errorf("unexpected AST for package: %T", n) } var members []*describeMember // NB: "unsafe" has no types.Package if pkg != nil { // Enumerate the accessible package members // in lexicographic order. for _, name := range pkg.Scope().Names() { if pkg == qpos.info.Pkg || ast.IsExported(name) { mem := pkg.Scope().Lookup(name) var methods []*types.Selection if mem, ok := mem.(*types.TypeName); ok { methods = accessibleMethods(mem.Type(), qpos.info.Pkg) } members = append(members, &describeMember{ mem, methods, }) } } } return &describePackageResult{o.fset, path[0], description, pkg, members}, nil }
func declTypeName(pkg *types.Package, name string) *types.TypeName { scope := pkg.Scope() if obj := scope.Lookup(name); obj != nil { return obj.(*types.TypeName) } obj := types.NewTypeName(token.NoPos, pkg, name, nil) // a named type may be referred to before the underlying type // is known - set it up types.NewNamed(obj, nil, nil) scope.Insert(obj) return obj }
func assocObjectPackages(pkg *types.Package, objectdata map[types.Object]*ObjectData) { for _, obj := range pkg.Scope().Entries { if data, ok := objectdata[obj]; ok { data.Package = pkg } else { objectdata[obj] = &ObjectData{Package: pkg} } } for _, pkg := range pkg.Imports() { assocObjectPackages(pkg, objectdata) } }
func describePackage(o *Oracle, qpos *QueryPos, path []ast.Node) (*describePackageResult, error) { var description string var pkg *types.Package switch n := path[0].(type) { case *ast.ImportSpec: // Most ImportSpecs have no .Name Ident so we can't // use ObjectOf. // We could use the types.Info.Implicits mechanism, // but it's easier just to look it up by name. description = "import of package " + n.Path.Value importPath, _ := strconv.Unquote(n.Path.Value) pkg = o.prog.ImportedPackage(importPath).Object case *ast.Ident: if _, isDef := path[1].(*ast.File); isDef { // e.g. package id pkg = qpos.info.Pkg description = fmt.Sprintf("definition of package %q", pkg.Path()) } else { // e.g. import id // or id.F() pkg = qpos.info.ObjectOf(n).Pkg() description = fmt.Sprintf("reference to package %q", pkg.Path()) } default: // Unreachable? return nil, fmt.Errorf("unexpected AST for package: %T", n) } var members []*describeMember // NB: "unsafe" has no types.Package if pkg != nil { // Enumerate the accessible package members // in lexicographic order. for _, name := range pkg.Scope().Names() { if pkg == qpos.info.Pkg || ast.IsExported(name) { mem := pkg.Scope().Lookup(name) var methods []*types.Selection if mem, ok := mem.(*types.TypeName); ok { methods = accessibleMethods(mem.Type(), qpos.info.Pkg) } members = append(members, &describeMember{ mem, methods, }) } } } return &describePackageResult{o.prog.Fset, path[0], description, pkg, members}, nil }
// 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() }
func (ctx *Context) getObjects(paths []string) ([]types.Object, []error) { var errors []error var objects []types.Object pathLoop: for _, path := range paths { buildPkg, err := build.Import(path, ".", 0) if err != nil { errors = append(errors, fmt.Errorf("Couldn't import %s: %s", path, err)) continue } fset := token.NewFileSet() var astFiles []*ast.File var pkg *types.Package if buildPkg.Goroot { // TODO what if the compiled package in GoRoot is // outdated? pkg, err = types.GcImport(ctx.allImports, path) if err != nil { errors = append(errors, fmt.Errorf("Couldn't import %s: %s", path, err)) continue } } else { if len(buildPkg.GoFiles) == 0 { errors = append(errors, fmt.Errorf("Couldn't parse %s: No (non cgo) Go files", path)) continue pathLoop } for _, file := range buildPkg.GoFiles { astFile, err := parseFile(fset, filepath.Join(buildPkg.Dir, file)) if err != nil { errors = append(errors, fmt.Errorf("Couldn't parse %s: %s", err)) continue pathLoop } astFiles = append(astFiles, astFile) } pkg, err = check(ctx, path, fset, astFiles) if err != nil { errors = append(errors, fmt.Errorf("Couldn't parse %s: %s\n", path, err)) continue pathLoop } } scope := pkg.Scope() for i := 0; i < scope.NumEntries(); i++ { obj := scope.At(i) objects = append(objects, obj) } } return objects, errors }
// export emits the exported package features. func (w *Walker) export(pkg *types.Package) { if *verbose { log.Println(pkg) } pop := w.pushScope("pkg " + pkg.Path()) w.current = pkg scope := pkg.Scope() for _, name := range scope.Names() { if ast.IsExported(name) { w.emitObj(scope.Lookup(name)) } } pop() }
func assocObjectPackages(pkg *types.Package, objectdata map[types.Object]*ObjectData) { scope := pkg.Scope() for _, name := range scope.Names() { obj := scope.Lookup(name) if data, ok := objectdata[obj]; ok { data.Package = pkg } else { objectdata[obj] = &ObjectData{Package: pkg} } } for _, pkg := range pkg.Imports() { assocObjectPackages(pkg, objectdata) } }
func FindImplentations(i *types.Interface, pkg *types.Package) []string { var names []string scope := pkg.Scope() allNames := scope.Names() for _, name := range allNames { obj := scope.Lookup(name) if typeName, ok := obj.(*types.TypeName); ok { if types.Implements(typeName.Type(), i) { names = append(names, typeName.Name()) } else { println(typeName.Name(), "cannot be an ensurer") println(types.NewMethodSet(typeName.Type()).String()) } } } return names }
func (p *importer) obj(pkg *types.Package) { var obj types.Object switch tag := p.int(); tag { case constTag: obj = types.NewConst(token.NoPos, pkg, p.string(), p.typ(), p.value()) case typeTag: // type object is added to scope via respective named type _ = p.typ().(*types.Named) return case varTag: obj = types.NewVar(token.NoPos, pkg, p.string(), p.typ()) case funcTag: obj = types.NewFunc(token.NoPos, pkg, p.string(), p.typ().(*types.Signature)) default: panic(fmt.Sprintf("unexpected object tag %d", tag)) } if alt := pkg.Scope().Insert(obj); alt != nil { panic(fmt.Sprintf("%s already declared", alt.Name())) } }
// 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: []byte(magic), pkgIndex: make(map[*types.Package]int), typIndex: make(map[types.Type]int), } // populate typIndex with predeclared types for _, t := range types.Typ[1:] { p.typIndex[t] = len(p.typIndex) } p.typIndex[types.Universe.Lookup("error").Type()] = 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 (c *exporter) Export(pkg *types.Package) error { c.pkg = pkg c.writeFunc = true f2, err := os.Create(c.compiler.packageExportsFile(pkg.Path())) if err != nil { return err } defer f2.Close() c.writer = f2 c.write("package %s\n", pkg.Name()) for _, imp := range c.pkg.Imports() { c.write("\timport %s \"%s\"\n", imp.Name(), imp.Path()) } for _, n := range pkg.Scope().Names() { if obj := pkg.Scope().Lookup(n); obj != nil { c.exportObject(obj) } } c.write("$$") return nil }
func newRuntimeInterface(pkg *types.Package, module llvm.Module, tm *llvmTypeMap, fr FuncResolver) (*runtimeInterface, error) { var ri runtimeInterface runtimeTypes := map[string]*runtimeType{ "eface": &ri.eface, "rtype": &ri.rtype, "uncommonType": &ri.uncommonType, "arrayType": &ri.arrayType, "chanType": &ri.chanType, "funcType": &ri.funcType, "iface": &ri.iface, "imethod": &ri.imethod, "interfaceType": &ri.interfaceType, "itab": &ri.itab, "mapiter": &ri.mapiter, "mapType": &ri.mapType, "method": &ri.method, "ptrType": &ri.ptrType, "sliceType": &ri.sliceType, "structField": &ri.structField, "structType": &ri.structType, "defers": &ri.defers, } for name, field := range runtimeTypes { obj := pkg.Scope().Lookup(name) if obj == nil { return nil, fmt.Errorf("no runtime type with name %s", name) } field.Type = obj.Type() field.llvm = tm.ToLLVM(field.Type) } intrinsics := map[string]**LLVMValue{ "chanclose": &ri.chanclose, "chanrecv": &ri.chanrecv, "chansend": &ri.chansend, "compareE2E": &ri.compareE2E, "convertE2I": &ri.convertE2I, "convertE2V": &ri.convertE2V, "mustConvertE2I": &ri.mustConvertE2I, "mustConvertE2V": &ri.mustConvertE2V, "convertI2E": &ri.convertI2E, "eqtyp": &ri.eqtyp, "Go": &ri.Go, "initdefers": &ri.initdefers, "llvm_stackrestore": &ri.stackrestore, "llvm_stacksave": &ri.stacksave, "llvm_setjmp": &ri.setjmp, "main": &ri.main, "printfloat": &ri.printfloat, "makechan": &ri.makechan, "makemap": &ri.makemap, "malloc": &ri.malloc, "mapaccess": &ri.mapaccess, "mapdelete": &ri.mapdelete, "mapiterinit": &ri.mapiterinit, "mapiternext": &ri.mapiternext, "maplookup": &ri.maplookup, "memcpy": &ri.memcpy, "memequal": &ri.memequal, "memset": &ri.memset, "panic_": &ri.panic_, "pushdefer": &ri.pushdefer, "recover_": &ri.recover_, "rundefers": &ri.rundefers, "chancap": &ri.chancap, "chanlen": &ri.chanlen, "maplen": &ri.maplen, "makeslice": &ri.makeslice, "selectdefault": &ri.selectdefault, "selectgo": &ri.selectgo, "selectinit": &ri.selectinit, "selectrecv": &ri.selectrecv, "selectsend": &ri.selectsend, "selectsize": &ri.selectsize, "sliceappend": &ri.sliceappend, "slicecopy": &ri.slicecopy, "sliceslice": &ri.sliceslice, "stringslice": &ri.stringslice, "strcat": &ri.strcat, "strcmp": &ri.strcmp, "strnext": &ri.strnext, "strrune": &ri.strrune, "strtorunes": &ri.strtorunes, "runestostr": &ri.runestostr, "streqalg": &ri.streqalg, "f32eqalg": &ri.f32eqalg, "f64eqalg": &ri.f64eqalg, "c64eqalg": &ri.c64eqalg, "c128eqalg": &ri.c128eqalg, } for name, field := range intrinsics { obj := pkg.Scope().Lookup(name) if obj == nil { return nil, fmt.Errorf("no runtime function with name %s", name) } *field = fr.ResolveFunc(obj.(*types.Func)) } return &ri, nil }
func Write(pkg *types.Package, out io.Writer, sizes types.Sizes) { fmt.Fprintf(out, "package %s\n", pkg.Name()) e := &exporter{pkg: pkg, imports: make(map[*types.Package]bool), out: out} for _, imp := range pkg.Imports() { e.addImport(imp) } for _, name := range pkg.Scope().Names() { obj := pkg.Scope().Lookup(name) _, isTypeName := obj.(*types.TypeName) if obj.Exported() || isTypeName { e.toExport = append(e.toExport, obj) } } for i := 0; i < len(e.toExport); i++ { switch o := e.toExport[i].(type) { case *types.TypeName: fmt.Fprintf(out, "type %s %s\n", e.makeName(o), e.makeType(o.Type().Underlying())) if _, isInterface := o.Type().Underlying().(*types.Interface); !isInterface { writeMethods := func(t types.Type) { methods := types.NewMethodSet(t) for i := 0; i < methods.Len(); i++ { m := methods.At(i) if len(m.Index()) > 1 { continue // method of embedded field } out.Write([]byte("func (? " + e.makeType(m.Recv()) + ") " + e.makeName(m.Obj()) + e.makeSignature(m.Type()) + "\n")) } } writeMethods(o.Type()) writeMethods(types.NewPointer(o.Type())) } case *types.Func: out.Write([]byte("func " + e.makeName(o) + e.makeSignature(o.Type()) + "\n")) case *types.Const: optType := "" basic, isBasic := o.Type().(*types.Basic) if !isBasic || basic.Info()&types.IsUntyped == 0 { optType = " " + e.makeType(o.Type()) } basic = o.Type().Underlying().(*types.Basic) var val string switch { case basic.Info()&types.IsBoolean != 0: val = strconv.FormatBool(exact.BoolVal(o.Val())) case basic.Info()&types.IsInteger != 0: if basic.Kind() == types.Uint64 { d, _ := exact.Uint64Val(o.Val()) val = fmt.Sprintf("%#x", d) break } d, _ := exact.Int64Val(o.Val()) if basic.Kind() == types.UntypedRune { switch { case d < 0 || d > unicode.MaxRune: val = fmt.Sprintf("('\\x00' + %d)", d) case d > 0xffff: val = fmt.Sprintf("'\\U%08x'", d) default: val = fmt.Sprintf("'\\u%04x'", d) } break } val = fmt.Sprintf("%#x", d) case basic.Info()&types.IsFloat != 0: f, _ := exact.Float64Val(o.Val()) val = strconv.FormatFloat(f, 'b', -1, 64) case basic.Info()&types.IsComplex != 0: r, _ := exact.Float64Val(exact.Real(o.Val())) i, _ := exact.Float64Val(exact.Imag(o.Val())) val = fmt.Sprintf("(%s+%si)", strconv.FormatFloat(r, 'b', -1, 64), strconv.FormatFloat(i, 'b', -1, 64)) case basic.Info()&types.IsString != 0: val = fmt.Sprintf("%#v", exact.StringVal(o.Val())) default: panic("Unhandled constant type: " + basic.String()) } out.Write([]byte("const " + e.makeName(o) + optType + " = " + val + "\n")) case *types.Var: out.Write([]byte("var " + e.makeName(o) + " " + e.makeType(o.Type()) + "\n")) default: panic(fmt.Sprintf("Unhandled object: %T\n", o)) } } fmt.Fprintf(out, "$$\n") }
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") }
func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) { // collect objects by kind var ( consts []*types.Const typez []*types.TypeName // types without methods typem []*types.TypeName // types with methods vars []*types.Var funcs []*types.Func builtins []*types.Builtin ) scope := pkg.Scope() for _, name := range scope.Names() { obj := scope.Lookup(name) if !filter(obj) { continue } switch obj := obj.(type) { case *types.Const: consts = append(consts, obj) case *types.TypeName: if named, _ := obj.Type().(*types.Named); named != nil && named.NumMethods() > 0 { typem = append(typem, obj) } 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) } } p.printf("package %s // %q\n\n", pkg.Name(), pkg.Path()) if len(consts) > 0 { p.print("const (\n") p.indent++ for _, obj := range consts { p.printObj(obj) p.print("\n") } p.indent-- p.print(")\n\n") } if len(vars) > 0 { p.print("var (\n") p.indent++ for _, obj := range vars { p.printObj(obj) p.print("\n") } p.indent-- p.print(")\n\n") } if len(typez) > 0 { p.print("type (\n") p.indent++ for _, obj := range typez { p.printf("%s ", obj.Name()) p.writeType(p.pkg, obj.Type().Underlying()) p.print("\n") } p.indent-- p.print(")\n\n") } for _, obj := range typem { p.printf("type %s ", obj.Name()) typ := obj.Type().(*types.Named) p.writeType(p.pkg, typ.Underlying()) p.print("\n") for i, n := 0, typ.NumMethods(); i < n; i++ { p.printFunc(typ.Method(i)) p.print("\n") } p.print("\n") } for _, obj := range funcs { p.printFunc(obj) p.print("\n") } // TODO(gri) better handling of builtins (package unsafe only) for _, obj := range builtins { p.printf("func %s() // builtin\n", obj.Name()) } p.print("\n") }
// FunctionType = ParamList ResultList . func (p *parser) parseFunctionType(pkg *types.Package) *types.Signature { params, isVariadic := p.parseParamList(pkg) results := p.parseResultList(pkg) return types.NewSignature(pkg.Scope(), nil, params, results, isVariadic) }
// funcSig returns the signature of the specified package-level function. func funcSig(pkg *types.Package, name string) *types.Signature { if f, ok := pkg.Scope().Lookup(name).(*types.Func); ok { return f.Type().(*types.Signature) } return nil }