honnef.co/go/tools@v0.5.0-0.dev.0.20240520180541-dcae280a5e87/internal/cmd/gogrep/gogrep.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "go/ast" 7 "go/format" 8 "go/parser" 9 "go/token" 10 "os" 11 "path/filepath" 12 "reflect" 13 "strings" 14 15 "honnef.co/go/tools/pattern" 16 ) 17 18 func match(fset *token.FileSet, pat pattern.Pattern, f *ast.File) { 19 ast.Inspect(f, func(node ast.Node) bool { 20 if node == nil { 21 return true 22 } 23 24 if _, ok := pat.Relevant[reflect.TypeOf(node)]; ok { 25 m := &pattern.Matcher{} 26 if m.Match(pat, node) { 27 fmt.Printf("%s: ", fset.Position(node.Pos())) 28 format.Node(os.Stdout, fset, node) 29 fmt.Println() 30 } 31 32 // OPT(dh): we could further speed this up by not 33 // chasing down impossible subtrees. For example, 34 // we'll never find an ImportSpec beneath a FuncLit. 35 } 36 return true 37 }) 38 39 } 40 41 func main() { 42 flag.Parse() 43 // XXX don't use MustParse, handle error 44 p := &pattern.Parser{} 45 q, err := p.Parse(flag.Args()[0]) 46 if err != nil { 47 fmt.Println(err) 48 os.Exit(1) 49 } 50 dir := flag.Args()[1] 51 // XXX should we create a new fileset per file? what if we're 52 // checking millions of files, will this use up a lot of memory? 53 fset := token.NewFileSet() 54 filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 55 if err != nil { 56 // XXX error handling 57 panic(err) 58 } 59 if !strings.HasSuffix(path, ".go") { 60 return nil 61 } 62 // XXX don't try to parse irregular files or directories 63 f, err := parser.ParseFile(fset, path, nil, parser.ParseComments) 64 if err != nil { 65 // XXX log error? 66 return nil 67 } 68 69 match(fset, q, f) 70 71 return nil 72 }) 73 }