Skip to content

Commit 34cd474

Browse files
committed
internal/lsp: use an enum for GC annotations settings
The annotations map should use an enum to indicate expected values. For now, we reuse the EnumValues to expose the information in the settings. Later, we'll create a separate EnumKeys field to expose this information more correctly. Also, adjust some of the logic that applies the settings because it was incorrect. Both gopls/doc/settings.md and internal/lsp/source/api_json.go are generated files. Updates golang/go#42961 Change-Id: Ifb032b70caaae73defe9a540df20d098d313e68e Reviewed-on: https://go-review.googlesource.com/c/tools/+/280354 Trust: Rebecca Stambler <[email protected]> Run-TryBot: Rebecca Stambler <[email protected]> gopls-CI: kokoro <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Peter Weinberger <[email protected]>
1 parent b1c9089 commit 34cd474

File tree

6 files changed

+193
-78
lines changed

6 files changed

+193
-78
lines changed

gopls/doc/generate.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,21 @@ func loadOptions(category reflect.Value, pkg *packages.Package) ([]*source.Optio
163163
typ = "enum"
164164
}
165165

166+
// Track any maps whose keys are enums.
167+
enumValues := enums[typesField.Type()]
168+
if m, ok := typesField.Type().(*types.Map); ok {
169+
if e, ok := enums[m.Key()]; ok {
170+
enumValues = e
171+
typ = strings.Replace(typ, m.Key().String(), m.Key().Underlying().String(), 1)
172+
}
173+
}
174+
166175
opts = append(opts, &source.OptionJSON{
167176
Name: lowerFirst(typesField.Name()),
168177
Type: typ,
169178
Doc: lowerFirst(astField.Doc.Text()),
170179
Default: string(defBytes),
171-
EnumValues: enums[typesField.Type()],
180+
EnumValues: enumValues,
172181
})
173182
}
174183
return opts, nil
@@ -378,14 +387,23 @@ func rewriteSettings(doc []byte, api *source.APIJSON) ([]byte, error) {
378387
for _, opt := range opts {
379388
var enumValues strings.Builder
380389
if len(opt.EnumValues) > 0 {
381-
enumValues.WriteString("Must be one of:\n\n")
382-
for _, val := range opt.EnumValues {
390+
var msg string
391+
if opt.Type == "enum" {
392+
msg = "\nMust be one of:\n\n"
393+
} else {
394+
msg = "\nCan contain any of:\n\n"
395+
}
396+
enumValues.WriteString(msg)
397+
for i, val := range opt.EnumValues {
383398
if val.Doc != "" {
384399
// Don't break the list item by starting a new paragraph.
385400
unbroken := parBreakRE.ReplaceAllString(val.Doc, "\\\n")
386-
fmt.Fprintf(&enumValues, " * %s\n", unbroken)
401+
fmt.Fprintf(&enumValues, "* %s", unbroken)
387402
} else {
388-
fmt.Fprintf(&enumValues, " * `%s`\n", val.Value)
403+
fmt.Fprintf(&enumValues, "* `%s`", val.Value)
404+
}
405+
if i < len(opt.EnumValues)-1 {
406+
fmt.Fprint(&enumValues, "\n")
389407
}
390408
}
391409
}

gopls/doc/settings.md

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,18 @@ Default: `{}`.
3636
### **hoverKind** *enum*
3737
hoverKind controls the information that appears in the hover text.
3838
SingleLine and Structured are intended for use only by authors of editor plugins.
39+
3940
Must be one of:
4041

41-
* `"FullDocumentation"`
42-
* `"NoDocumentation"`
43-
* `"SingleLine"`
44-
* `"Structured"` is an experimental setting that returns a structured hover format.
42+
* `"FullDocumentation"`
43+
* `"NoDocumentation"`
44+
* `"SingleLine"`
45+
* `"Structured"` is an experimental setting that returns a structured hover format.
4546
This format separates the signature from the documentation, so that the client
4647
can do more manipulation of these fields.\
4748
This should only be used by clients that support this behavior.
4849

49-
* `"SynopsisDocumentation"`
50-
50+
* `"SynopsisDocumentation"`
5151

5252
Default: `"FullDocumentation"`.
5353
### **usePlaceholders** *bool*
@@ -120,32 +120,32 @@ Default: `true`.
120120
### **importShortcut** *enum*
121121
importShortcut specifies whether import statements should link to
122122
documentation or go to definitions.
123-
Must be one of:
124123

125-
* `"Both"`
126-
* `"Definition"`
127-
* `"Link"`
124+
Must be one of:
128125

126+
* `"Both"`
127+
* `"Definition"`
128+
* `"Link"`
129129

130130
Default: `"Both"`.
131131
### **matcher** *enum*
132132
matcher sets the algorithm that is used when calculating completion candidates.
133-
Must be one of:
134133

135-
* `"CaseInsensitive"`
136-
* `"CaseSensitive"`
137-
* `"Fuzzy"`
134+
Must be one of:
138135

136+
* `"CaseInsensitive"`
137+
* `"CaseSensitive"`
138+
* `"Fuzzy"`
139139

140140
Default: `"Fuzzy"`.
141141
### **symbolMatcher** *enum*
142142
symbolMatcher sets the algorithm that is used when finding workspace symbols.
143-
Must be one of:
144143

145-
* `"CaseInsensitive"`
146-
* `"CaseSensitive"`
147-
* `"Fuzzy"`
144+
Must be one of:
148145

146+
* `"CaseInsensitive"`
147+
* `"CaseSensitive"`
148+
* `"Fuzzy"`
149149

150150
Default: `"Fuzzy"`.
151151
### **symbolStyle** *enum*
@@ -159,21 +159,21 @@ Example Usage:
159159
...
160160
}
161161
```
162+
162163
Must be one of:
163164

164-
* `"Dynamic"` uses whichever qualifier results in the highest scoring
165+
* `"Dynamic"` uses whichever qualifier results in the highest scoring
165166
match for the given symbol query. Here a "qualifier" is any "/" or "."
166167
delimited suffix of the fully qualified symbol. i.e. "to/pkg.Foo.Field" or
167168
just "Foo.Field".
168169

169-
* `"Full"` is fully qualified symbols, i.e.
170+
* `"Full"` is fully qualified symbols, i.e.
170171
"path/to/pkg.Foo.Field".
171172

172-
* `"Package"` is package qualified symbols i.e.
173+
* `"Package"` is package qualified symbols i.e.
173174
"pkg.Foo.Field".
174175

175176

176-
177177
Default: `"Dynamic"`.
178178
### **directoryFilters** *[]string*
179179
directoryFilters can be used to exclude unwanted directories from the
@@ -198,15 +198,21 @@ The below settings are considered experimental. They may be deprecated or change
198198

199199
<!-- BEGIN Experimental: DO NOT MANUALLY EDIT THIS SECTION -->
200200
### **annotations** *map[string]bool*
201-
annotations suppress various kinds of optimization diagnostics
202-
that would be reported by the gc_details command.
203-
* noNilcheck suppresses display of nilchecks.
204-
* noEscape suppresses escape choices.
205-
* noInline suppresses inlining choices.
206-
* noBounds suppresses bounds checking diagnostics.
201+
annotations specifies the various kinds of optimization diagnostics
202+
that should be reported by the gc_details command.
207203

204+
Can contain any of:
208205

209-
Default: `{}`.
206+
* `"bounds"` controls bounds checking diagnostics.
207+
208+
* `"escape"` controls diagnostics about escape choices.
209+
210+
* `"inline"` controls diagnostics about inlining choices.
211+
212+
* `"nil"` controls nil checks.
213+
214+
215+
Default: `{"bounds":true,"escape":true,"inline":true,"nil":true}`.
210216
### **staticcheck** *bool*
211217
staticcheck enables additional analyses from staticcheck.io.
212218

internal/lsp/source/api_json.go

Lines changed: 22 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/lsp/source/gc_annotations.go

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,22 @@ import (
1919
"golang.org/x/tools/internal/span"
2020
)
2121

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+
2238
func GCOptimizationDetails(ctx context.Context, snapshot Snapshot, pkgDir span.URI) (map[VersionedFileIdentity][]*Diagnostic, error) {
2339
outDir := filepath.Join(os.TempDir(), fmt.Sprintf("gopls-%d.details", os.Getpid()))
2440

@@ -113,7 +129,7 @@ func parseDetailsFile(filename string, options *Options) (span.URI, []*Diagnosti
113129
if msg != "" {
114130
msg = fmt.Sprintf("%s(%s)", msg, d.Message)
115131
}
116-
if skipDiagnostic(msg, d.Source, options) {
132+
if !showDiagnostic(msg, d.Source, options) {
117133
continue
118134
}
119135
var related []RelatedInformation
@@ -138,24 +154,27 @@ func parseDetailsFile(filename string, options *Options) (span.URI, []*Diagnosti
138154
return uri, diagnostics, nil
139155
}
140156

141-
// skipDiagnostic reports whether a given diagnostic should be shown to the end
157+
// showDiagnostic reports whether a given diagnostic should be shown to the end
142158
// user, given the current options.
143-
func skipDiagnostic(msg, source string, o *Options) bool {
159+
func showDiagnostic(msg, source string, o *Options) bool {
144160
if source != "go compiler" {
145161
return false
146162
}
163+
if o.Annotations == nil {
164+
return true
165+
}
147166
switch {
148-
case o.Annotations["noInline"]:
149-
return strings.HasPrefix(msg, "canInline") ||
150-
strings.HasPrefix(msg, "cannotInline") ||
151-
strings.HasPrefix(msg, "inlineCall")
152-
case o.Annotations["noEscape"]:
153-
return strings.HasPrefix(msg, "escape") || msg == "leak"
154-
case o.Annotations["noNilcheck"]:
155-
return strings.HasPrefix(msg, "nilcheck")
156-
case o.Annotations["noBounds"]:
157-
return strings.HasPrefix(msg, "isInBounds") ||
158-
strings.HasPrefix(msg, "isSliceInBounds")
167+
case strings.HasPrefix(msg, "canInline") ||
168+
strings.HasPrefix(msg, "cannotInline") ||
169+
strings.HasPrefix(msg, "inlineCall"):
170+
return o.Annotations[Inline]
171+
case strings.HasPrefix(msg, "escape") || msg == "leak":
172+
return o.Annotations[Escape]
173+
case strings.HasPrefix(msg, "nilcheck"):
174+
return o.Annotations[Nil]
175+
case strings.HasPrefix(msg, "isInBounds") ||
176+
strings.HasPrefix(msg, "isSliceInBounds"):
177+
return o.Annotations[Bounds]
159178
}
160179
return false
161180
}

0 commit comments

Comments
 (0)