Gopls: Navigation features

This page documents gopls features for navigating your source code.

Definition

The LSP textDocument/definition request returns the location of the declaration of the symbol under the cursor. Most editors provide a command to navigate directly to that location.

A definition query also works in these unexpected places:

Client support:

References

The LSP textDocument/references request returns the locations of all identifiers that refer to the symbol under the cursor.

The references algorithm handles various parts of syntax as follows:

Be aware that a references query returns information only about the build configuration used to analyze the selected file, so if you ask for the references to a symbol defined in foo_windows.go, the result will never include the file bar_linux.go, even if that file refers to a symbol of the same name; see https://go.dev/issue/65755.

Clients can request that the declaration be included among the references; most do.

Client support:

Implementation

The LSP textDocument/implementation request queries the relation between abstract and concrete types and their methods.

Interfaces and concrete types are matched using method sets:

For example:

The LSP’s Implementation feature has a built-in bias towards subtypes, possibly because in languages such as Java and C++ the relationship between a type and its supertypes is explicit in the syntax, so the corresponding “Go to interfaces” operation can be achieved as sequence of two or more “Go to definition” steps: the first to visit the type declaration, and the rest to sequentially visit ancestors. (See https://github.com/microsoft/language-server-protocol/issues/2037.)

In Go, where there is no syntactic relationship between two types, a search is required when navigating in either direction between subtypes and supertypes. The heuristic above works well in many cases, but it is not possible to ask for the superinterfaces of io.ReadCloser. For more explicit navigation between subtypes and supertypes, use the [Type Hierarchy](#Type Hierarchy) feature.

Only non-trivial interfaces are considered; no implementations are reported for type any.

Within the same package, all matching types/methods are reported. However, across packages, only exported package-level types and their methods are reported, so local types (whether interfaces, or struct types with methods due to embedding) may be missing from the results.

Functions, func types, and dynamic function calls are matched using signatures:

If either the target type or the candidate type are generic, the results will include the candidate type if there is any instantiation of the two types that would allow one to implement the other. (Note: the matcher doesn’t current implement full unification, so type parameters are treated like wildcards that may match arbitrary types, without regard to consistency of substitutions across the method set or even within a single method. This may lead to occasional spurious matches.)

Since a type may be both a function type and a named type with methods (for example, http.HandlerFunc), it may participate in both kinds of implementation queries (by method-sets and function signatures). Queries using method-sets should be invoked on the type or method name, and queries using signatures should be invoked on a func or ( token.

Client support:

Type Definition

The LSP textDocument/typeDefinition request returns the location of the type of the selected symbol.

For example, if the selection is the name buf of a local variable of type *bytes.Buffer, a typeDefinition query will return the location of the type bytes.Buffer. Clients typically navigate to that location.

Type constructors such as pointer, array, slice, channel, and map are stripped off the selected type in the search for a named type. For example, if x is of type chan []*T, the reported type definition will be that of T. Similarly, if the symbol’s type is a function with one “interesting” (named, non-error) result type, the function’s result type is used.

Gopls currently requires that a typeDefinition query be applied to a symbol, not to an arbitrary expression; see https://go.dev/issue/67890 for potential extensions of this functionality.

Client support:

Document Symbol

The textDocument/documentSymbol LSP query reports the list of top-level declarations in this file. Clients may use this information to present an overview of the file, and an index for faster navigation.

Gopls responds with the DocumentSymbol type if the client indicates hierarchicalDocumentSymbolSupport; otherwise it returns a SymbolInformation.

Client support:

Symbol

The workspace/symbol LSP query searches an index of all the symbols in the workspace.

The default symbol matching algorithm (fastFuzzy), inspired by the popular fuzzy matcher FZF, attempts a variety of inexact matches to correct for misspellings or abbreviations in your query. For example, it considers DocSym a match for DocumentSymbol.

Settings:

Client support:

Selection Range

The textDocument/selectionRange LSP query returns information about the lexical extent of each piece of syntax enclosing the current selection. Clients may use it to provide an operation to expand the selection to successively larger expressions.

Client support:

Call Hierarchy

The LSP CallHierarchy mechanism consists of three queries that together enable clients to present a hierarchical view of a portion of the static call graph:

Invoke the command while selecting the name in a function declaration.

Dynamic calls are not included, because it is not analytically practical to detect them. So, beware that the results may not be exhaustive, and perform a References query if necessary.

The hierarchy does not consider a nested function distinct from its enclosing named function. (Without the ability to detect dynamic calls, it would make little sense do so.)

The screenshot below shows the outgoing call tree rooted at f. The tree has been expanded to show a path from f to the String method of fmt.Stringer through the guts of fmt.Sprint:

Client support:

Type Hierarchy

The LSP TypeHierarchy mechanism consists of three queries that together enable clients to present a hierarchical view of a portion of the subtyping relation over named types.

Invoke the command while selecting the name of a type.

As with an Implementation query, a type hierarchy query reports function-local types only within the same package as the query type. Also the result does not include alias types, only defined types.

Caveats:

Client support:


The source files for this documentation can be found beneath golang.org/x/tools/gopls/doc.