// growSpan expands the span for the object to contain the instance represented // by the identifier. func (pkg *Package) growSpan(ident *ast.Ident, obj types.Object) { if *strictShadowing { return // No need } pos := ident.Pos() end := ident.End() span, ok := pkg.spans[obj] if ok { if span.min > pos { span.min = pos } if span.max < end { span.max = end } } else { span = Span{pos, end} } pkg.spans[obj] = span }
func completeCalltip(src []byte, fn string, offset int) []gocode.GoSublimeGocodeCandidate { fset := token.NewFileSet() af, _ := parser.ParseFile(fset, fn, src, 0) if af != nil { vis := &calltipVisitor{ offset: offset, fset: fset, } ast.Walk(vis, af) if vis.x != nil { var id *ast.Ident switch v := vis.x.Fun.(type) { case *ast.Ident: id = v case *ast.SelectorExpr: id = v.Sel } if id != nil && id.End().IsValid() { line := offsetLine(fset, af, offset) cp := fset.Position(id.End()) cr := cp.Offset cl := gocode.GoSublimeGocodeComplete(src, fn, cr) if (cp.Line == line || line == 0) && len(cl) > 0 { for i, c := range cl { if strings.EqualFold(id.Name, c.Name) { return cl[i : i+1] } } } } } } return []gocode.GoSublimeGocodeCandidate{} }
// Returns true if unused func checkObj(expr *ast.Ident, object types.Object, prog *loader.Program, ssaprog *ssa.Program, fset *token.FileSet) (unused bool) { if _, ok := object.(*types.Var); !ok { if debug { fmt.Println("Skipping object", object) } return false } pkg, node, _ := prog.PathEnclosingInterval(expr.Pos(), expr.End()) spkg := ssaprog.Package(pkg.Pkg) f := ssa.EnclosingFunction(spkg, node) if f == nil { if debug { fmt.Printf("Unknown function %v %v %v %v\n", fset.Position(expr.Pos()), object, pkg, prog) } return false } value, _ := f.ValueForExpr(expr) // Unwrap unops and grab the value inside if v, ok := value.(*ssa.UnOp); ok { if debug { fmt.Println("Unwrapping unop") } value = v.X } if debug { fmt.Printf("%v %v: %v %#v\n", fset.Position(expr.Pos()), expr, object, value) } if _, ok := value.(*ssa.Global); ok { if debug { fmt.Printf(" is global\n") } return false } if value == nil { if debug { fmt.Println("Value is nil", object) } return false } refs := value.Referrers() if refs == nil { if debug { fmt.Println("Referrers is nil", object) } return false } if debug { fmt.Printf(" (refs) %v\n", refs) } hasRef := false for _, r := range *refs { _, ok := r.(*ssa.DebugRef) hasRef = hasRef || !ok if debug && !ok { fmt.Printf("%v %v: %v %v\n", fset.Position(expr.Pos()), expr, object, r) } } if !hasRef { unused = true } return unused }
// NewDef creates a new Def. func (g *Grapher) NewDef(obj types.Object, declIdent *ast.Ident) (*Def, error) { // Find the AST node that declares this def. var declNode ast.Node _, astPath, _ := g.program.PathEnclosingInterval(declIdent.Pos(), declIdent.End()) for _, node := range astPath { switch node.(type) { case *ast.FuncDecl, *ast.GenDecl, *ast.ValueSpec, *ast.TypeSpec, *ast.Field, *ast.DeclStmt, *ast.AssignStmt: declNode = node goto found } } found: if declNode == nil { return nil, fmt.Errorf("On ident %s at %s: no DeclNode found (using PathEnclosingInterval)", declIdent.Name, g.program.Fset.Position(declIdent.Pos())) } key, info, err := g.defInfo(obj) if err != nil { return nil, err } si := definfo.DefInfo{ Exported: info.exported, PkgScope: info.pkgscope, PkgName: obj.Pkg().Name(), Kind: defKind(obj), } if typ := obj.Type(); typ != nil { si.TypeString = typ.String() if utyp := typ.Underlying(); utyp != nil { si.UnderlyingTypeString = utyp.String() } } switch obj := obj.(type) { case *types.Var: if obj.IsField() { if fieldStruct, ok := g.structFields[obj]; ok { if struct_, ok := fieldStruct.parent.(*types.Named); ok { si.FieldOfStruct = struct_.Obj().Name() } } } case *types.Func: sig := obj.Type().(*types.Signature) if recv := sig.Recv(); recv != nil && recv.Type() != nil { // omit package path; just get receiver type name si.Receiver = strings.Replace(recv.Type().String(), obj.Pkg().Path()+".", "", 1) } } return &Def{ Name: obj.Name(), DefKey: key, File: g.program.Fset.Position(declIdent.Pos()).Filename, IdentSpan: makeSpan(g.program.Fset, declIdent), DeclSpan: makeSpan(g.program.Fset, declNode), DefInfo: si, }, nil }