Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / internal / lsp / source / options.go
1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package source
6
7 import (
8         "context"
9         "fmt"
10         "regexp"
11         "strings"
12         "sync"
13         "time"
14
15         "golang.org/x/tools/go/analysis"
16         "golang.org/x/tools/go/analysis/passes/asmdecl"
17         "golang.org/x/tools/go/analysis/passes/assign"
18         "golang.org/x/tools/go/analysis/passes/atomic"
19         "golang.org/x/tools/go/analysis/passes/atomicalign"
20         "golang.org/x/tools/go/analysis/passes/bools"
21         "golang.org/x/tools/go/analysis/passes/buildtag"
22         "golang.org/x/tools/go/analysis/passes/cgocall"
23         "golang.org/x/tools/go/analysis/passes/composite"
24         "golang.org/x/tools/go/analysis/passes/copylock"
25         "golang.org/x/tools/go/analysis/passes/deepequalerrors"
26         "golang.org/x/tools/go/analysis/passes/errorsas"
27         "golang.org/x/tools/go/analysis/passes/httpresponse"
28         "golang.org/x/tools/go/analysis/passes/loopclosure"
29         "golang.org/x/tools/go/analysis/passes/lostcancel"
30         "golang.org/x/tools/go/analysis/passes/nilfunc"
31         "golang.org/x/tools/go/analysis/passes/printf"
32         "golang.org/x/tools/go/analysis/passes/shift"
33         "golang.org/x/tools/go/analysis/passes/sortslice"
34         "golang.org/x/tools/go/analysis/passes/stdmethods"
35         "golang.org/x/tools/go/analysis/passes/structtag"
36         "golang.org/x/tools/go/analysis/passes/testinggoroutine"
37         "golang.org/x/tools/go/analysis/passes/tests"
38         "golang.org/x/tools/go/analysis/passes/unmarshal"
39         "golang.org/x/tools/go/analysis/passes/unreachable"
40         "golang.org/x/tools/go/analysis/passes/unsafeptr"
41         "golang.org/x/tools/go/analysis/passes/unusedresult"
42         "golang.org/x/tools/internal/lsp/analysis/fillreturns"
43         "golang.org/x/tools/internal/lsp/analysis/fillstruct"
44         "golang.org/x/tools/internal/lsp/analysis/nonewvars"
45         "golang.org/x/tools/internal/lsp/analysis/noresultvalues"
46         "golang.org/x/tools/internal/lsp/analysis/simplifycompositelit"
47         "golang.org/x/tools/internal/lsp/analysis/simplifyrange"
48         "golang.org/x/tools/internal/lsp/analysis/simplifyslice"
49         "golang.org/x/tools/internal/lsp/analysis/undeclaredname"
50         "golang.org/x/tools/internal/lsp/analysis/unusedparams"
51         "golang.org/x/tools/internal/lsp/diff"
52         "golang.org/x/tools/internal/lsp/diff/myers"
53         "golang.org/x/tools/internal/lsp/protocol"
54         errors "golang.org/x/xerrors"
55 )
56
57 var (
58         optionsOnce    sync.Once
59         defaultOptions *Options
60 )
61
62 //go:generate go run golang.org/x/tools/internal/lsp/source/genapijson -output api_json.go
63
64 // DefaultOptions is the options that are used for Gopls execution independent
65 // of any externally provided configuration (LSP initialization, command
66 // invokation, etc.).
67 func DefaultOptions() *Options {
68         optionsOnce.Do(func() {
69                 var commands []string
70                 for _, c := range Commands {
71                         commands = append(commands, c.ID())
72                 }
73                 defaultOptions = &Options{
74                         ClientOptions: ClientOptions{
75                                 InsertTextFormat:                  protocol.PlainTextTextFormat,
76                                 PreferredContentFormat:            protocol.Markdown,
77                                 ConfigurationSupported:            true,
78                                 DynamicConfigurationSupported:     true,
79                                 DynamicWatchedFilesSupported:      true,
80                                 LineFoldingOnly:                   false,
81                                 HierarchicalDocumentSymbolSupport: true,
82                         },
83                         ServerOptions: ServerOptions{
84                                 SupportedCodeActions: map[FileKind]map[protocol.CodeActionKind]bool{
85                                         Go: {
86                                                 protocol.SourceFixAll:          true,
87                                                 protocol.SourceOrganizeImports: true,
88                                                 protocol.QuickFix:              true,
89                                                 protocol.RefactorRewrite:       true,
90                                                 protocol.RefactorExtract:       true,
91                                         },
92                                         Mod: {
93                                                 protocol.SourceOrganizeImports: true,
94                                         },
95                                         Sum: {},
96                                 },
97                                 SupportedCommands: commands,
98                         },
99                         UserOptions: UserOptions{
100                                 HoverKind:  FullDocumentation,
101                                 LinkTarget: "pkg.go.dev",
102                         },
103                         DebuggingOptions: DebuggingOptions{
104                                 CompletionBudget: 100 * time.Millisecond,
105                         },
106                         ExperimentalOptions: ExperimentalOptions{
107                                 TempModfile:             true,
108                                 ExpandWorkspaceToModule: true,
109                                 Codelens: map[string]bool{
110                                         CommandGenerate.Name:          true,
111                                         CommandRegenerateCgo.Name:     true,
112                                         CommandTidy.Name:              true,
113                                         CommandToggleDetails.Name:     false,
114                                         CommandUpgradeDependency.Name: true,
115                                         CommandVendor.Name:            true,
116                                 },
117                                 LinksInHover:            true,
118                                 CompleteUnimported:      true,
119                                 CompletionDocumentation: true,
120                                 DeepCompletion:          true,
121                                 ImportShortcut:          Both,
122                                 Matcher:                 Fuzzy,
123                                 SymbolMatcher:           SymbolFuzzy,
124                                 SymbolStyle:             PackageQualifiedSymbols,
125                         },
126                         InternalOptions: InternalOptions{
127                                 LiteralCompletions: true,
128                         },
129                         Hooks: Hooks{
130                                 ComputeEdits:         myers.ComputeEdits,
131                                 URLRegexp:            urlRegexp(),
132                                 DefaultAnalyzers:     defaultAnalyzers(),
133                                 TypeErrorAnalyzers:   typeErrorAnalyzers(),
134                                 ConvenienceAnalyzers: convenienceAnalyzers(),
135                                 StaticcheckAnalyzers: map[string]Analyzer{},
136                                 GoDiff:               true,
137                         },
138                 }
139         })
140         return defaultOptions
141 }
142
143 // Options holds various configuration that affects Gopls execution, organized
144 // by the nature or origin of the settings.
145 type Options struct {
146         ClientOptions
147         ServerOptions
148         UserOptions
149         DebuggingOptions
150         ExperimentalOptions
151         InternalOptions
152         Hooks
153 }
154
155 // ClientOptions holds LSP-specific configuration that is provided by the
156 // client.
157 type ClientOptions struct {
158         InsertTextFormat                  protocol.InsertTextFormat
159         ConfigurationSupported            bool
160         DynamicConfigurationSupported     bool
161         DynamicWatchedFilesSupported      bool
162         PreferredContentFormat            protocol.MarkupKind
163         LineFoldingOnly                   bool
164         HierarchicalDocumentSymbolSupport bool
165 }
166
167 // ServerOptions holds LSP-specific configuration that is provided by the
168 // server.
169 type ServerOptions struct {
170         SupportedCodeActions map[FileKind]map[protocol.CodeActionKind]bool
171         SupportedCommands    []string
172 }
173
174 // UserOptions holds custom Gopls configuration (not part of the LSP) that is
175 // modified by the client.
176 type UserOptions struct {
177         // BuildFlags is the set of flags passed on to the build system when invoked.
178         // It is applied to queries like `go list`, which is used when discovering files.
179         // The most common use is to set `-tags`.
180         BuildFlags []string
181
182         // Env adds environment variables to external commands run by `gopls`, most notably `go list`.
183         Env map[string]string
184
185         // HoverKind controls the information that appears in the hover text.
186         // SingleLine and Structured are intended for use only by authors of editor plugins.
187         HoverKind HoverKind
188
189         // Placeholders enables placeholders for function parameters or struct fields in completion responses.
190         UsePlaceholders bool
191
192         // LinkTarget controls where documentation links go.
193         // It might be one of:
194         //
195         // * `"godoc.org"`
196         // * `"pkg.go.dev"`
197         //
198         // If company chooses to use its own `godoc.org`, its address can be used as well.
199         LinkTarget string
200
201         // Local is the equivalent of the `goimports -local` flag, which puts imports beginning with this string after 3rd-party packages.
202         // It should be the prefix of the import path whose imports should be grouped separately.
203         Local string
204
205         // Gofumpt indicates if we should run gofumpt formatting.
206         Gofumpt bool
207 }
208
209 // EnvSlice returns Env as a slice of k=v strings.
210 func (u *UserOptions) EnvSlice() []string {
211         var result []string
212         for k, v := range u.Env {
213                 result = append(result, fmt.Sprintf("%v=%v", k, v))
214         }
215         return result
216 }
217
218 // SetEnvSlice sets Env from a slice of k=v strings.
219 func (u *UserOptions) SetEnvSlice(env []string) {
220         u.Env = map[string]string{}
221         for _, kv := range env {
222                 split := strings.SplitN(kv, "=", 2)
223                 if len(split) != 2 {
224                         continue
225                 }
226                 u.Env[split[0]] = split[1]
227         }
228 }
229
230 // Hooks contains configuration that is provided to the Gopls command by the
231 // main package.
232 type Hooks struct {
233         GoDiff               bool
234         ComputeEdits         diff.ComputeEdits
235         URLRegexp            *regexp.Regexp
236         GofumptFormat        func(ctx context.Context, src []byte) ([]byte, error)
237         DefaultAnalyzers     map[string]Analyzer
238         TypeErrorAnalyzers   map[string]Analyzer
239         ConvenienceAnalyzers map[string]Analyzer
240         StaticcheckAnalyzers map[string]Analyzer
241 }
242
243 // ExperimentalOptions defines configuration for features under active
244 // development. WARNING: This configuration will be changed in the future. It
245 // only exists while these features are under development.
246 type ExperimentalOptions struct {
247         // Analyses specify analyses that the user would like to enable or disable.
248         // A map of the names of analysis passes that should be enabled/disabled.
249         // A full list of analyzers that gopls uses can be found [here](analyzers.md)
250         //
251         // Example Usage:
252         // ```json5
253         // ...
254         // "analyses": {
255         //   "unreachable": false, // Disable the unreachable analyzer.
256         //   "unusedparams": true  // Enable the unusedparams analyzer.
257         // }
258         // ...
259         // ```
260         Analyses map[string]bool
261
262         // Codelens overrides the enabled/disabled state of code lenses. See the "Code Lenses"
263         // section of settings.md for the list of supported lenses.
264         //
265         // Example Usage:
266         // ```json5
267         // "gopls": {
268         // ...
269         //   "codelens": {
270         //     "generate": false,  // Don't show the `go generate` lens.
271         //     "gc_details": true  // Show a code lens toggling the display of gc's choices.
272         //   }
273         // ...
274         // }
275         // ```
276         Codelens map[string]bool
277
278         // CompletionDocumentation enables documentation with completion results.
279         CompletionDocumentation bool
280
281         // CompleteUnimported enables completion for packages that you do not currently import.
282         CompleteUnimported bool
283
284         // DeepCompletion enables the ability to return completions from deep inside relevant entities, rather than just the locally accessible ones.
285         //
286         // Consider this example:
287         //
288         // ```go
289         // package main
290         //
291         // import "fmt"
292         //
293         // type wrapString struct {
294         //     str string
295         // }
296         //
297         // func main() {
298         //     x := wrapString{"hello world"}
299         //     fmt.Printf(<>)
300         // }
301         // ```
302         //
303         // At the location of the `<>` in this program, deep completion would suggest the result `x.str`.
304         DeepCompletion bool
305
306         // Matcher sets the algorithm that is used when calculating completion candidates.
307         Matcher Matcher
308
309         // Annotations suppress various kinds of optimization diagnostics
310         // that would be reported by the gc_details command.
311         //  * noNilcheck suppresses display of nilchecks.
312         //  * noEscape suppresses escape choices.
313         //  * noInline suppresses inlining choices.
314         //  * noBounds suppresses bounds checking diagnostics.
315         Annotations map[string]bool
316
317         // Staticcheck enables additional analyses from staticcheck.io.
318         Staticcheck bool
319
320         // SymbolMatcher sets the algorithm that is used when finding workspace symbols.
321         SymbolMatcher SymbolMatcher
322
323         // SymbolStyle controls how symbols are qualified in symbol responses.
324         //
325         // Example Usage:
326         // ```json5
327         // "gopls": {
328         // ...
329         //   "symbolStyle": "dynamic",
330         // ...
331         // }
332         // ```
333         SymbolStyle SymbolStyle
334
335         // LinksInHover toggles the presence of links to documentation in hover.
336         LinksInHover bool
337
338         // TempModfile controls the use of the -modfile flag in Go 1.14.
339         TempModfile bool
340
341         // ImportShortcut specifies whether import statements should link to
342         // documentation or go to definitions.
343         ImportShortcut ImportShortcut
344
345         // VerboseWorkDoneProgress controls whether the LSP server should send
346         // progress reports for all work done outside the scope of an RPC.
347         VerboseWorkDoneProgress bool
348
349         // SemanticTokens controls whether the LSP server will send
350         // semantic tokens to the client.
351         SemanticTokens bool
352
353         // ExpandWorkspaceToModule instructs `gopls` to expand the scope of the workspace to include the
354         // modules containing the workspace folders. Set this to false to avoid loading
355         // your entire module. This is particularly useful for those working in a monorepo.
356         ExpandWorkspaceToModule bool
357
358         // ExperimentalWorkspaceModule opts a user into the experimental support
359         // for multi-module workspaces.
360         ExperimentalWorkspaceModule bool
361
362         // ExperimentalDiagnosticsDelay controls the amount of time that gopls waits
363         // after the most recent file modification before computing deep diagnostics.
364         // Simple diagnostics (parsing and type-checking) are always run immediately
365         // on recently modified packages.
366         //
367         // This option must be set to a valid duration string, for example `"250ms"`.
368         ExperimentalDiagnosticsDelay time.Duration
369
370         // ExperimentalPackageCacheKey controls whether to use a coarser cache key
371         // for package type information to increase cache hits. This setting removes
372         // the user's environment, build flags, and working directory from the cache
373         // key, which should be a safe change as all relevant inputs into the type
374         // checking pass are already hashed into the key. This is temporarily guarded
375         // by an experiment because caching behavior is subtle and difficult to
376         // comprehensively test.
377         ExperimentalPackageCacheKey bool
378 }
379
380 // DebuggingOptions should not affect the logical execution of Gopls, but may
381 // be altered for debugging purposes.
382 type DebuggingOptions struct {
383         // VerboseOutput enables additional debug logging.
384         VerboseOutput bool
385
386         // CompletionBudget is the soft latency goal for completion requests. Most
387         // requests finish in a couple milliseconds, but in some cases deep
388         // completions can take much longer. As we use up our budget we
389         // dynamically reduce the search scope to ensure we return timely
390         // results. Zero means unlimited.
391         CompletionBudget time.Duration
392 }
393
394 // InternalOptions contains settings that are not exposed to the user for various
395 // reasons, e.g. settings used by tests.
396 type InternalOptions struct {
397         // LiteralCompletions controls whether literal candidates such as
398         // "&someStruct{}" are offered. Tests disable this flag to simplify
399         // their expected values.
400         LiteralCompletions bool
401 }
402
403 type ImportShortcut string
404
405 const (
406         Both       ImportShortcut = "Both"
407         Link       ImportShortcut = "Link"
408         Definition ImportShortcut = "Definition"
409 )
410
411 func (s ImportShortcut) ShowLinks() bool {
412         return s == Both || s == Link
413 }
414
415 func (s ImportShortcut) ShowDefinition() bool {
416         return s == Both || s == Definition
417 }
418
419 type Matcher string
420
421 const (
422         Fuzzy           Matcher = "Fuzzy"
423         CaseInsensitive Matcher = "CaseInsensitive"
424         CaseSensitive   Matcher = "CaseSensitive"
425 )
426
427 type SymbolMatcher string
428
429 const (
430         SymbolFuzzy           SymbolMatcher = "Fuzzy"
431         SymbolCaseInsensitive SymbolMatcher = "CaseInsensitive"
432         SymbolCaseSensitive   SymbolMatcher = "CaseSensitive"
433 )
434
435 type SymbolStyle string
436
437 const (
438         // PackageQualifiedSymbols is package qualified symbols i.e.
439         // "pkg.Foo.Field".
440         PackageQualifiedSymbols SymbolStyle = "Package"
441         // FullyQualifiedSymbols is fully qualified symbols, i.e.
442         // "path/to/pkg.Foo.Field".
443         FullyQualifiedSymbols SymbolStyle = "Full"
444         // DynamicSymbols uses whichever qualifier results in the highest scoring
445         // match for the given symbol query. Here a "qualifier" is any "/" or "."
446         // delimited suffix of the fully qualified symbol. i.e. "to/pkg.Foo.Field" or
447         // just "Foo.Field".
448         DynamicSymbols SymbolStyle = "Dynamic"
449 )
450
451 type HoverKind string
452
453 const (
454         SingleLine            HoverKind = "SingleLine"
455         NoDocumentation       HoverKind = "NoDocumentation"
456         SynopsisDocumentation HoverKind = "SynopsisDocumentation"
457         FullDocumentation     HoverKind = "FullDocumentation"
458
459         // Structured is an experimental setting that returns a structured hover format.
460         // This format separates the signature from the documentation, so that the client
461         // can do more manipulation of these fields.
462         //
463         // This should only be used by clients that support this behavior.
464         Structured HoverKind = "Structured"
465 )
466
467 type OptionResults []OptionResult
468
469 type OptionResult struct {
470         Name  string
471         Value interface{}
472         Error error
473
474         State       OptionState
475         Replacement string
476 }
477
478 type OptionState int
479
480 const (
481         OptionHandled = OptionState(iota)
482         OptionDeprecated
483         OptionUnexpected
484 )
485
486 type LinkTarget string
487
488 func SetOptions(options *Options, opts interface{}) OptionResults {
489         var results OptionResults
490         switch opts := opts.(type) {
491         case nil:
492         case map[string]interface{}:
493                 // If the user's settings contains "allExperiments", set that first,
494                 // and then let them override individual settings independently.
495                 var enableExperiments bool
496                 for name, value := range opts {
497                         if b, ok := value.(bool); name == "allExperiments" && ok && b {
498                                 enableExperiments = true
499                                 options.enableAllExperiments()
500                         }
501                 }
502                 for name, value := range opts {
503                         results = append(results, options.set(name, value))
504                 }
505                 // Finally, enable any experimental features that are specified in
506                 // maps, which allows users to individually toggle them on or off.
507                 if enableExperiments {
508                         options.enableAllExperimentMaps()
509                 }
510         default:
511                 results = append(results, OptionResult{
512                         Value: opts,
513                         Error: errors.Errorf("Invalid options type %T", opts),
514                 })
515         }
516         return results
517 }
518
519 func (o *Options) ForClientCapabilities(caps protocol.ClientCapabilities) {
520         // Check if the client supports snippets in completion items.
521         if c := caps.TextDocument.Completion; c.CompletionItem.SnippetSupport {
522                 o.InsertTextFormat = protocol.SnippetTextFormat
523         }
524         // Check if the client supports configuration messages.
525         o.ConfigurationSupported = caps.Workspace.Configuration
526         o.DynamicConfigurationSupported = caps.Workspace.DidChangeConfiguration.DynamicRegistration
527         o.DynamicWatchedFilesSupported = caps.Workspace.DidChangeWatchedFiles.DynamicRegistration
528
529         // Check which types of content format are supported by this client.
530         if hover := caps.TextDocument.Hover; len(hover.ContentFormat) > 0 {
531                 o.PreferredContentFormat = hover.ContentFormat[0]
532         }
533         // Check if the client supports only line folding.
534         fr := caps.TextDocument.FoldingRange
535         o.LineFoldingOnly = fr.LineFoldingOnly
536         // Check if the client supports hierarchical document symbols.
537         o.HierarchicalDocumentSymbolSupport = caps.TextDocument.DocumentSymbol.HierarchicalDocumentSymbolSupport
538 }
539
540 func (o *Options) Clone() *Options {
541         result := &Options{
542                 ClientOptions:       o.ClientOptions,
543                 DebuggingOptions:    o.DebuggingOptions,
544                 ExperimentalOptions: o.ExperimentalOptions,
545                 InternalOptions:     o.InternalOptions,
546                 Hooks: Hooks{
547                         GoDiff:        o.Hooks.GoDiff,
548                         ComputeEdits:  o.Hooks.ComputeEdits,
549                         GofumptFormat: o.GofumptFormat,
550                         URLRegexp:     o.URLRegexp,
551                 },
552                 ServerOptions: o.ServerOptions,
553                 UserOptions:   o.UserOptions,
554         }
555         // Fully clone any slice or map fields. Only Hooks, ExperimentalOptions,
556         // and UserOptions can be modified.
557         copyStringMap := func(src map[string]bool) map[string]bool {
558                 dst := make(map[string]bool)
559                 for k, v := range src {
560                         dst[k] = v
561                 }
562                 return dst
563         }
564         result.Analyses = copyStringMap(o.Analyses)
565         result.Annotations = copyStringMap(o.Annotations)
566         result.Codelens = copyStringMap(o.Codelens)
567
568         copySlice := func(src []string) []string {
569                 dst := make([]string, len(src))
570                 copy(dst, src)
571                 return dst
572         }
573         result.SetEnvSlice(o.EnvSlice())
574         result.BuildFlags = copySlice(o.BuildFlags)
575
576         copyAnalyzerMap := func(src map[string]Analyzer) map[string]Analyzer {
577                 dst := make(map[string]Analyzer)
578                 for k, v := range src {
579                         dst[k] = v
580                 }
581                 return dst
582         }
583         result.DefaultAnalyzers = copyAnalyzerMap(o.DefaultAnalyzers)
584         result.TypeErrorAnalyzers = copyAnalyzerMap(o.TypeErrorAnalyzers)
585         result.ConvenienceAnalyzers = copyAnalyzerMap(o.ConvenienceAnalyzers)
586         result.StaticcheckAnalyzers = copyAnalyzerMap(o.StaticcheckAnalyzers)
587         return result
588 }
589
590 func (o *Options) AddStaticcheckAnalyzer(a *analysis.Analyzer) {
591         o.StaticcheckAnalyzers[a.Name] = Analyzer{Analyzer: a, Enabled: true}
592 }
593
594 // enableAllExperiments turns on all of the experimental "off-by-default"
595 // features offered by gopls.
596 // Any experimental features specified in maps should be enabled in
597 // enableAllExperimentMaps.
598 func (o *Options) enableAllExperiments() {
599         o.ExperimentalDiagnosticsDelay = 200 * time.Millisecond
600         o.ExperimentalPackageCacheKey = true
601         o.SymbolStyle = DynamicSymbols
602 }
603
604 func (o *Options) enableAllExperimentMaps() {
605         if _, ok := o.Codelens[CommandToggleDetails.Name]; !ok {
606                 o.Codelens[CommandToggleDetails.Name] = true
607         }
608         if _, ok := o.Analyses[unusedparams.Analyzer.Name]; !ok {
609                 o.Analyses[unusedparams.Analyzer.Name] = true
610         }
611 }
612
613 func (o *Options) set(name string, value interface{}) OptionResult {
614         result := OptionResult{Name: name, Value: value}
615         switch name {
616         case "env":
617                 menv, ok := value.(map[string]interface{})
618                 if !ok {
619                         result.errorf("invalid type %T, expect map", value)
620                         break
621                 }
622                 for k, v := range menv {
623                         o.Env[k] = fmt.Sprint(v)
624                 }
625
626         case "buildFlags":
627                 iflags, ok := value.([]interface{})
628                 if !ok {
629                         result.errorf("invalid type %T, expect list", value)
630                         break
631                 }
632                 flags := make([]string, 0, len(iflags))
633                 for _, flag := range iflags {
634                         flags = append(flags, fmt.Sprintf("%s", flag))
635                 }
636                 o.BuildFlags = flags
637
638         case "completionDocumentation":
639                 result.setBool(&o.CompletionDocumentation)
640         case "usePlaceholders":
641                 result.setBool(&o.UsePlaceholders)
642         case "deepCompletion":
643                 result.setBool(&o.DeepCompletion)
644         case "completeUnimported":
645                 result.setBool(&o.CompleteUnimported)
646         case "completionBudget":
647                 result.setDuration(&o.CompletionBudget)
648         case "matcher":
649                 if s, ok := result.asOneOf(
650                         string(Fuzzy),
651                         string(CaseSensitive),
652                         string(CaseInsensitive),
653                 ); ok {
654                         o.Matcher = Matcher(s)
655                 }
656
657         case "symbolMatcher":
658                 if s, ok := result.asOneOf(
659                         string(SymbolFuzzy),
660                         string(SymbolCaseInsensitive),
661                         string(SymbolCaseSensitive),
662                 ); ok {
663                         o.SymbolMatcher = SymbolMatcher(s)
664                 }
665
666         case "symbolStyle":
667                 if s, ok := result.asOneOf(
668                         string(FullyQualifiedSymbols),
669                         string(PackageQualifiedSymbols),
670                         string(DynamicSymbols),
671                 ); ok {
672                         o.SymbolStyle = SymbolStyle(s)
673                 }
674
675         case "hoverKind":
676                 if s, ok := result.asOneOf(
677                         string(NoDocumentation),
678                         string(SingleLine),
679                         string(SynopsisDocumentation),
680                         string(FullDocumentation),
681                         string(Structured),
682                 ); ok {
683                         o.HoverKind = HoverKind(s)
684                 }
685
686         case "linkTarget":
687                 result.setString(&o.LinkTarget)
688
689         case "linksInHover":
690                 result.setBool(&o.LinksInHover)
691
692         case "importShortcut":
693                 if s, ok := result.asOneOf(string(Both), string(Link), string(Definition)); ok {
694                         o.ImportShortcut = ImportShortcut(s)
695                 }
696
697         case "analyses":
698                 result.setBoolMap(&o.Analyses)
699
700         case "annotations":
701                 result.setBoolMap(&o.Annotations)
702                 for k := range o.Annotations {
703                         switch k {
704                         case "noEscape", "noNilcheck", "noInline", "noBounds":
705                                 continue
706                         default:
707                                 result.Name += ":" + k // put mistake(s) in the message
708                                 result.State = OptionUnexpected
709                         }
710                 }
711
712         case "codelens":
713                 var lensOverrides map[string]bool
714                 result.setBoolMap(&lensOverrides)
715                 if result.Error == nil {
716                         if o.Codelens == nil {
717                                 o.Codelens = make(map[string]bool)
718                         }
719                         for lens, enabled := range lensOverrides {
720                                 o.Codelens[lens] = enabled
721                         }
722                 }
723
724         case "staticcheck":
725                 result.setBool(&o.Staticcheck)
726
727         case "local":
728                 result.setString(&o.Local)
729
730         case "verboseOutput":
731                 result.setBool(&o.VerboseOutput)
732
733         case "verboseWorkDoneProgress":
734                 result.setBool(&o.VerboseWorkDoneProgress)
735
736         case "tempModfile":
737                 result.setBool(&o.TempModfile)
738
739         case "gofumpt":
740                 result.setBool(&o.Gofumpt)
741
742         case "semanticTokens":
743                 result.setBool(&o.SemanticTokens)
744
745         case "expandWorkspaceToModule":
746                 result.setBool(&o.ExpandWorkspaceToModule)
747
748         case "experimentalWorkspaceModule":
749                 result.setBool(&o.ExperimentalWorkspaceModule)
750
751         case "experimentalDiagnosticsDelay":
752                 result.setDuration(&o.ExperimentalDiagnosticsDelay)
753
754         case "experimentalPackageCacheKey":
755                 result.setBool(&o.ExperimentalPackageCacheKey)
756
757         case "allExperiments":
758                 // This setting should be handled before all of the other options are
759                 // processed, so do nothing here.
760
761         // Replaced settings.
762         case "experimentalDisabledAnalyses":
763                 result.State = OptionDeprecated
764                 result.Replacement = "analyses"
765
766         case "disableDeepCompletion":
767                 result.State = OptionDeprecated
768                 result.Replacement = "deepCompletion"
769
770         case "disableFuzzyMatching":
771                 result.State = OptionDeprecated
772                 result.Replacement = "fuzzyMatching"
773
774         case "wantCompletionDocumentation":
775                 result.State = OptionDeprecated
776                 result.Replacement = "completionDocumentation"
777
778         case "wantUnimportedCompletions":
779                 result.State = OptionDeprecated
780                 result.Replacement = "completeUnimported"
781
782         case "fuzzyMatching":
783                 result.State = OptionDeprecated
784                 result.Replacement = "matcher"
785
786         case "caseSensitiveCompletion":
787                 result.State = OptionDeprecated
788                 result.Replacement = "matcher"
789
790         // Deprecated settings.
791         case "wantSuggestedFixes":
792                 result.State = OptionDeprecated
793
794         case "noIncrementalSync":
795                 result.State = OptionDeprecated
796
797         case "watchFileChanges":
798                 result.State = OptionDeprecated
799
800         case "go-diff":
801                 result.State = OptionDeprecated
802
803         default:
804                 result.State = OptionUnexpected
805         }
806         return result
807 }
808
809 func (r *OptionResult) errorf(msg string, values ...interface{}) {
810         prefix := fmt.Sprintf("parsing setting %q: ", r.Name)
811         r.Error = errors.Errorf(prefix+msg, values...)
812 }
813
814 func (r *OptionResult) asBool() (bool, bool) {
815         b, ok := r.Value.(bool)
816         if !ok {
817                 r.errorf("invalid type %T, expect bool", r.Value)
818                 return false, false
819         }
820         return b, true
821 }
822
823 func (r *OptionResult) setBool(b *bool) {
824         if v, ok := r.asBool(); ok {
825                 *b = v
826         }
827 }
828
829 func (r *OptionResult) setDuration(d *time.Duration) {
830         if v, ok := r.asString(); ok {
831                 parsed, err := time.ParseDuration(v)
832                 if err != nil {
833                         r.errorf("failed to parse duration %q: %v", v, err)
834                         return
835                 }
836                 *d = parsed
837         }
838 }
839
840 func (r *OptionResult) setBoolMap(bm *map[string]bool) {
841         all, ok := r.Value.(map[string]interface{})
842         if !ok {
843                 r.errorf("invalid type %T for map[string]bool option", r.Value)
844                 return
845         }
846         m := make(map[string]bool)
847         for a, enabled := range all {
848                 if enabled, ok := enabled.(bool); ok {
849                         m[a] = enabled
850                 } else {
851                         r.errorf("invalid type %T for map key %q", enabled, a)
852                         return
853                 }
854         }
855         *bm = m
856 }
857
858 func (r *OptionResult) asString() (string, bool) {
859         b, ok := r.Value.(string)
860         if !ok {
861                 r.errorf("invalid type %T, expect string", r.Value)
862                 return "", false
863         }
864         return b, true
865 }
866
867 func (r *OptionResult) asOneOf(options ...string) (string, bool) {
868         s, ok := r.asString()
869         if !ok {
870                 return "", false
871         }
872         lower := strings.ToLower(s)
873         for _, opt := range options {
874                 if strings.ToLower(opt) == lower {
875                         return opt, true
876                 }
877         }
878         r.errorf("invalid option %q for enum", r.Value)
879         return "", false
880 }
881
882 func (r *OptionResult) setString(s *string) {
883         if v, ok := r.asString(); ok {
884                 *s = v
885         }
886 }
887
888 // EnabledAnalyzers returns all of the analyzers enabled for the given
889 // snapshot.
890 func EnabledAnalyzers(snapshot Snapshot) (analyzers []Analyzer) {
891         for _, a := range snapshot.View().Options().DefaultAnalyzers {
892                 if a.IsEnabled(snapshot.View()) {
893                         analyzers = append(analyzers, a)
894                 }
895         }
896         for _, a := range snapshot.View().Options().TypeErrorAnalyzers {
897                 if a.IsEnabled(snapshot.View()) {
898                         analyzers = append(analyzers, a)
899                 }
900         }
901         for _, a := range snapshot.View().Options().ConvenienceAnalyzers {
902                 if a.IsEnabled(snapshot.View()) {
903                         analyzers = append(analyzers, a)
904                 }
905         }
906         for _, a := range snapshot.View().Options().StaticcheckAnalyzers {
907                 if a.IsEnabled(snapshot.View()) {
908                         analyzers = append(analyzers, a)
909                 }
910         }
911         return analyzers
912 }
913
914 func typeErrorAnalyzers() map[string]Analyzer {
915         return map[string]Analyzer{
916                 fillreturns.Analyzer.Name: {
917                         Analyzer:       fillreturns.Analyzer,
918                         FixesError:     fillreturns.FixesError,
919                         HighConfidence: true,
920                         Enabled:        true,
921                 },
922                 nonewvars.Analyzer.Name: {
923                         Analyzer:   nonewvars.Analyzer,
924                         FixesError: nonewvars.FixesError,
925                         Enabled:    true,
926                 },
927                 noresultvalues.Analyzer.Name: {
928                         Analyzer:   noresultvalues.Analyzer,
929                         FixesError: noresultvalues.FixesError,
930                         Enabled:    true,
931                 },
932                 undeclaredname.Analyzer.Name: {
933                         Analyzer:   undeclaredname.Analyzer,
934                         FixesError: undeclaredname.FixesError,
935                         Command:    CommandUndeclaredName,
936                         Enabled:    true,
937                 },
938         }
939 }
940
941 func convenienceAnalyzers() map[string]Analyzer {
942         return map[string]Analyzer{
943                 fillstruct.Analyzer.Name: {
944                         Analyzer: fillstruct.Analyzer,
945                         Command:  CommandFillStruct,
946                         Enabled:  true,
947                 },
948         }
949 }
950
951 func defaultAnalyzers() map[string]Analyzer {
952         return map[string]Analyzer{
953                 // The traditional vet suite:
954                 asmdecl.Analyzer.Name:      {Analyzer: asmdecl.Analyzer, Enabled: true},
955                 assign.Analyzer.Name:       {Analyzer: assign.Analyzer, Enabled: true},
956                 atomic.Analyzer.Name:       {Analyzer: atomic.Analyzer, Enabled: true},
957                 atomicalign.Analyzer.Name:  {Analyzer: atomicalign.Analyzer, Enabled: true},
958                 bools.Analyzer.Name:        {Analyzer: bools.Analyzer, Enabled: true},
959                 buildtag.Analyzer.Name:     {Analyzer: buildtag.Analyzer, Enabled: true},
960                 cgocall.Analyzer.Name:      {Analyzer: cgocall.Analyzer, Enabled: true},
961                 composite.Analyzer.Name:    {Analyzer: composite.Analyzer, Enabled: true},
962                 copylock.Analyzer.Name:     {Analyzer: copylock.Analyzer, Enabled: true},
963                 errorsas.Analyzer.Name:     {Analyzer: errorsas.Analyzer, Enabled: true},
964                 httpresponse.Analyzer.Name: {Analyzer: httpresponse.Analyzer, Enabled: true},
965                 loopclosure.Analyzer.Name:  {Analyzer: loopclosure.Analyzer, Enabled: true},
966                 lostcancel.Analyzer.Name:   {Analyzer: lostcancel.Analyzer, Enabled: true},
967                 nilfunc.Analyzer.Name:      {Analyzer: nilfunc.Analyzer, Enabled: true},
968                 printf.Analyzer.Name:       {Analyzer: printf.Analyzer, Enabled: true},
969                 shift.Analyzer.Name:        {Analyzer: shift.Analyzer, Enabled: true},
970                 stdmethods.Analyzer.Name:   {Analyzer: stdmethods.Analyzer, Enabled: true},
971                 structtag.Analyzer.Name:    {Analyzer: structtag.Analyzer, Enabled: true},
972                 tests.Analyzer.Name:        {Analyzer: tests.Analyzer, Enabled: true},
973                 unmarshal.Analyzer.Name:    {Analyzer: unmarshal.Analyzer, Enabled: true},
974                 unreachable.Analyzer.Name:  {Analyzer: unreachable.Analyzer, Enabled: true},
975                 unsafeptr.Analyzer.Name:    {Analyzer: unsafeptr.Analyzer, Enabled: true},
976                 unusedresult.Analyzer.Name: {Analyzer: unusedresult.Analyzer, Enabled: true},
977
978                 // Non-vet analyzers:
979                 deepequalerrors.Analyzer.Name:  {Analyzer: deepequalerrors.Analyzer, Enabled: true},
980                 sortslice.Analyzer.Name:        {Analyzer: sortslice.Analyzer, Enabled: true},
981                 testinggoroutine.Analyzer.Name: {Analyzer: testinggoroutine.Analyzer, Enabled: true},
982                 unusedparams.Analyzer.Name:     {Analyzer: unusedparams.Analyzer, Enabled: false},
983
984                 // gofmt -s suite:
985                 simplifycompositelit.Analyzer.Name: {Analyzer: simplifycompositelit.Analyzer, Enabled: true, HighConfidence: true},
986                 simplifyrange.Analyzer.Name:        {Analyzer: simplifyrange.Analyzer, Enabled: true, HighConfidence: true},
987                 simplifyslice.Analyzer.Name:        {Analyzer: simplifyslice.Analyzer, Enabled: true, HighConfidence: true},
988         }
989 }
990
991 func urlRegexp() *regexp.Regexp {
992         // Ensure links are matched as full words, not anywhere.
993         re := regexp.MustCompile(`\b(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?\b`)
994         re.Longest()
995         return re
996 }
997
998 type APIJSON struct {
999         Options  map[string][]*OptionJSON
1000         Commands []*CommandJSON
1001         Lenses   []*LensJSON
1002 }
1003
1004 type OptionJSON struct {
1005         Name       string
1006         Type       string
1007         Doc        string
1008         EnumValues []EnumValue
1009         Default    string
1010 }
1011
1012 type EnumValue struct {
1013         Value string
1014         Doc   string
1015 }
1016
1017 type CommandJSON struct {
1018         Command string
1019         Title   string
1020         Doc     string
1021 }
1022
1023 type LensJSON struct {
1024         Lens  string
1025         Title string
1026         Doc   string
1027 }