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) } pkg = pkgname.Imported() description = fmt.Sprintf("import of package %q", pkg.Path()) 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).(*types.PkgName).Imported() 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 }
// checkInFileBlock performs safety checks for renames of objects in the file block, // i.e. imported package names. func (r *Unexporter) checkInFileBlock(objsToUpdate map[types.Object]string, from *types.PkgName, to string) { // Check import name is not "init". if to == "init" { r.errorf(from.Pos(), "%q is not a valid imported package name", to) } // Check for conflicts between file and package block. if prev := from.Pkg().Scope().Lookup(to); prev != nil { r.warn(from, r.errorf(from.Pos(), "renaming this %s %q to %q would conflict", objectKind(from), from.Name(), to), r.errorf(prev.Pos(), "\twith this package member %s", objectKind(prev))) return // since checkInPackageBlock would report redundant errors } // Check for conflicts in lexical scope. r.checkInLexicalScope(objsToUpdate, from, to, r.packages[from.Pkg()]) // Finally, modify ImportSpec syntax to add or remove the Name as needed. info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos()) if from.Imported().Name() == to { // ImportSpec.Name not needed path[1].(*ast.ImportSpec).Name = nil } else { // ImportSpec.Name needed if spec := path[1].(*ast.ImportSpec); spec.Name == nil { spec.Name = &ast.Ident{NamePos: spec.Path.Pos(), Name: to} info.Defs[spec.Name] = from } } }