├── README.md ├── go-find-references └── main.go /README.md: -------------------------------------------------------------------------------- 1 | # go-find-references 2 | Find all References of an Identifier in a Codebase 3 | 4 | ### Usage 5 | 6 | > go-find-references [flags] 7 | 8 | ###### flags: 9 | `-file [string]`: the complete path of the file that contains the identifier. 10 | `-offset [int]`: the byte offset of the identifier in the above file. 11 | `-root [string]`: the directory in which to search for references (optional). If omitted, the directory containing `file` will be used. 12 | 13 | For each found reference, the program will output two lines of text: 14 | The first line contains the path of the file relative to `root` followed by `:lineNumber`. 15 | The second line contains the (trimmed) source text line containing the reference. 16 | 17 | ### example output: 18 | > go-find-references -file /usr/lib/go/src/pkg/sort/search.go -offset 2254 19 | 20 | /usr/share/go/src/pkg/sort/search.go:59:6 21 | func Search(n int, f func(int) bool) int { 22 | /usr/share/go/src/pkg/sort/search.go:84:9 23 | return Search(len(a), func(i int) bool { return a[i] >= x }) 24 | /usr/share/go/src/pkg/sort/search.go:93:9 25 | return Search(len(a), func(i int) bool { return a[i] >= x }) 26 | /usr/share/go/src/pkg/sort/search.go:102:9 27 | return Search(len(a), func(i int) bool { return a[i] >= x }) 28 | 29 | ### TODOs: 30 | 31 | * Improve error messages 32 | * Add support for non-expression identifiers (e.g. keys in struct initialization) 33 | -------------------------------------------------------------------------------- /go-find-references: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukehoban/go-find-references/42505ef666d1ecfde4067ae7a0037543e9fed3e9/go-find-references -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "flag" 6 | "fmt" 7 | "os" 8 | "path" 9 | 10 | "github.com/lukehoban/ident" 11 | ) 12 | 13 | var ( 14 | byteOffset = flag.Int("offset", -1, "the byte offset of the identifier in the file") 15 | filePath = flag.String("file", "", "the file path containing the identifier") 16 | searchRoot = flag.String("root", "", "the root directory in which to search for references") 17 | showIdent = flag.Bool("ident", false, "whether to show the name and position where the identifier is defined") 18 | ) 19 | 20 | func main() { 21 | flag.Parse() 22 | 23 | if *filePath == "" || *byteOffset == -1 { 24 | flag.Usage() 25 | return 26 | } 27 | 28 | if *searchRoot == "" { 29 | *searchRoot = path.Dir(*filePath) 30 | } 31 | 32 | def, err := ident.Lookup(*filePath, *byteOffset) 33 | if err != nil { 34 | reportError(err) 35 | return 36 | } 37 | 38 | if *showIdent { 39 | fmt.Println(def.Name, def.Position) 40 | } 41 | 42 | refs, errs := def.FindReferences(*searchRoot, true) 43 | for { 44 | select { 45 | case ref, ok := <-refs: 46 | if !ok { 47 | return 48 | } 49 | reportReference(ref) 50 | case err, ok := <-errs: 51 | if !ok { 52 | return 53 | } 54 | reportError(err) 55 | } 56 | } 57 | } 58 | 59 | func reportError(err error) { 60 | fmt.Fprintln(os.Stderr, "error:", err) 61 | } 62 | 63 | func reportReference(ref ident.Reference) { 64 | f, err := os.Open(ref.Position.Filename) 65 | if err != nil { 66 | reportError(err) 67 | } 68 | 69 | _, err = f.Seek(int64(ref.Position.Offset-ref.Position.Column+1), 0) 70 | if err != nil { 71 | reportError(err) 72 | } 73 | 74 | line, err := bufio.NewReader(f).ReadString('\n') 75 | if err != nil { 76 | reportError(err) 77 | } 78 | 79 | fmt.Println(ref.Position) 80 | fmt.Println(line[:len(line)-1]) 81 | } 82 | --------------------------------------------------------------------------------