Skip to content

Commit 66eb306

Browse files
adonovangopherbot
authored andcommitted
Revert "internal/settings: drop "annotations" setting"
This reverts commit 5fe60fd (CL 639835), which removed the ability for users to customize the subset of "annotations" (a misnomer for categories of compiler optimization details). Apparently some users were relying on this experimental feature. Minor tweaks were made to comments but not to logic. Fixes golang/go#71888 Change-Id: I3d0227f841582a2cb29521b9b999546226b670ef Reviewed-on: https://go-review.googlesource.com/c/tools/+/652595 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]>
1 parent ff03c59 commit 66eb306

File tree

6 files changed

+203
-22
lines changed

6 files changed

+203
-22
lines changed

gopls/doc/settings.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,30 @@ These analyses are documented on
355355

356356
Default: `false`.
357357

358+
<a id='annotations'></a>
359+
### `annotations map[enum]bool`
360+
361+
annotations specifies the various kinds of compiler
362+
optimization details that should be reported as diagnostics
363+
when enabled for a package by the "Toggle compiler
364+
optimization details" (`gopls.gc_details`) command.
365+
366+
(Some users care only about one kind of annotation in their
367+
profiling efforts. More importantly, in large packages, the
368+
number of annotations can sometimes overwhelm the user
369+
interface and exceed the per-file diagnostic limit.)
370+
371+
TODO(adonovan): rename this field to CompilerOptDetail.
372+
373+
Each enum must be one of:
374+
375+
* `"bounds"` controls bounds checking diagnostics.
376+
* `"escape"` controls diagnostics about escape choices.
377+
* `"inline"` controls diagnostics about inlining choices.
378+
* `"nil"` controls nil checks.
379+
380+
Default: `{"bounds":true,"escape":true,"inline":true,"nil":true}`.
381+
358382
<a id='vulncheck'></a>
359383
### `vulncheck enum`
360384

gopls/internal/doc/api.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,41 @@
689689
"Hierarchy": "ui.diagnostic",
690690
"DeprecationMessage": ""
691691
},
692+
{
693+
"Name": "annotations",
694+
"Type": "map[enum]bool",
695+
"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\n(Some users care only about one kind of annotation in their\nprofiling efforts. More importantly, in large packages, the\nnumber of annotations can sometimes overwhelm the user\ninterface and exceed the per-file diagnostic limit.)\n\nTODO(adonovan): rename this field to CompilerOptDetail.\n",
696+
"EnumKeys": {
697+
"ValueType": "bool",
698+
"Keys": [
699+
{
700+
"Name": "\"bounds\"",
701+
"Doc": "`\"bounds\"` controls bounds checking diagnostics.\n",
702+
"Default": "true"
703+
},
704+
{
705+
"Name": "\"escape\"",
706+
"Doc": "`\"escape\"` controls diagnostics about escape choices.\n",
707+
"Default": "true"
708+
},
709+
{
710+
"Name": "\"inline\"",
711+
"Doc": "`\"inline\"` controls diagnostics about inlining choices.\n",
712+
"Default": "true"
713+
},
714+
{
715+
"Name": "\"nil\"",
716+
"Doc": "`\"nil\"` controls nil checks.\n",
717+
"Default": "true"
718+
}
719+
]
720+
},
721+
"EnumValues": null,
722+
"Default": "{\"bounds\":true,\"escape\":true,\"inline\":true,\"nil\":true}",
723+
"Status": "",
724+
"Hierarchy": "ui.diagnostic",
725+
"DeprecationMessage": ""
726+
},
692727
{
693728
"Name": "vulncheck",
694729
"Type": "enum",

gopls/internal/golang/compileropt.go

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616

1717
"golang.org/x/tools/gopls/internal/cache"
1818
"golang.org/x/tools/gopls/internal/protocol"
19+
"golang.org/x/tools/gopls/internal/settings"
1920
"golang.org/x/tools/internal/event"
2021
)
2122

@@ -65,7 +66,7 @@ func CompilerOptDetails(ctx context.Context, snapshot *cache.Snapshot, pkgDir pr
6566
reports := make(map[protocol.DocumentURI][]*cache.Diagnostic)
6667
var parseError error
6768
for _, fn := range files {
68-
uri, diagnostics, err := parseDetailsFile(fn)
69+
uri, diagnostics, err := parseDetailsFile(fn, snapshot.Options())
6970
if err != nil {
7071
// expect errors for all the files, save 1
7172
parseError = err
@@ -87,7 +88,7 @@ func CompilerOptDetails(ctx context.Context, snapshot *cache.Snapshot, pkgDir pr
8788
}
8889

8990
// parseDetailsFile parses the file written by the Go compiler which contains a JSON-encoded protocol.Diagnostic.
90-
func parseDetailsFile(filename string) (protocol.DocumentURI, []*cache.Diagnostic, error) {
91+
func parseDetailsFile(filename string, options *settings.Options) (protocol.DocumentURI, []*cache.Diagnostic, error) {
9192
buf, err := os.ReadFile(filename)
9293
if err != nil {
9394
return "", nil, err
@@ -118,30 +119,14 @@ func parseDetailsFile(filename string) (protocol.DocumentURI, []*cache.Diagnosti
118119
if err := dec.Decode(d); err != nil {
119120
return "", nil, err
120121
}
121-
if d.Source != "go compiler" {
122-
continue
123-
}
124122
d.Tags = []protocol.DiagnosticTag{} // must be an actual slice
125123
msg := d.Code.(string)
126124
if msg != "" {
127-
// Typical message prefixes gathered by grepping the source of
128-
// cmd/compile for literal arguments in calls to logopt.LogOpt.
129-
// (It is not a well defined set.)
130-
//
131-
// - canInlineFunction
132-
// - cannotInlineCall
133-
// - cannotInlineFunction
134-
// - copy
135-
// - escape
136-
// - escapes
137-
// - isInBounds
138-
// - isSliceInBounds
139-
// - iteration-variable-to-{heap,stack}
140-
// - leak
141-
// - loop-modified-{range,for}
142-
// - nilcheck
143125
msg = fmt.Sprintf("%s(%s)", msg, d.Message)
144126
}
127+
if !showDiagnostic(msg, d.Source, options) {
128+
continue
129+
}
145130

146131
// zeroIndexedRange subtracts 1 from the line and
147132
// range, because the compiler output neglects to
@@ -186,6 +171,51 @@ func parseDetailsFile(filename string) (protocol.DocumentURI, []*cache.Diagnosti
186171
return uri, diagnostics, nil
187172
}
188173

174+
// showDiagnostic reports whether a given diagnostic should be shown to the end
175+
// user, given the current options.
176+
func showDiagnostic(msg, source string, o *settings.Options) bool {
177+
if source != "go compiler" {
178+
return false
179+
}
180+
if o.Annotations == nil {
181+
return true
182+
}
183+
184+
// The strings below were gathered by grepping the source of
185+
// cmd/compile for literal arguments in calls to logopt.LogOpt.
186+
// (It is not a well defined set.)
187+
//
188+
// - canInlineFunction
189+
// - cannotInlineCall
190+
// - cannotInlineFunction
191+
// - escape
192+
// - escapes
193+
// - isInBounds
194+
// - isSliceInBounds
195+
// - leak
196+
// - nilcheck
197+
//
198+
// Additional ones not handled by logic below:
199+
// - copy
200+
// - iteration-variable-to-{heap,stack}
201+
// - loop-modified-{range,for}
202+
203+
switch {
204+
case strings.HasPrefix(msg, "canInline") ||
205+
strings.HasPrefix(msg, "cannotInline") ||
206+
strings.HasPrefix(msg, "inlineCall"):
207+
return o.Annotations[settings.Inline]
208+
case strings.HasPrefix(msg, "escape") || msg == "leak":
209+
return o.Annotations[settings.Escape]
210+
case strings.HasPrefix(msg, "nilcheck"):
211+
return o.Annotations[settings.Nil]
212+
case strings.HasPrefix(msg, "isInBounds") ||
213+
strings.HasPrefix(msg, "isSliceInBounds"):
214+
return o.Annotations[settings.Bounds]
215+
}
216+
return false
217+
}
218+
189219
func findJSONFiles(dir string) ([]string, error) {
190220
ans := []string{}
191221
f := func(path string, fi os.FileInfo, _ error) error {

gopls/internal/settings/default.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ func DefaultOptions(overrides ...func(*Options)) *Options {
9191
},
9292
UIOptions: UIOptions{
9393
DiagnosticOptions: DiagnosticOptions{
94+
Annotations: map[Annotation]bool{
95+
Bounds: true,
96+
Escape: true,
97+
Inline: true,
98+
Nil: true,
99+
},
94100
Vulncheck: ModeVulncheckOff,
95101
DiagnosticsDelay: 1 * time.Second,
96102
DiagnosticsTrigger: DiagnosticsOnEdit,

gopls/internal/settings/settings.go

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,23 @@ import (
1818
"golang.org/x/tools/gopls/internal/util/frob"
1919
)
2020

21+
// An Annotation is a category of Go compiler optimization diagnostic.
22+
type Annotation string
23+
24+
const (
25+
// Nil controls nil checks.
26+
Nil Annotation = "nil"
27+
28+
// Escape controls diagnostics about escape choices.
29+
Escape Annotation = "escape"
30+
31+
// Inline controls diagnostics about inlining choices.
32+
Inline Annotation = "inline"
33+
34+
// Bounds controls bounds checking diagnostics.
35+
Bounds Annotation = "bounds"
36+
)
37+
2138
// Options holds various configuration that affects Gopls execution, organized
2239
// by the nature or origin of the settings.
2340
//
@@ -436,6 +453,19 @@ type DiagnosticOptions struct {
436453
// [Staticcheck's website](https://staticcheck.io/docs/checks/).
437454
Staticcheck bool `status:"experimental"`
438455

456+
// Annotations specifies the various kinds of compiler
457+
// optimization details that should be reported as diagnostics
458+
// when enabled for a package by the "Toggle compiler
459+
// optimization details" (`gopls.gc_details`) command.
460+
//
461+
// (Some users care only about one kind of annotation in their
462+
// profiling efforts. More importantly, in large packages, the
463+
// number of annotations can sometimes overwhelm the user
464+
// interface and exceed the per-file diagnostic limit.)
465+
//
466+
// TODO(adonovan): rename this field to CompilerOptDetail.
467+
Annotations map[Annotation]bool
468+
439469
// Vulncheck enables vulnerability scanning.
440470
Vulncheck VulncheckMode `status:"experimental"`
441471

@@ -1124,7 +1154,7 @@ func (o *Options) setOne(name string, value any) (applied []CounterPath, _ error
11241154
return setBoolMap(&o.Hints, value)
11251155

11261156
case "annotations":
1127-
return nil, &SoftError{"the 'annotations' setting was removed in gopls/v0.18.0; all compiler optimization details are now shown"}
1157+
return setAnnotationMap(&o.Annotations, value)
11281158

11291159
case "vulncheck":
11301160
return setEnum(&o.Vulncheck, value,
@@ -1420,6 +1450,51 @@ func setDuration(dest *time.Duration, value any) error {
14201450
return nil
14211451
}
14221452

1453+
func setAnnotationMap(dest *map[Annotation]bool, value any) ([]CounterPath, error) {
1454+
all, err := asBoolMap[string](value)
1455+
if err != nil {
1456+
return nil, err
1457+
}
1458+
var counters []CounterPath
1459+
// Default to everything enabled by default.
1460+
m := make(map[Annotation]bool)
1461+
for k, enabled := range all {
1462+
var a Annotation
1463+
cnts, err := setEnum(&a, k,
1464+
Nil,
1465+
Escape,
1466+
Inline,
1467+
Bounds)
1468+
if err != nil {
1469+
// In case of an error, process any legacy values.
1470+
switch k {
1471+
case "noEscape":
1472+
m[Escape] = false
1473+
return nil, fmt.Errorf(`"noEscape" is deprecated, set "Escape: false" instead`)
1474+
1475+
case "noNilcheck":
1476+
m[Nil] = false
1477+
return nil, fmt.Errorf(`"noNilcheck" is deprecated, set "Nil: false" instead`)
1478+
1479+
case "noInline":
1480+
m[Inline] = false
1481+
return nil, fmt.Errorf(`"noInline" is deprecated, set "Inline: false" instead`)
1482+
1483+
case "noBounds":
1484+
m[Bounds] = false
1485+
return nil, fmt.Errorf(`"noBounds" is deprecated, set "Bounds: false" instead`)
1486+
1487+
default:
1488+
return nil, err
1489+
}
1490+
}
1491+
counters = append(counters, cnts...)
1492+
m[a] = enabled
1493+
}
1494+
*dest = m
1495+
return counters, nil
1496+
}
1497+
14231498
func setBoolMap[K ~string](dest *map[K]bool, value any) ([]CounterPath, error) {
14241499
m, err := asBoolMap[K](value)
14251500
if err != nil {

gopls/internal/settings/settings_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,17 @@ func TestOptions_Set(t *testing.T) {
180180
return len(o.DirectoryFilters) == 0
181181
},
182182
},
183+
{
184+
name: "annotations",
185+
value: map[string]any{
186+
"Nil": false,
187+
"noBounds": true,
188+
},
189+
wantError: true,
190+
check: func(o Options) bool {
191+
return !o.Annotations[Nil] && !o.Annotations[Bounds]
192+
},
193+
},
183194
{
184195
name: "vulncheck",
185196
value: []any{"invalid"},

0 commit comments

Comments
 (0)