func (r *renamer) checkInLocalScope(from types.Object) { info := r.packages[from.Pkg()] // Is this object an implicit local var for a type switch? // Each case has its own var, whose position is the decl of y, // but Ident in that decl does not appear in the Uses map. // // switch y := x.(type) { // Defs[Ident(y)] is undefined // case int: print(y) // Implicits[CaseClause(int)] = Var(y_int) // case string: print(y) // Implicits[CaseClause(string)] = Var(y_string) // } // var isCaseVar bool for syntax, obj := range info.Implicits { if _, ok := syntax.(*ast.CaseClause); ok && obj.Pos() == from.Pos() { isCaseVar = true r.check(obj) } } r.checkInLexicalScope(from, info) // Finally, if this was a type switch, change the variable y. if isCaseVar { _, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos()) path[0].(*ast.Ident).Name = r.to // path is [Ident AssignStmt TypeSwitchStmt...] } }
// checkSelection checks that all uses and selections that resolve to // the specified object would continue to do so after the renaming. func (r *renamer) checkSelections(from types.Object) { for pkg, info := range r.packages { if id := someUse(info, from); id != nil { if !r.checkExport(id, pkg, from) { return } } for syntax, sel := range info.Selections { // There may be extant selections of only the old // name or only the new name, so we must check both. // (If neither, the renaming is sound.) // // In both cases, we wish to compare the lengths // of the implicit field path (Selection.Index) // to see if the renaming would change it. // // If a selection that resolves to 'from', when renamed, // would yield a path of the same or shorter length, // this indicates ambiguity or a changed referent, // analogous to same- or sub-block lexical conflict. // // If a selection using the name 'to' would // yield a path of the same or shorter length, // this indicates ambiguity or shadowing, // analogous to same- or super-block lexical conflict. // TODO(adonovan): fix: derive from Types[syntax.X].Mode // TODO(adonovan): test with pointer, value, addressable value. isAddressable := true if sel.Obj() == from { if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), r.to); obj != nil { // Renaming this existing selection of // 'from' may block access to an existing // type member named 'to'. delta := len(indices) - len(sel.Index()) if delta > 0 { continue // no ambiguity } r.selectionConflict(from, delta, syntax, obj) return } } else if sel.Obj().Name() == r.to { if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), from.Name()); obj == from { // Renaming 'from' may cause this existing // selection of the name 'to' to change // its meaning. delta := len(indices) - len(sel.Index()) if delta > 0 { continue // no ambiguity } r.selectionConflict(from, -delta, syntax, sel.Obj()) return } } } } }
// isPackageLevel reports whether obj is a package-level object. func isPackageLevel(obj types.Object) bool { // TODO(adonovan): fix go/types bug: // obj.Parent().Parent() == obj.Pkg().Scope() // doesn't work because obj.Parent() gets mutated during // dot-imports. return obj.Pkg().Scope().Lookup(obj.Name()) == obj }
// same reports whether x and y are identical, or both are PkgNames // referring to the same Package. // func sameObj(x, y types.Object) bool { if x == y { return true } if _, ok := x.(*types.PkgName); ok { if _, ok := y.(*types.PkgName); ok { return x.Pkg() == y.Pkg() } } return false }
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 (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 }
func (c *funcContext) objectName(o types.Object) string { if o.Pkg() != c.p.pkg || o.Parent() == c.p.pkg.Scope() { c.p.dependencies[o] = true } if o.Pkg() != c.p.pkg { pkgVar, found := c.p.pkgVars[o.Pkg().Path()] if !found { pkgVar = fmt.Sprintf(`$packages["%s"]`, o.Pkg().Path()) } return pkgVar + "." + o.Name() } switch o.(type) { case *types.Var, *types.Const: if o.Exported() && o.Parent() == c.p.pkg.Scope() { return "$pkg." + o.Name() } } name, found := c.p.objectVars[o] if !found { name = c.newVariableWithLevel(o.Name(), o.Parent() == c.p.pkg.Scope(), "") c.p.objectVars[o] = name } if c.p.escapingVars[o] { return name + "[0]" } return name }
func (cdd *CDD) Name(w *bytes.Buffer, obj types.Object, direct bool) { if obj == nil { w.WriteByte('_') return } switch o := obj.(type) { case *types.PkgName: // Imported package name in SelectorExpr: pkgname.Name w.WriteString(upath(o.Pkg().Path())) return case *types.Func: s := o.Type().(*types.Signature) if r := s.Recv(); r != nil { t := r.Type() if p, ok := t.(*types.Pointer); ok { t = p.Elem() direct = false } cdd.Type(w, t) w.WriteByte('$') w.WriteString(o.Name()) if !cdd.gtc.isLocal(t.(*types.Named).Obj()) { cdd.addObject(o, direct) } return } } if p := obj.Pkg(); p != nil && !cdd.gtc.isLocal(obj) { cdd.addObject(obj, direct) w.WriteString(upath(obj.Pkg().Path())) w.WriteByte('$') } name := obj.Name() switch name { case "init": w.WriteString(cdd.gtc.uniqueId() + name) default: w.WriteString(name) if cdd.gtc.isLocal(obj) { w.WriteByte('$') } } }
func (e *exporter) makeName(o types.Object) string { if o.Name() == "" || o.Name() == "_" { return "?" } if o.Pkg() == nil || o.Pkg() == e.pkg { return `@"".` + o.Name() } e.addImport(o.Pkg()) return `@"` + o.Pkg().Path() + `".` + o.Name() }
func typeObjectToJson(o *types.Object) interface{} { switch o := (*o).(type) { case *types.Package: return typePackageToJson(o) case *types.Const: return struct { Isa string Pkg interface{} Name string Type interface{} Val interface{} }{ "Const", typePackageToJson(o.Pkg()), o.Name(), typeTypeToJson(o.Type()), o.Val(), } case *types.TypeName: return struct { Isa string Pkg interface{} Name string Type interface{} }{ "TypeName", typePackageToJson(o.Pkg()), o.Name(), typeTypeToJson(o.Type()), } case *types.Var: return struct { Isa string Pkg interface{} Name string Type interface{} }{ "Var", typePackageToJson(o.Pkg()), o.Name(), typeTypeToJson(o.Type()), } case *types.Func: return struct { Isa string Pkg interface{} Name string Type interface{} }{ "Func", typePackageToJson(o.Pkg()), o.Name(), typeTypeToJson(o.Type()), } default: if o != nil { return nil } else { return "UNKNOWN" } } return nil }
func (e *exporter) makeName(o types.Object) string { switch o.Name() { case "": return "?" case "_": return "_" default: pkgPath := "" if o.Pkg() != nil && o.Pkg() != e.pkg { e.addImport(o.Pkg()) pkgPath = o.Pkg().Path() } return `@"` + pkgPath + `".` + o.Name() } }
// checkInPackageBlock performs safety checks for renames of // func/var/const/type objects in the package block. func (r *renamer) checkInPackageBlock(from types.Object) { // Check that there are no references to the name from another // package if the renaming would make it unexported. if ast.IsExported(from.Name()) && !ast.IsExported(r.to) { for pkg, info := range r.packages { if pkg == from.Pkg() { continue } if id := someUse(info, from); id != nil && !r.checkExport(id, pkg, from) { break } } } info := r.packages[from.Pkg()] lexinfo := lexical.Structure(r.iprog.Fset, from.Pkg(), &info.Info, info.Files) // Check that in the package block, "init" is a function, and never referenced. if r.to == "init" { kind := objectKind(from) if kind == "func" { // Reject if intra-package references to it exist. if refs := lexinfo.Refs[from]; len(refs) > 0 { r.errorf(from.Pos(), "renaming this func %q to %q would make it a package initializer", from.Name(), r.to) r.errorf(refs[0].Id.Pos(), "\tbut references to it exist") } } else { r.errorf(from.Pos(), "you cannot have a %s at package level named %q", kind, r.to) } } // Check for conflicts between package block and all file blocks. for _, f := range info.Files { if prev, b := lexinfo.Blocks[f].Lookup(r.to); b == lexinfo.Blocks[f] { r.errorf(from.Pos(), "renaming this %s %q to %q would conflict", objectKind(from), from.Name(), r.to) r.errorf(prev.Pos(), "\twith this %s", objectKind(prev)) return // since checkInPackageBlock would report redundant errors } } // Check for conflicts in lexical scope. if from.Exported() { for _, info := range r.packages { r.checkInLexicalScope(from, info) } } else { r.checkInLexicalScope(from, info) } }
func (c *PkgContext) objectName(o types.Object) string { if o.Pkg() != nil && o.Pkg() != c.pkg { pkgVar, found := c.pkgVars[o.Pkg().Path()] if !found { pkgVar = fmt.Sprintf(`Go$packages["%s"]`, o.Pkg().Path()) } return pkgVar + "." + o.Name() } name, found := c.objectVars[o] if !found { name = c.newVariable(o.Name()) c.objectVars[o] = name } switch o.(type) { case *types.Var, *types.Const: if o.Parent() == c.pkg.Scope() { return "Go$pkg." + name } } return name }
// packageLevelValue returns the package-level value corresponding to // the specified named object, which may be a package-level const // (*Const), var (*Global) or func (*Function) of some package in // prog. It returns nil if the object is not found. // func (prog *Program) packageLevelValue(obj types.Object) Value { if pkg, ok := prog.packages[obj.Pkg()]; ok { return pkg.values[obj] } return nil }
func isGlobalObject(obj types.Object) bool { pkg := obj.Pkg() return pkg == nil || obj.Parent() == pkg.Scope() }
func (gtc *GTC) isImported(o types.Object) bool { return o.Pkg() != gtc.pkg }
// isPackageLevel reports whether obj is a package-level object. func isPackageLevel(obj types.Object) bool { return obj.Pkg().Scope().Lookup(obj.Name()) == obj }
func isAccessibleFrom(obj types.Object, pkg *types.Package) bool { return ast.IsExported(obj.Name()) || obj.Pkg() == pkg }
func (w *PkgWalker) LookupObjects(pkg *types.Package, pkgInfo *types.Info, cursor *FileCursor) { var cursorObj types.Object var cursorSelection *types.Selection var cursorObjIsDef bool //lookup defs _ = cursorObjIsDef if cursorObj == nil { for sel, obj := range pkgInfo.Selections { if cursor.pos >= sel.Sel.Pos() && cursor.pos <= sel.Sel.End() { cursorObj = obj.Obj() cursorSelection = obj break } } } if cursorObj == nil { for id, obj := range pkgInfo.Defs { if cursor.pos >= id.Pos() && cursor.pos <= id.End() { cursorObj = obj cursorObjIsDef = true break } } } _ = cursorSelection if cursorObj == nil { for id, obj := range pkgInfo.Uses { if cursor.pos >= id.Pos() && cursor.pos <= id.End() { cursorObj = obj break } } } if cursorObj == nil { return } kind, err := parserObjKind(cursorObj) if err != nil { log.Fatalln(err) } if kind == ObjField { if cursorObj.(*types.Var).Anonymous() { if named, ok := cursorObj.Type().(*types.Named); ok { cursorObj = named.Obj() } } } cursorPkg := cursorObj.Pkg() cursorPos := cursorObj.Pos() var fieldTypeInfo *types.Info var fieldTypeObj types.Object if cursorPkg == pkg { fieldTypeInfo = pkgInfo } cursorIsInterfaceMethod := false var cursorInterfaceTypeName string if kind == ObjMethod && cursorSelection != nil && cursorSelection.Recv() != nil { sig := cursorObj.(*types.Func).Type().Underlying().(*types.Signature) if _, ok := sig.Recv().Type().Underlying().(*types.Interface); ok { named := cursorSelection.Recv().(*types.Named) obj, typ := w.lookupNamedMethod(named, cursorObj.Name()) if obj != nil { cursorObj = obj } if typ != nil { cursorPkg = typ.Obj().Pkg() cursorInterfaceTypeName = typ.Obj().Name() } cursorIsInterfaceMethod = true } } if cursorPkg != nil && cursorPkg != pkg && kind != ObjPkgName && w.isBinaryPkg(cursorPkg.Path()) { conf := &PkgConfig{ IgnoreFuncBodies: true, AllowBinary: true, Info: &types.Info{ Defs: make(map[*ast.Ident]types.Object), }, } pkg, _ := w.Import("", cursorPkg.Path(), conf) if pkg != nil { if cursorIsInterfaceMethod { for _, obj := range conf.Info.Defs { if obj == nil { continue } if fn, ok := obj.(*types.Func); ok { if fn.Name() == cursorObj.Name() { if sig, ok := fn.Type().Underlying().(*types.Signature); ok { if named, ok := sig.Recv().Type().(*types.Named); ok { if named.Obj() != nil && named.Obj().Name() == cursorInterfaceTypeName { cursorPos = obj.Pos() break } } } } } } } else { for _, obj := range conf.Info.Defs { if obj != nil && obj.String() == cursorObj.String() { cursorPos = obj.Pos() break } } } } if kind == ObjField || cursorIsInterfaceMethod { fieldTypeInfo = conf.Info } } if kind == ObjField { fieldTypeObj = w.LookupStructFromField(fieldTypeInfo, cursorPkg, cursorObj, cursorPos) } if typeFindDef { fmt.Println(w.fset.Position(cursorPos)) } if typeFindInfo { if kind == ObjField && fieldTypeObj != nil { typeName := fieldTypeObj.Name() if fieldTypeObj.Pkg() != nil && fieldTypeObj.Pkg() != pkg { typeName = fieldTypeObj.Pkg().Name() + "." + fieldTypeObj.Name() } fmt.Println(typeName, simpleType(cursorObj.String())) } else if kind == ObjBuiltin { fmt.Println(builtinInfo(cursorObj.Name())) } else if cursorIsInterfaceMethod { fmt.Println(strings.Replace(simpleType(cursorObj.String()), "(interface)", cursorPkg.Name()+"."+cursorInterfaceTypeName, 1)) } else { fmt.Println(simpleType(cursorObj.String())) } } //if f, ok := w.parsedFileCache[w.fset.Position(cursorPos).Filename]; ok { // for _, d := range f.Decls { // if inRange(d, cursorPos) { // if fd, ok := d.(*ast.FuncDecl); ok { // fd.Body = nil // } // commentMap := ast.NewCommentMap(w.fset, f, f.Comments) // commentedNode := printer.CommentedNode{Node: d} // if comments := commentMap.Filter(d).Comments(); comments != nil { // commentedNode.Comments = comments // } // var b bytes.Buffer // printer.Fprint(&b, w.fset, &commentedNode) // b.Write([]byte("\n\n")) // Add a blank line between entries if we print documentation. // log.Println(w.nodeString(d)) // } // } //} if !typeFindUse { return } var usages []int if kind == ObjPkgName { for id, obj := range pkgInfo.Uses { if obj != nil && obj.Id() == cursorObj.Id() { //!= nil && cursorObj.Pos() == obj.Pos() { usages = append(usages, int(id.Pos())) } } } else { for id, obj := range pkgInfo.Defs { if obj == cursorObj { //!= nil && cursorObj.Pos() == obj.Pos() { usages = append(usages, int(id.Pos())) } } for id, obj := range pkgInfo.Uses { if obj == cursorObj { //!= nil && cursorObj.Pos() == obj.Pos() { usages = append(usages, int(id.Pos())) } } } (sort.IntSlice(usages)).Sort() for _, pos := range usages { fmt.Println(w.fset.Position(token.Pos(pos))) } }