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