func (w *PkgWalker) LookupStructFromField(info *types.Info, cursorPkg *types.Package, cursorObj types.Object, cursorPos token.Pos) types.Object { if info == nil { conf := &PkgConfig{ IgnoreFuncBodies: true, AllowBinary: true, Info: &types.Info{ Defs: make(map[*ast.Ident]types.Object), }, } w.imported[cursorPkg.Path()] = nil pkg, _ := w.Import("", cursorPkg.Path(), conf) if pkg != nil { info = conf.Info } } for _, obj := range info.Defs { if obj == nil { continue } if _, ok := obj.(*types.TypeName); ok { if t, ok := obj.Type().Underlying().(*types.Struct); ok { for i := 0; i < t.NumFields(); i++ { if t.Field(i).Pos() == cursorPos { return obj } } } } } return nil }
func (e *exporter) addImport(pkg *types.Package) { if _, found := e.imports[pkg]; found { return } fmt.Fprintf(e.out, "import %s \"%s\"\n", pkg.Name(), pkg.Path()) e.imports[pkg] = true }
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 }
// pkgpath returns a package path suitable for naming symbols. func pkgpath(p *types.Package) string { path := p.Path() name := p.Name() if path == "" || name == "main" { path = p.Name() } return path }
// Export generates a file containing package export data // suitable for importing with Importer.Import. func Export(ctx *build.Context, pkg *types.Package) error { exportsPath := packageExportsFile(ctx, pkg.Path()) err := os.MkdirAll(filepath.Dir(exportsPath), 0755) if err != nil && !os.IsExist(err) { return err } tracef("Writing import data to %q", exportsPath) return ioutil.WriteFile(exportsPath, importer.ExportData(pkg), 0644) }
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 typePackageToJson(p *types.Package) interface{} { if p == nil { return nil } else { return struct { Isa, Name, ImportPath string }{ "Package", p.Name(), p.Path(), } } }
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 }
func (r *renamer) checkExport(id *ast.Ident, pkg *types.Package, from types.Object) bool { // Reject cross-package references if r.to is unexported. // (Such references may be qualified identifiers or field/method // selections.) if !ast.IsExported(r.to) && pkg != from.Pkg() { r.errorf(from.Pos(), "renaming this %s %q to %q would make it unexported", objectKind(from), from.Name(), r.to) r.errorf(id.Pos(), "\tbreaking references from packages such as %q", pkg.Path()) return false } return true }
// 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 (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()) }
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 isJsPackage(pkg *types.Package) bool { return pkg != nil && pkg.Path() == "github.com/gopherjs/gopherjs/js" }
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") }
// Transform applies the transformation to the specified parsed file, // whose type information is supplied in info, and returns the number // of replacements that were made. // // It mutates the AST in place (the identity of the root node is // unchanged), and may add nodes for which no type information is // available in info. // // Derived from rewriteFile in $GOROOT/src/cmd/gofmt/rewrite.go. // func (tr *Transformer) Transform(info *types.Info, pkg *types.Package, file *ast.File) int { if !tr.seenInfos[info] { tr.seenInfos[info] = true mergeTypeInfo(&tr.info.Info, info) } tr.currentPkg = pkg tr.nsubsts = 0 if tr.verbose { fmt.Fprintf(os.Stderr, "before: %s\n", astString(tr.fset, tr.before)) fmt.Fprintf(os.Stderr, "after: %s\n", astString(tr.fset, tr.after)) } var f func(rv reflect.Value) reflect.Value f = func(rv reflect.Value) reflect.Value { // don't bother if val is invalid to start with if !rv.IsValid() { return reflect.Value{} } rv = apply(f, rv) e := rvToExpr(rv) if e != nil { savedEnv := tr.env tr.env = make(map[string]ast.Expr) // inefficient! Use a slice of k/v pairs if tr.matchExpr(tr.before, e) { if tr.verbose { fmt.Fprintf(os.Stderr, "%s matches %s", astString(tr.fset, tr.before), astString(tr.fset, e)) if len(tr.env) > 0 { fmt.Fprintf(os.Stderr, " with:") for name, ast := range tr.env { fmt.Fprintf(os.Stderr, " %s->%s", name, astString(tr.fset, ast)) } } fmt.Fprintf(os.Stderr, "\n") } tr.nsubsts++ // Clone the replacement tree, performing parameter substitution. // We update all positions to n.Pos() to aid comment placement. rv = tr.subst(tr.env, reflect.ValueOf(tr.after), reflect.ValueOf(e.Pos())) } tr.env = savedEnv } return rv } file2 := apply(f, reflect.ValueOf(file)).Interface().(*ast.File) // By construction, the root node is unchanged. if file != file2 { panic("BUG") } // Add any necessary imports. // TODO(adonovan): remove no-longer needed imports too. if tr.nsubsts > 0 { pkgs := make(map[string]*types.Package) for obj := range tr.importedObjs { pkgs[obj.Pkg().Path()] = obj.Pkg() } for _, imp := range file.Imports { path, _ := strconv.Unquote(imp.Path.Value) delete(pkgs, path) } delete(pkgs, pkg.Path()) // don't import self // NB: AddImport may completely replace the AST! // It thus renders info and tr.info no longer relevant to file. var paths []string for path := range pkgs { paths = append(paths, path) } sort.Strings(paths) for _, path := range paths { astutil.AddImport(tr.fset, file, path) } } tr.currentPkg = nil return tr.nsubsts }
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") }