func stripParens(x ast.Expr) ast.Expr { if px, strip := x.(*ast.ParenExpr); strip { // parentheses must not be stripped if there are any // unparenthesized composite literals starting with // a type name ast.Inspect(px.X, func(node ast.Node) bool { switch x := node.(type) { case *ast.ParenExpr: // parentheses protect enclosed composite literals return false case *ast.CompositeLit: if isTypeName(x.Type) { strip = false // do not strip parentheses } return false } // in all other cases, keep inspecting return true }) if strip { return stripParens(px.X) } } return x }
func lookup(filepath string, offset int) (Definition, error) { def := Definition{} f, err := parser.ParseFile(fileset, filepath, nil, 0, getScope(filepath)) if err != nil { return def, err } containsOffset := func(node ast.Node) bool { from := fileset.Position(node.Pos()).Offset to := fileset.Position(node.End()).Offset return offset >= from && offset < to } // traverse the ast tree until we find a node at the given offset position var ident ast.Expr ast.Inspect(f, func(node ast.Node) bool { switch expr := node.(type) { case *ast.SelectorExpr: if containsOffset(expr) && containsOffset(expr.Sel) { ident = expr } case *ast.Ident: if containsOffset(expr) { ident = expr } } return ident == nil }) if ident == nil { return def, errors.New("no identifier found") } pos := getDefPosition(ident) if pos == nil { return def, errors.New("could not find definition of identifier") } obj, _ := types.ExprType(ident, types.DefaultImporter) def.Name = obj.Name def.Position = *pos return def, nil }
func (def Definition) findReferences(searchpath string, recursive bool) (chan Reference, chan error) { refs := make(chan Reference) errs := make(chan error, 1000) // returns true on error and reports it failed := func(err error) bool { if err != nil { select { case errs <- err: default: } return true } return false } scanAST := func(f ast.Node) { check := func(expr ast.Expr) { pos := getDefPosition(expr) if pos != nil && *pos == def.Position { refs <- Reference{fileset.Position(expr.Pos())} } } ast.Inspect(f, func(node ast.Node) bool { switch e := node.(type) { case *ast.SelectorExpr: if e.Sel.Name == def.Name { check(e) } case *ast.Ident: if e.Name == def.Name { check(e) } } return true }) } scanFile := func(filepath string) { defer func() { if e := recover(); e != nil { return } }() f, err := parser.ParseFile(fileset, filepath, nil, 0, getScope(filepath)) if failed(err) { return } scanAST(f) } var scanFolder func(dirpath string) scanFolder = func(dirpath string) { filter := func(fi os.FileInfo) bool { return path.Ext(fi.Name()) == ".go" } defer func() { if e := recover(); e != nil { return } }() result, err := parser.ParseDir(fileset, dirpath, filter, 0) if failed(err) { return } for _, pkg := range result { scanAST(pkg) } if !recursive { return } dir, err := os.Open(dirpath) if failed(err) { return } infos, err := dir.Readdir(0) if failed(err) { return } for _, fi := range infos { if fi.IsDir() && !strings.HasPrefix(fi.Name(), ".") { scanFolder(path.Join(dirpath, fi.Name())) } } } go func() { defer close(refs) defer close(errs) fi, err := os.Lstat(searchpath) if err != nil { return } if fi.IsDir() { scanFolder(searchpath) } else { scanFile(searchpath) } }() return refs, errs }