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