blob: 4bf1138af6c2deebdcec2d2ae3765dd804cce6a0 [file] [log] [blame] [view]
# Gopls: Diagnostics
Gopls continuously annotates all your open files of source code with a
variety of diagnostics. Every time you edit a file or make a
configuration change, gopls asynchronously recomputes these
diagnostics and sends them to the client using the LSP
[`publishDiagnostics`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_publishDiagnostics)
notification, giving you real-time feedback that reduces the cost of
common mistakes.
Diagnostics come from two main sources: build errors and analysis findings.
- **Build errors** are those that you would obtain from running `go
build`. Gopls doesn't actually run the compiler; that would be too
slow. Instead it runs `go list` (when needed) to compute the
metadata of the build, then processes those packages in a similar
manner to the compiler front-end: reading, scanning, and parsing the
source files, then type-checking them. Each of these steps can
produce errors that gopls will surface as a diagnostic.
The `source` field of the LSP `Diagnostic` record indicates where
the diagnostic came from: those with source `"go list"` come from
the `go list` command, and those with source `"compiler"` come from
gopls' parsing or type checking phases, which are similar to those
used in the Go compiler.
![A diagnostic due to a type error](../assets/diagnostic-typeerror.png)
The example above shows a `string + int` addition, causes the type
checker to report a `MismatchedTypes` error. The diagnostic contains
a link to the documentation about this class of type error.
- **Analysis findings** come from the [**Go analysis
framework**](https://golang.org/x/tools/go/analysis), the system
used by `go vet` to apply a variety of additional static checks to
your Go code. The best-known example is the [`printf`
analyzer](https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/printf),
which reports calls to [`fmt.Printf`](https://pkg.go.dev/fmt#Printf)
where the format "verb" doesn't match the argument, such as
`fmt.Printf("%d", "three")`.
Gopls provides dozens of analyzers aggregated from a variety of
suites. See [Analyzers](../analyzers.md) for the complete list. The
`source` field of each diagnostic produced by an analyzer records
the name of the analyzer that produced it.
![A diagnostic due to an analysis finding](../assets/diagnostic-analysis.png)
The example above shows a `printf` formatting mistake. The diagnostic contains
a link to the documentation for the `printf` analyzer.
## Recomputation of diagnostics
Diagnostics are automatically recomputed each time the source files
are edited.
Build errors are updated immediately after each file is edited,
potentially after every keystroke. This ensures rapid feedback of
syntax and type errors while editing.
Analysis diagnostics can be more expensive to compute than type
checking, so they are usually recomputed after a short idle period
following an edit.
The [`diagnosticsDelay`](../settings.md#diagnosticsDelay) setting determines
this period.
Alternatively, diagnostics may be triggered only after an edited file
is saved, using the
[`diagnosticsTrigger`](../settings.md#diagnosticsTrigger) setting.
Gopls does not currently support "pull-based" diagnostics, which are
computed synchronously when requested by the client; see golang/go#53275.
## Quick fixes
Each analyzer diagnostic may suggest one or more alternative
ways to fix the problem by editing the code.
For example, when a `return` statement has too few operands,
the [`fillreturns`](../analyzers.md#fillreturns) analyzer
suggests a fix that heuristically fills in the missing ones
with suitable values. Applying the fix eliminates the build error.
![An analyzer diagnostic with two alternative fixes](../assets/remove-unusedparam-before.png)
The screenshot above shows VS Code's Quick Fix menu for an "unused
parameter" analysis diagnostic with two alternative fixes.
(See [Remove unused parameter](transformation.md#remove-unused-parameter) for more detail.)
Suggested fixes that are indisputably safe are [code
actions](transformation.md#code-actions) whose kind is
`"source.fixAll"`. Many client editors have a shortcut to apply all
such fixes.
TODO(adonovan): audit all the analyzers to ensure that their
documentation is up-to-date w.r.t. any fixes they suggest.
Settings:
- The [`diagnosticsDelay`](../settings.md#diagnosticsDelay) setting determines
the idle period after an edit before diagnostics are recomputed.
- The [`diagnosticsTriggerr`](../settings.md#diagnosticsTrigger) setting determines
what events cause recomputation of diagnostics.
- The [`linkTarget`](../settings.md#linkTarget) setting specifies
the base URI for Go package links in the Diagnostic.CodeDescription field.
Client support:
- **VS Code**: Diagnostics appear as a red squiggly underline.
Hovering reveals the details, along with any suggested fixes.
- **Emacs + eglot**: Diagnostics appear as a red squiggly underline.
Hovering reveals the details. Use `M-x eglot-code-action-quickfix`
to apply available fixes; it will prompt if there are more than one.
- **Vim + coc.nvim**: ??
- **CLI**: `gopls check file.go`
<!--
dorky details and deletia:
- The **vet suite**, of about thirty analyzers
designed to catch likely mistakes in your code.
- **Type-error fixers**. These are gopls-specific analyzers that
enrich diagnostics from the type checker by suggesting fixes for
simple problems.
For example, when a return statement has too few operands, the
[fillreturns](https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/fillreturns) analyzer can heuristically fill in the missing ones
with suitable values.
The actual diagnostics are produced by the type checker,
so these analyzers won't cause you to see any new diagnostics;
but they add fixes to existing ones.
(The user needs to know this because the settings expose it.)
currently: fillreturns nonewvars noresultvalues stubmethods undeclaredname unusedvariable
- **Simplifiers**. These are gopls-specific analyzers that
suggest ways to rewrite your code more simply.
They do not indicate a mistake in your code,
which is why they are not part of `go vet`.
For example, the `simplifyrange` analyzer will eliminate the
unnecessary blank variable in `for _ = range v {...}`.
currently: simplifycompositelit simplifyrange simplifyslice unusedparams infertypeargs
- **Bug detectors**. Gopls has a suite of bug-detecting analyzers that
can't be part of vet for some reason. That might be because they
have dependencies that vet cannot have (e.g. nilness and
unusedwrite, which construct SSA), or because they are tightly
integrated with gopls (e.g. embeddirective, which produces lazy
fixes through the code action mechanism
[But others do that too: undeclaredname embeddirective unusedparams stubmethods]
currently: atomicalign deepequalerrors nilness sortslice unusedwrite embeddirective
- **staticcheck**: four suites:
add(simple.Analyzers, nil)
add(staticcheck.Analyzers - SA5009, SA5011
add(stylecheck.Analyzers, nil)
add(quickfix.Analyzers, nil)
- **Experimental analyzers**. Gopls has some analyzers that are not
enabled by default, because they produce too high a rate of false
positives. For example, fieldalignment, shadow, useany.
Note: fillstruct is not a real analyzer.
-->