Skip to content

Commit c61a2b0

Browse files
committed
gopls/internal/golang: make GCDetails a code action, not a code lens
Before, GCDetails was a code lens source that annotated the package declaration of each file with a command. The command, gopls.gc_details, toggles the per-package flag that controls whether Go compiler optimization details are reported as diagnostics. Code lenses are poorly supported across editors, and this code lens was disabled by default (presumably because VS Code has an alternative custom client-side command to toggle the flag). This change changes the command from being a code lens to code action, offered for any selection in the file; the mechanism of toggling the flag (the gopls.gc_details command) is unchanged, though the redundant ToggleGCDetails command has been eliminated. This change should make it easier for users in a range of editors to both discover and use this useful feature. The new nomenclature avoids "GC" (the old name for the Go compiler, easily confused with "garbage collector"), and instead uses "Toggle compiler optimization details" consistently. (The one exception is the string value of the command, whose name must not be changed since it would break the VS Code client side logic.) + Test, relnote, docs Change-Id: If05f1945914d763396fb9a7626d97e3802a7acbc Reviewed-on: https://go-review.googlesource.com/c/tools/+/639255 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]> Commit-Queue: Alan Donovan <[email protected]>
1 parent fc95c03 commit c61a2b0

26 files changed

+277
-337
lines changed

gopls/doc/codelenses.md

-24
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,6 @@ Client support:
2323

2424
<!-- This portion is generated by doc/generate from the ../internal/settings package. -->
2525
<!-- BEGIN Lenses: DO NOT MANUALLY EDIT THIS SECTION -->
26-
## `gc_details`: Toggle display of Go compiler optimization decisions
27-
28-
29-
This codelens source causes the `package` declaration of
30-
each file to be annotated with a command to toggle the
31-
state of the per-session variable that controls whether
32-
optimization decisions from the Go compiler (formerly known
33-
as "gc") should be displayed as diagnostics.
34-
35-
Optimization decisions include:
36-
- whether a variable escapes, and how escape is inferred;
37-
- whether a nil-pointer check is implied or eliminated;
38-
- whether a function can be inlined.
39-
40-
TODO(adonovan): this source is off by default because the
41-
annotation is annoying and because VS Code has a separate
42-
"Toggle gc details" command. Replace it with a Code Action
43-
("Source action...").
44-
45-
46-
Default: off
47-
48-
File type: Go
49-
5026
## `generate`: Run `go generate`
5127

5228

gopls/doc/features/diagnostics.md

+20
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,26 @@ build`. Gopls doesn't actually run the compiler; that would be too
4949
The example above shows a `printf` formatting mistake. The diagnostic contains
5050
a link to the documentation for the `printf` analyzer.
5151

52+
There is an optional third source of diagnostics:
53+
54+
<a id='toggleCompilerOptDetails'/>
55+
56+
- **Compiler optimization details** are diagnostics that report
57+
details relevant to optimization decisions made by the Go
58+
compiler, such as whether a variable escapes or a slice index
59+
requires a bounds check.
60+
61+
Optimization decisions include:
62+
whether a variable escapes, and how escape is inferred;
63+
whether a nil-pointer check is implied or eliminated; and
64+
whether a function can be inlined.
65+
66+
This source is disabled by default but can be enabled on a
67+
package-by-package basis by invoking the
68+
`source.toggleCompilerOptDetails` ("Toggle compiler optimization
69+
details") code action.
70+
71+
5272
## Recomputation of diagnostics
5373

5474
By default, diagnostics are automatically recomputed each time the source files

gopls/doc/features/transformation.md

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Gopls supports the following code actions:
7070
- [`source.freesymbols`](web.md#freesymbols)
7171
- `source.test` (undocumented) <!-- TODO: fix that -->
7272
- [`source.addTest`](#source.addTest)
73+
- [`source.toggleCompilerOptDetails`](diagnostics.md#toggleCompilerOptDetails)
7374
- [`gopls.doc.features`](README.md), which opens gopls' index of features in a browser
7475
- [`refactor.extract.constant`](#extract)
7576
- [`refactor.extract.function`](#extract)

gopls/doc/release/v0.18.0.md

+16
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,24 @@
22

33
- The experimental `hoverKind=Structured` setting is no longer supported.
44

5+
- The `gc_details` code lens has been deleted. (It was previously
6+
disabled by default.) This functionality is now available through
7+
the `settings.toggleCompilerOptDetails` code action (documented
8+
below), as code actions are better supported than code lenses across
9+
a range of clients.
10+
11+
VS Code's special "Go: Toggle GC details" command continues to work.
12+
513
# New features
614

15+
## "Toggle compiler optimization details" code action
16+
17+
This code action, accessible through the "Source Action" menu in VS
18+
Code, toggles a per-package flag that causes Go compiler optimization
19+
details to be reported as diagnostics. For example, it indicates which
20+
variables escape to the heap, and which array accesses require bounds
21+
checks.
22+
723
## New `modernize` analyzer
824

925
Gopls will now report when code could be simplified or clarified by

gopls/doc/settings.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,12 @@ Example Usage:
184184
...
185185
"codelenses": {
186186
"generate": false, // Don't show the `go generate` lens.
187-
"gc_details": true // Show a code lens toggling the display of gc's choices.
188187
}
189188
...
190189
}
191190
```
192191

193-
Default: `{"gc_details":false,"generate":true,"regenerate_cgo":true,"run_govulncheck":false,"tidy":true,"upgrade_dependency":true,"vendor":true}`.
192+
Default: `{"generate":true,"regenerate_cgo":true,"run_govulncheck":false,"tidy":true,"upgrade_dependency":true,"vendor":true}`.
194193

195194
<a id='semanticTokens'></a>
196195
### `semanticTokens bool`
@@ -321,8 +320,10 @@ Default: `false`.
321320

322321
**This setting is experimental and may be deleted.**
323322

324-
annotations specifies the various kinds of optimization diagnostics
325-
that should be reported by the gc_details command.
323+
annotations specifies the various kinds of compiler
324+
optimization details that should be reported as diagnostics
325+
when enabled for a package by the "Toggle compiler
326+
optimization details" (`gopls.gc_details`) command.
326327

327328
Each enum must be one of:
328329

gopls/internal/cache/diagnostics.go

+15-12
Original file line numberDiff line numberDiff line change
@@ -95,21 +95,24 @@ func (d *Diagnostic) Hash() file.Hash {
9595
return hash
9696
}
9797

98+
// A DiagnosticSource identifies the source of a diagnostic.
99+
//
100+
// Its value may be one of the distinguished string values below, or
101+
// the Name of an [analysis.Analyzer].
98102
type DiagnosticSource string
99103

100104
const (
101-
UnknownError DiagnosticSource = "<Unknown source>"
102-
ListError DiagnosticSource = "go list"
103-
ParseError DiagnosticSource = "syntax"
104-
TypeError DiagnosticSource = "compiler"
105-
ModTidyError DiagnosticSource = "go mod tidy"
106-
OptimizationDetailsError DiagnosticSource = "optimizer details"
107-
UpgradeNotification DiagnosticSource = "upgrade available"
108-
Vulncheck DiagnosticSource = "vulncheck imports"
109-
Govulncheck DiagnosticSource = "govulncheck"
110-
TemplateError DiagnosticSource = "template"
111-
WorkFileError DiagnosticSource = "go.work file"
112-
ConsistencyInfo DiagnosticSource = "consistency"
105+
UnknownError DiagnosticSource = "<Unknown source>"
106+
ListError DiagnosticSource = "go list"
107+
ParseError DiagnosticSource = "syntax"
108+
TypeError DiagnosticSource = "compiler"
109+
ModTidyError DiagnosticSource = "go mod tidy"
110+
CompilerOptDetailsInfo DiagnosticSource = "optimizer details" // cmd/compile -json=0,dir
111+
UpgradeNotification DiagnosticSource = "upgrade available"
112+
Vulncheck DiagnosticSource = "vulncheck imports"
113+
Govulncheck DiagnosticSource = "govulncheck"
114+
TemplateError DiagnosticSource = "template"
115+
WorkFileError DiagnosticSource = "go.work file"
113116
)
114117

115118
// A SuggestedFix represents a suggested fix (for a diagnostic)

gopls/internal/cache/snapshot.go

+19-19
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,9 @@ type Snapshot struct {
183183
// vulns maps each go.mod file's URI to its known vulnerabilities.
184184
vulns *persistent.Map[protocol.DocumentURI, *vulncheck.Result]
185185

186-
// gcOptimizationDetails describes the packages for which we want
187-
// optimization details to be included in the diagnostics.
188-
gcOptimizationDetails map[metadata.PackageID]unit
186+
// compilerOptDetails describes the packages for which we want
187+
// compiler optimization details to be included in the diagnostics.
188+
compilerOptDetails map[metadata.PackageID]unit
189189

190190
// Concurrent type checking:
191191
// typeCheckMu guards the ongoing type checking batch, and reference count of
@@ -1492,7 +1492,7 @@ func (s *Snapshot) clone(ctx, bgCtx context.Context, changed StateChange, done f
14921492

14931493
// TODO(rfindley): reorganize this function to make the derivation of
14941494
// needsDiagnosis clearer.
1495-
needsDiagnosis := len(changed.GCDetails) > 0 || len(changed.ModuleUpgrades) > 0 || len(changed.Vulns) > 0
1495+
needsDiagnosis := len(changed.CompilerOptDetails) > 0 || len(changed.ModuleUpgrades) > 0 || len(changed.Vulns) > 0
14961496

14971497
bgCtx, cancel := context.WithCancel(bgCtx)
14981498
result := &Snapshot{
@@ -1522,22 +1522,22 @@ func (s *Snapshot) clone(ctx, bgCtx context.Context, changed StateChange, done f
15221522
vulns: cloneWith(s.vulns, changed.Vulns),
15231523
}
15241524

1525-
// Compute the new set of packages for which we want gc details, after
1526-
// applying changed.GCDetails.
1527-
if len(s.gcOptimizationDetails) > 0 || len(changed.GCDetails) > 0 {
1528-
newGCDetails := make(map[metadata.PackageID]unit)
1529-
for id := range s.gcOptimizationDetails {
1530-
if _, ok := changed.GCDetails[id]; !ok {
1531-
newGCDetails[id] = unit{} // no change
1525+
// Compute the new set of packages for which we want compiler
1526+
// optimization details, after applying changed.CompilerOptDetails.
1527+
if len(s.compilerOptDetails) > 0 || len(changed.CompilerOptDetails) > 0 {
1528+
newCompilerOptDetails := make(map[metadata.PackageID]unit)
1529+
for id := range s.compilerOptDetails {
1530+
if _, ok := changed.CompilerOptDetails[id]; !ok {
1531+
newCompilerOptDetails[id] = unit{} // no change
15321532
}
15331533
}
1534-
for id, want := range changed.GCDetails {
1534+
for id, want := range changed.CompilerOptDetails {
15351535
if want {
1536-
newGCDetails[id] = unit{}
1536+
newCompilerOptDetails[id] = unit{}
15371537
}
15381538
}
1539-
if len(newGCDetails) > 0 {
1540-
result.gcOptimizationDetails = newGCDetails
1539+
if len(newCompilerOptDetails) > 0 {
1540+
result.compilerOptDetails = newCompilerOptDetails
15411541
}
15421542
}
15431543

@@ -2161,10 +2161,10 @@ func (s *Snapshot) setBuiltin(path string) {
21612161
s.builtin = protocol.URIFromPath(path)
21622162
}
21632163

2164-
// WantGCDetails reports whether to compute GC optimization details for the
2165-
// specified package.
2166-
func (s *Snapshot) WantGCDetails(id metadata.PackageID) bool {
2167-
_, ok := s.gcOptimizationDetails[id]
2164+
// WantCompilerOptDetails reports whether to compute compiler
2165+
// optimization details for the specified package.
2166+
func (s *Snapshot) WantCompilerOptDetails(id metadata.PackageID) bool {
2167+
_, ok := s.compilerOptDetails[id]
21682168
return ok
21692169
}
21702170

gopls/internal/cache/view.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -736,11 +736,11 @@ func (s *Snapshot) initialize(ctx context.Context, firstAttempt bool) {
736736
// By far the most common of these is a change to file state, but a query of
737737
// module upgrade information or vulnerabilities also affects gopls' behavior.
738738
type StateChange struct {
739-
Modifications []file.Modification // if set, the raw modifications originating this change
740-
Files map[protocol.DocumentURI]file.Handle
741-
ModuleUpgrades map[protocol.DocumentURI]map[string]string
742-
Vulns map[protocol.DocumentURI]*vulncheck.Result
743-
GCDetails map[metadata.PackageID]bool // package -> whether or not we want details
739+
Modifications []file.Modification // if set, the raw modifications originating this change
740+
Files map[protocol.DocumentURI]file.Handle
741+
ModuleUpgrades map[protocol.DocumentURI]map[string]string
742+
Vulns map[protocol.DocumentURI]*vulncheck.Result
743+
CompilerOptDetails map[metadata.PackageID]bool // package -> whether or not we want details
744744
}
745745

746746
// InvalidateView processes the provided state change, invalidating any derived

gopls/internal/cmd/integration_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,8 @@ type C struct{}
994994
res.checkExit(true)
995995
got := res.stdout
996996
want := `command "Browse documentation for package a" [source.doc]` +
997+
"\n" +
998+
`command "Toggle compiler optimization details" [source.toggleCompilerOptDetails]` +
997999
"\n"
9981000
if got != want {
9991001
t.Errorf("codeaction: got <<%s>>, want <<%s>>\nstderr:\n%s", got, want, res.stderr)

gopls/internal/doc/api.json

+3-15
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@
638638
{
639639
"Name": "annotations",
640640
"Type": "map[enum]bool",
641-
"Doc": "annotations specifies the various kinds of optimization diagnostics\nthat should be reported by the gc_details command.\n",
641+
"Doc": "annotations specifies the various kinds of compiler\noptimization details that should be reported as diagnostics\nwhen enabled for a package by the \"Toggle compiler\noptimization details\" (`gopls.gc_details`) command.\n",
642642
"EnumKeys": {
643643
"ValueType": "bool",
644644
"Keys": [
@@ -791,15 +791,10 @@
791791
{
792792
"Name": "codelenses",
793793
"Type": "map[enum]bool",
794-
"Doc": "codelenses overrides the enabled/disabled state of each of gopls'\nsources of [Code Lenses](codelenses.md).\n\nExample Usage:\n\n```json5\n\"gopls\": {\n...\n \"codelenses\": {\n \"generate\": false, // Don't show the `go generate` lens.\n \"gc_details\": true // Show a code lens toggling the display of gc's choices.\n }\n...\n}\n```\n",
794+
"Doc": "codelenses overrides the enabled/disabled state of each of gopls'\nsources of [Code Lenses](codelenses.md).\n\nExample Usage:\n\n```json5\n\"gopls\": {\n...\n \"codelenses\": {\n \"generate\": false, // Don't show the `go generate` lens.\n }\n...\n}\n```\n",
795795
"EnumKeys": {
796796
"ValueType": "bool",
797797
"Keys": [
798-
{
799-
"Name": "\"gc_details\"",
800-
"Doc": "`\"gc_details\"`: Toggle display of Go compiler optimization decisions\n\nThis codelens source causes the `package` declaration of\neach file to be annotated with a command to toggle the\nstate of the per-session variable that controls whether\noptimization decisions from the Go compiler (formerly known\nas \"gc\") should be displayed as diagnostics.\n\nOptimization decisions include:\n- whether a variable escapes, and how escape is inferred;\n- whether a nil-pointer check is implied or eliminated;\n- whether a function can be inlined.\n\nTODO(adonovan): this source is off by default because the\nannotation is annoying and because VS Code has a separate\n\"Toggle gc details\" command. Replace it with a Code Action\n(\"Source action...\").\n",
801-
"Default": "false"
802-
},
803798
{
804799
"Name": "\"generate\"",
805800
"Doc": "`\"generate\"`: Run `go generate`\n\nThis codelens source annotates any `//go:generate` comments\nwith commands to run `go generate` in this directory, on\nall directories recursively beneath this one.\n\nSee [Generating code](https://go.dev/blog/generate) for\nmore details.\n",
@@ -843,7 +838,7 @@
843838
]
844839
},
845840
"EnumValues": null,
846-
"Default": "{\"gc_details\":false,\"generate\":true,\"regenerate_cgo\":true,\"run_govulncheck\":false,\"tidy\":true,\"upgrade_dependency\":true,\"vendor\":true}",
841+
"Default": "{\"generate\":true,\"regenerate_cgo\":true,\"run_govulncheck\":false,\"tidy\":true,\"upgrade_dependency\":true,\"vendor\":true}",
847842
"Status": "",
848843
"Hierarchy": "ui"
849844
},
@@ -928,13 +923,6 @@
928923
]
929924
},
930925
"Lenses": [
931-
{
932-
"FileType": "Go",
933-
"Lens": "gc_details",
934-
"Title": "Toggle display of Go compiler optimization decisions",
935-
"Doc": "\nThis codelens source causes the `package` declaration of\neach file to be annotated with a command to toggle the\nstate of the per-session variable that controls whether\noptimization decisions from the Go compiler (formerly known\nas \"gc\") should be displayed as diagnostics.\n\nOptimization decisions include:\n- whether a variable escapes, and how escape is inferred;\n- whether a nil-pointer check is implied or eliminated;\n- whether a function can be inlined.\n\nTODO(adonovan): this source is off by default because the\nannotation is annoying and because VS Code has a separate\n\"Toggle gc details\" command. Replace it with a Code Action\n(\"Source action...\").\n",
936-
"Default": false
937-
},
938926
{
939927
"FileType": "Go",
940928
"Lens": "generate",

gopls/internal/golang/code_lens.go

+3-22
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ import (
2323
// CodeLensSources returns the supported sources of code lenses for Go files.
2424
func CodeLensSources() map[settings.CodeLensSource]cache.CodeLensSourceFunc {
2525
return map[settings.CodeLensSource]cache.CodeLensSourceFunc{
26-
settings.CodeLensGenerate: goGenerateCodeLens, // commands: Generate
27-
settings.CodeLensTest: runTestCodeLens, // commands: Test
28-
settings.CodeLensRegenerateCgo: regenerateCgoLens, // commands: RegenerateCgo
29-
settings.CodeLensGCDetails: toggleDetailsCodeLens, // commands: GCDetails
26+
settings.CodeLensGenerate: goGenerateCodeLens, // commands: Generate
27+
settings.CodeLensTest: runTestCodeLens, // commands: Test
28+
settings.CodeLensRegenerateCgo: regenerateCgoLens, // commands: RegenerateCgo
3029
}
3130
}
3231

@@ -196,21 +195,3 @@ func regenerateCgoLens(ctx context.Context, snapshot *cache.Snapshot, fh file.Ha
196195
cmd := command.NewRegenerateCgoCommand("regenerate cgo definitions", command.URIArg{URI: puri})
197196
return []protocol.CodeLens{{Range: rng, Command: cmd}}, nil
198197
}
199-
200-
func toggleDetailsCodeLens(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle) ([]protocol.CodeLens, error) {
201-
pgf, err := snapshot.ParseGo(ctx, fh, parsego.Full)
202-
if err != nil {
203-
return nil, err
204-
}
205-
if !pgf.File.Package.IsValid() {
206-
// Without a package name we have nowhere to put the codelens, so give up.
207-
return nil, nil
208-
}
209-
rng, err := pgf.PosRange(pgf.File.Package, pgf.File.Package)
210-
if err != nil {
211-
return nil, err
212-
}
213-
puri := fh.URI()
214-
cmd := command.NewGCDetailsCommand("Toggle gc annotation details", puri)
215-
return []protocol.CodeLens{{Range: rng, Command: cmd}}, nil
216-
}

gopls/internal/golang/codeaction.go

+9
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ var codeActionProducers = [...]codeActionProducer{
231231
{kind: settings.GoDoc, fn: goDoc, needPkg: true},
232232
{kind: settings.GoFreeSymbols, fn: goFreeSymbols},
233233
{kind: settings.GoTest, fn: goTest},
234+
{kind: settings.GoToggleCompilerOptDetails, fn: toggleCompilerOptDetails},
234235
{kind: settings.GoplsDocFeatures, fn: goplsDocFeatures},
235236
{kind: settings.RefactorExtractFunction, fn: refactorExtractFunction},
236237
{kind: settings.RefactorExtractMethod, fn: refactorExtractMethod},
@@ -871,3 +872,11 @@ func goAssembly(ctx context.Context, req *codeActionsRequest) error {
871872
}
872873
return nil
873874
}
875+
876+
// toggleCompilerOptDetails produces "Toggle compiler optimization details" code action.
877+
// See [server.commandHandler.ToggleCompilerOptDetails] for command implementation.
878+
func toggleCompilerOptDetails(ctx context.Context, req *codeActionsRequest) error {
879+
cmd := command.NewGCDetailsCommand("Toggle compiler optimization details", req.fh.URI())
880+
req.addCommandAction(cmd, false)
881+
return nil
882+
}

0 commit comments

Comments
 (0)