Alan Donovan | 799a471 | 2024-05-03 18:53:37 -0400 | [diff] [blame^] | 1 | # Gopls: Navigation features |
| 2 | |
| 3 | This page documents gopls features for navigating your source code. |
| 4 | |
| 5 | ## Definition |
| 6 | |
| 7 | The LSP [`textDocument/definition`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_definition) |
| 8 | request returns the location of the declaration of the symbol under the cursor. |
| 9 | Most editors provide a command to navigate directly to that location. |
| 10 | |
| 11 | A definition query also works in these unexpected places: |
| 12 | |
| 13 | - On an **import path**, it returns the list of locations, of |
| 14 | each package declaration in the files of the imported package. |
| 15 | - On a **package declaration**, it returns the location of |
| 16 | the package declaration that provides the documentation of that package. |
| 17 | - On a symbol in a **[`go:linkname` directive](https://pkg.go.dev/cmd/compile)**, |
| 18 | it returns the location of that symbol's declaration. |
| 19 | - On a **[doc link](https://tip.golang.org/doc/comment#doclinks)**, it returns |
| 20 | (like [`hover`](passive.md#Hover)) the location of the linked symbol. |
| 21 | - On a file name in a **[`go:embed` directive](https://pkg.go.dev/embed)**, |
| 22 | it returns the location of the embedded file. |
| 23 | |
| 24 | <!-- On a built-in symbol such as `append` or `unsafe.Pointer`, `definition` reports |
| 25 | the location of the declaration in the builtin or unsafe pseudo-packages, |
| 26 | which are just documentation. --> |
| 27 | |
| 28 | Client support: |
| 29 | - **VS Code**: Use [Go to Definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition) (`F12` or `⌘`-click). |
| 30 | If the cursor is already at the declaration, the request is instead interpreted as "Go to References". |
| 31 | - **Emacs + eglot**: use [`M-x xref-find-definitions`](https://www.gnu.org/software/emacs/manual/html_node/emacs/Xref.html). |
| 32 | - **Vim + coc.nvim**: ?? |
| 33 | - **CLI**: `gopls definition file.go:#offset` |
| 34 | |
| 35 | ## References |
| 36 | |
| 37 | The LSP [`textDocument/references`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_references) |
| 38 | request returns the locations of all identifiers that refers to the symbol under the cursor. |
| 39 | |
| 40 | The references algorithm handles various parts of syntax as follows: |
| 41 | |
| 42 | - The references to a **symbol** report all uses of that symbol. |
| 43 | In the case of exported this may include locations in other packages. |
| 44 | - The references to a **package declaration** are all the |
| 45 | direct imports of the package, along with all the other package |
| 46 | declarations in the same package. |
| 47 | - It is an error to request the references to a **built-in symbol** |
| 48 | such as `int` or `append`, |
| 49 | as they are presumed too numerous to be of interest. |
| 50 | - The references to an **interface method** include references to |
| 51 | concrete types that implement the interface. Similarly, the |
| 52 | references to a **method of a concrete type** include references to |
| 53 | corresponding interface methods. |
| 54 | - An **embedded field** `T` in a struct type such as `struct{T}` is |
| 55 | unique in Go in that it is both a reference (to a type) and a |
| 56 | definition (of a field). |
| 57 | The `references` operation reports only the references to it [as a field](golang/go#63521). |
| 58 | To find references to the type, jump to the type declararation first. |
| 59 | |
| 60 | Be aware that a references query returns information only about the |
| 61 | build configuration used to analyze the selected file, so if you ask |
| 62 | for the references to a symbol defined in `foo_windows.go`, the result |
| 63 | will never include the file `bar_linux.go`, even if that file refers |
| 64 | to a symbol of the same name; see golang/go#65755. |
| 65 | |
| 66 | Clients can request that the the declaration be included among the |
| 67 | references; most do. |
| 68 | |
| 69 | Client support: |
| 70 | - **VS Code**: Use [`Go to References`](https://code.visualstudio.com/docs/editor/editingevolved#_peek) to quickly "peek" at the references, |
| 71 | or `Find all References` to open the references panel. |
| 72 | - **Emacs + eglot**: Via [`xref` package](https://www.gnu.org/software/emacs/manual/html_node/emacs/Xref.html): use `M-x xref-find-references`. |
| 73 | - **Vim + coc.nvim**: ?? |
| 74 | - **CLI**: `gopls references file.go:#offset` |
| 75 | |
| 76 | ## Implementation |
| 77 | |
| 78 | The LSP |
| 79 | [`textDocument/implementation`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_implementation) |
| 80 | request queries the "implements" relation between interfaces and concrete types: |
| 81 | |
| 82 | - When invoked on a reference to an **interface type**, it returns the |
| 83 | location of the declaration of each type that implements |
| 84 | the interface. |
| 85 | - When invoked on a **concrete type**, |
| 86 | it returns the locations of the matching interface types. |
| 87 | - When invoked on an **interface method**, it returns the corresponding |
| 88 | methods of the types that satisfy the interface. |
| 89 | - When invoked on a **concrete method**, |
| 90 | it returns the locations of the matching interface methods. |
| 91 | |
| 92 | Only non-trivial interfaces are considered; no implementations are |
| 93 | reported for type `any`. |
| 94 | |
| 95 | Within the same package, all matching types/methods are reported. |
| 96 | However, across packages, only exported package-level types and their |
| 97 | methods are reported, so local types (whether interfaces, or struct |
| 98 | types with methods due to embedding) may be missing from the results. |
| 99 | <!-- Reason: assignability of local types such as I and J defined thus: |
| 100 | package p; func P() {type I interface {...}} |
| 101 | package q; func Q() {type J struct {...}} |
| 102 | depends on them both being in the same types.Importer "realm", |
| 103 | but that is not consistent with the "scalable" gopls design. |
| 104 | --> |
| 105 | |
| 106 | Generic types are currently not fully supported; see golang/go#59224. |
| 107 | |
| 108 | Client support: |
| 109 | - **VS Code**: Use [Go to Implementations](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-implementation) (`⌘F12`). |
| 110 | - **Emacs + eglot**: Use `M-x eglot-find-implementation`. |
| 111 | - **Vim + coc.nvim**: ?? |
| 112 | - **CLI**: `gopls implementation file.go:#offset` |
| 113 | |
| 114 | |
| 115 | ## TypeDefinition |
| 116 | |
| 117 | The LSP |
| 118 | [`textDocument/typeDefinition`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_typeDefinition) |
| 119 | request returns the location of the type of the selected symbol. |
| 120 | |
| 121 | For example, if the selection is the name `buf` of a local variable of |
| 122 | type `*bytes.Buffer`, a `typeDefinition` query will return the |
| 123 | location of the type `bytes.Buffer`. |
| 124 | Clients typically navigate to that location. |
| 125 | |
| 126 | Type constructors such as pointer, array, slice, channel, and map are |
| 127 | stripped off the selected type in the search for a named type. For |
| 128 | example, if x is of type `chan []*T`, the reported type definition |
| 129 | will be that of `T`. |
| 130 | Similarly, if the symbol's type is a function with one "interesting" |
| 131 | (named, non-`error`) result type, the function's result type is used. |
| 132 | |
| 133 | Gopls currently requires that a `typeDefinition` query be applied to a |
| 134 | symbol, not to an arbitrary expression; see golang/go#67890 for |
| 135 | potential extensions of this functionality. |
| 136 | <!-- e.g. selecting a struct field, package name, or other piece of syntax. --> |
| 137 | |
| 138 | Client support: |
| 139 | - **VS Code**: Use [Go to Type Definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-implementation). |
| 140 | - **Emacs + eglot**: Use `M-x eglot-find-typeDefinition`. |
| 141 | - **Vim + coc.nvim**: ?? |
| 142 | - **CLI**: not supported |
| 143 | |
| 144 | ## DocumentSymbol |
| 145 | |
| 146 | The `textDocument/documentSymbol` LSP query reports the list of |
| 147 | top-level declarations in this file. Clients may use this information |
| 148 | to present an overview of the file, and an index for faster navigation. |
| 149 | |
| 150 | Gopls responds with the newer |
| 151 | [`DocumentSymbol`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#documentSymbol) |
| 152 | type if the client indicates |
| 153 | [`hierarchicalDocumentSymbolSupport`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#documentSymbolClientCapabilities); |
| 154 | otherwise it returns the older |
| 155 | [`SymbolInformation`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#symbolInformation). |
| 156 | |
| 157 | Client support: |
| 158 | - **VS Code**: Use the [Outline view](https://code.visualstudio.com/docs/getstarted/userinterface#_outline-view) for navigation. |
| 159 | - **Emacs + eglot**: Use [`M-x imenu`](https://www.gnu.org/software/emacs/manual/html_node/emacs/Imenu.html#Imenu) to jump to a symbol. |
| 160 | - **Vim + coc.nvim**: ?? |
| 161 | - **CLI**: `gopls links file.go` |
| 162 | |
| 163 | |
| 164 | ## Symbol |
| 165 | |
| 166 | The |
| 167 | [`workspace/symbol`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_symbol) |
| 168 | LSP query searches an index of all the symbols in the workspace. |
| 169 | |
| 170 | The default symbol matching algorithm (`fastFuzzy`), inspired by the |
| 171 | popular fuzzy matcher [FZF](https://github.com/junegunn/fzf), attempts |
| 172 | a variety of inexact matches to correct for misspellings in your |
| 173 | query. For example, it considers `DocSym` a match for `DocumentSymbol`. |
| 174 | |
| 175 | <!-- |
| 176 | It also supports the following special characters within queries: |
| 177 | |
| 178 | | Character | Usage | Match | |
| 179 | | --------- | --------- | ------------ | |
| 180 | | `'` | `'abc` | exact | |
| 181 | | `^` | `^printf` | exact prefix | |
| 182 | | `$` | `printf$` | exact suffix | |
| 183 | |
| 184 | However, VS Code does its own fuzzy matching afterward, so these |
| 185 | aren't effective in that client. |
| 186 | --> |
| 187 | |
| 188 | TODO: screenshot |
| 189 | |
| 190 | Settings: |
| 191 | - The [`symbolMatcher`](../settings.md#symbolMatcher) setting controls the algorithm used for symbol matching. |
| 192 | - The [`symbolStyle`](../settings.md#symbolStyle) setting controls how symbols are qualified in symbol responses. |
| 193 | - The [`symbolScope`](../settings.md#symbolScope) setting determines the scope of the query. |
| 194 | - The [`directoryFilters`](../settings.md#directoryFilters) setting specifies directories to be excluded from the search. |
| 195 | |
| 196 | Client support: |
| 197 | - **VS Code**: Use ⌘T to open [Go to Symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol) with workspace scope. (Alternatively, use Ctrl-Shift-O, and add a `@` prefix to search within the file or a `#` prefix to search throughout the workspace.) |
| 198 | - **Emacs + eglot**: Use [`M-x xref-find-apropos`](https://www.gnu.org/software/emacs/manual/html_node/emacs/Looking-Up-Identifiers.html) to show symbols that match a search term. |
| 199 | - **Vim + coc.nvim**: ?? |
| 200 | - **CLI**: `gopls links file.go` |
| 201 | |
| 202 | |
| 203 | ## SelectionRange |
| 204 | |
| 205 | The |
| 206 | [`textDocument/selectionRange`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_selectionRange) |
| 207 | LSP query returns information about the lexical extent of each piece |
| 208 | of syntax enclosing the current selection. |
| 209 | Clients may use it to provide an operation to expand the selection |
| 210 | to successively larger expressions. |
| 211 | |
| 212 | Client support: |
| 213 | - **VSCode**: Use `⌘⇧^→` to expand the selection or `⌘⇧^←` to contract it again; watch this [video](https://www.youtube.com/watch?v=dO4SGAMl7uQ). |
| 214 | - **Emacs + eglot**: Not standard. Use `M-x eglot-expand-selection` defined in [this configuration snippet](https://github.com/joaotavora/eglot/discussions/1220#discussioncomment-9321061). |
| 215 | - **Vim + coc.nvim**: ?? |
| 216 | - **CLI**: not supported |
| 217 | |
| 218 | ## CallHierarchy |
| 219 | |
| 220 | The LSP CallHierarchy mechanism consists of three queries that |
| 221 | together enable clients to present a hierarchical view of a portion of |
| 222 | the static call graph: |
| 223 | |
| 224 | - [`textDocument/prepareCallHierarchy`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_prepareCallHierarchy) returns a list of [items](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#callHierarchyItem) for a given position, each representing a named function or method enclosing the position; |
| 225 | - [`callHierarchyItem/incomingCalls`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#callHierarchy_incomingCalls) returns the set of call sites that call the selected item; and |
| 226 | - [`callHierarchy/outgoingCalls`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#callHierarchy_incomingCalls) returns the set of functions called by the selected item. |
| 227 | |
| 228 | Invoke the command while selecting the name in a function declaration. |
| 229 | |
| 230 | Dynamic calls are not included, because it is not analytically |
| 231 | practical to detect them. So, beware that the results may not be |
| 232 | exhaustive, and perform a [References](#references) query if necessary. |
| 233 | |
| 234 | The hierarchy does not consider a nested function distinct from its |
| 235 | enclosing named function. (Without the ability to detect dynamic |
| 236 | calls, it would make little sense do so.) |
| 237 | |
| 238 | The screenshot below shows the outgoing call tree rooted at `f`. The |
| 239 | tree has been expanded to show a path from `f` to the `String` method |
| 240 | of `fmt.Stringer` through the guts of `fmt.Sprint:` |
| 241 | |
| 242 | <img title="Outgoing calls of f" src="../assets/outgoingcalls.png" width="640"> |
| 243 | |
| 244 | Caveats: |
| 245 | - In some cases dynamic function calls are (erroneously) included in |
| 246 | the output; see golang/go#68153. |
| 247 | |
| 248 | Client support: |
| 249 | - **VS Code**: `Show Call Hierarchy` menu item (`⌥⇧H`) opens [Call hierarchy view](https://code.visualstudio.com/docs/cpp/cpp-ide#_call-hierarchy) (note: docs refer to C++ but the idea is the same for Go). |
| 250 | - **Emacs + eglot**: Not standard; install with `(package-vc-install "https://github.com/dolmens/eglot-hierarchy")`. Use `M-x eglot-hierarchy-call-hierarchy` to show the direct incoming calls to the selected function; use a prefix argument (`C-u`) to show the direct outgoing calls. There is no way to expand the tree. |
| 251 | - **CLI**: `gopls call_hierarchy file.go:#offset` shows outgoing and incoming calls. |