func (x *Indexer) Visit(node ast.Node) ast.Visitor { switch n := node.(type) { case nil: // nothing to do case *ast.Ident: x.visitIdent(Use, n) case *ast.FieldList: x.visitFieldList(VarDecl, n) case *ast.InterfaceType: x.visitFieldList(MethodDecl, n.Methods) case *ast.DeclStmt: // local declarations should only be *ast.GenDecls; // ignore incorrect ASTs if decl, ok := n.Decl.(*ast.GenDecl); ok { x.decl = nil // no snippets for local declarations x.visitGenDecl(decl) } case *ast.GenDecl: x.decl = n x.visitGenDecl(n) case *ast.FuncDecl: kind := FuncDecl if n.Recv != nil { kind = MethodDecl ast.Walk(x, n.Recv) } x.decl = n x.visitIdent(kind, n.Name) ast.Walk(x, n.Type) if n.Body != nil { ast.Walk(x, n.Body) } case *ast.File: x.decl = nil x.visitIdent(PackageClause, n.Name) for _, d := range n.Decls { ast.Walk(x, d) } default: return x } return nil }
// idents is an iterator that returns all idents in f via the result channel. func idents(f *ast.File) <-chan *ast.Ident { v := make(visitor) go func() { ast.Walk(v, f) close(v) }() return v }
func (x *Indexer) visitFieldList(kind SpotKind, list *ast.FieldList) { for _, f := range list.List { x.decl = nil // no snippets for fields for _, name := range f.Names { x.visitIdent(kind, name) } ast.Walk(x, f.Type) // ignore tag - not indexed at the moment } }
func (x *Indexer) visitSpec(kind SpotKind, spec ast.Spec) { switch n := spec.(type) { case *ast.ImportSpec: x.visitIdent(ImportDecl, n.Name) // ignore path - not indexed at the moment case *ast.ValueSpec: for _, n := range n.Names { x.visitIdent(kind, n) } ast.Walk(x, n.Type) for _, v := range n.Values { ast.Walk(x, v) } case *ast.TypeSpec: x.visitIdent(TypeDecl, n.Name) ast.Walk(x, n.Type) } }
func (x *Indexer) visitFile(dirname string, f os.FileInfo, fulltextIndex bool) { if f.IsDir() { return } filename := pathpkg.Join(dirname, f.Name()) goFile := false switch { case isGoFile(f): if !includeTestFiles && (!isPkgFile(f) || strings.HasPrefix(filename, "test/")) { return } if !includeMainPackages && pkgName(filename) == "main" { return } goFile = true case !fulltextIndex || !isWhitelisted(f.Name()): return } file, fast := x.addFile(filename, goFile) if file == nil { return // addFile failed } if fast != nil { // we've got a Go file to index x.current = file pak := x.lookupPackage(dirname, fast.Name.Name) x.file = &File{f.Name(), pak} ast.Walk(x, fast) } // update statistics x.stats.Bytes += file.Size() x.stats.Files++ x.stats.Lines += file.LineCount() }