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.
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"
67 defaultOptions *Options
70 // DefaultOptions is the options that are used for Gopls execution independent
71 // of any externally provided configuration (LSP initialization, command
73 func DefaultOptions() *Options {
74 optionsOnce.Do(func() {
76 for _, c := range command.Commands {
77 commands = append(commands, c.ID())
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,
89 ServerOptions: ServerOptions{
90 SupportedCodeActions: map[FileKind]map[protocol.CodeActionKind]bool{
92 protocol.SourceFixAll: true,
93 protocol.SourceOrganizeImports: true,
94 protocol.QuickFix: true,
95 protocol.RefactorRewrite: true,
96 protocol.RefactorExtract: true,
99 protocol.SourceOrganizeImports: true,
100 protocol.QuickFix: true,
104 SupportedCommands: commands,
106 UserOptions: UserOptions{
107 BuildOptions: BuildOptions{
108 ExpandWorkspaceToModule: true,
109 ExperimentalPackageCacheKey: true,
111 UIOptions: UIOptions{
112 DiagnosticOptions: DiagnosticOptions{
113 ExperimentalDiagnosticsDelay: 250 * time.Millisecond,
114 Annotations: map[Annotation]bool{
121 DocumentationOptions: DocumentationOptions{
122 HoverKind: FullDocumentation,
123 LinkTarget: "pkg.go.dev",
126 NavigationOptions: NavigationOptions{
127 ImportShortcut: Both,
128 SymbolMatcher: SymbolFuzzy,
129 SymbolStyle: DynamicSymbols,
131 CompletionOptions: CompletionOptions{
133 CompletionBudget: 100 * time.Millisecond,
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,
145 InternalOptions: InternalOptions{
146 LiteralCompletions: true,
148 CompleteUnimported: true,
149 CompletionDocumentation: true,
150 DeepCompletion: true,
153 ComputeEdits: myers.ComputeEdits,
154 URLRegexp: urlRegexp(),
155 DefaultAnalyzers: defaultAnalyzers(),
156 TypeErrorAnalyzers: typeErrorAnalyzers(),
157 ConvenienceAnalyzers: convenienceAnalyzers(),
158 StaticcheckAnalyzers: map[string]*Analyzer{},
163 return defaultOptions
166 // Options holds various configuration that affects Gopls execution, organized
167 // by the nature or origin of the settings.
168 type Options struct {
176 // ClientOptions holds LSP-specific configuration that is provided by the
178 type ClientOptions struct {
179 InsertTextFormat protocol.InsertTextFormat
180 ConfigurationSupported bool
181 DynamicConfigurationSupported bool
182 DynamicWatchedFilesSupported bool
183 PreferredContentFormat protocol.MarkupKind
185 HierarchicalDocumentSymbolSupport bool
186 SemanticTypes []string
187 SemanticMods []string
188 RelatedInformationSupported bool
191 // ServerOptions holds LSP-specific configuration that is provided by the
193 type ServerOptions struct {
194 SupportedCodeActions map[FileKind]map[protocol.CodeActionKind]bool
195 SupportedCommands []string
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`.
204 // Env adds environment variables to external commands run by `gopls`, most notably `go list`.
205 Env map[string]string
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.
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
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"`
228 // ExperimentalWorkspaceModule opts a user into the experimental support
229 // for multi-module workspaces.
230 ExperimentalWorkspaceModule bool `status:"experimental"`
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"`
241 // AllowModfileModifications disables -mod=readonly, allowing imports from
242 // out-of-scope modules. This option will eventually be removed.
243 AllowModfileModifications bool `status:"experimental"`
245 // AllowImplicitNetworkAccess disables GOPROXY=off, allowing implicit module
246 // downloads rather than requiring user action. This option will eventually
248 AllowImplicitNetworkAccess bool `status:"experimental"`
251 type UIOptions struct {
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.
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.
274 Codelenses map[string]bool
276 // SemanticTokens controls whether the LSP server will send
277 // semantic tokens to the client.
278 SemanticTokens bool `status:"experimental"`
281 type CompletionOptions struct {
282 // Placeholders enables placeholders for function parameters or struct
283 // fields in completion responses.
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"`
293 // Matcher sets the algorithm that is used when calculating completion
295 Matcher Matcher `status:"advanced"`
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.
303 // LinkTarget controls where documentation links go.
304 // It might be one of:
309 // If company chooses to use its own `godoc.org`, its address can be used as well.
312 // LinksInHover toggles the presence of links to documentation in hover.
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
323 // Gofumpt indicates if we should run gofumpt formatting.
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).
338 // "unreachable": false, // Disable the unreachable analyzer.
339 // "unusedparams": true // Enable the unusedparams analyzer.
343 Analyses map[string]bool
345 // Staticcheck enables additional analyses from staticcheck.io.
346 Staticcheck bool `status:"experimental"`
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"`
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.
357 // This option must be set to a valid duration string, for example `"250ms"`.
358 ExperimentalDiagnosticsDelay time.Duration `status:"experimental"`
361 type NavigationOptions struct {
362 // ImportShortcut specifies whether import statements should link to
363 // documentation or go to definitions.
364 ImportShortcut ImportShortcut
366 // SymbolMatcher sets the algorithm that is used when finding workspace symbols.
367 SymbolMatcher SymbolMatcher `status:"advanced"`
369 // SymbolStyle controls how symbols are qualified in symbol responses.
376 // "symbolStyle": "dynamic",
380 SymbolStyle SymbolStyle `status:"advanced"`
383 // UserOptions holds custom Gopls configuration (not part of the LSP) that is
384 // modified by the client.
385 type UserOptions struct {
390 // VerboseOutput enables additional debug logging.
391 VerboseOutput bool `status:"debug"`
394 // EnvSlice returns Env as a slice of k=v strings.
395 func (u *UserOptions) EnvSlice() []string {
397 for k, v := range u.Env {
398 result = append(result, fmt.Sprintf("%v=%v", k, v))
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)
411 u.Env[split[0]] = split[1]
415 // Hooks contains configuration that is provided to the Gopls command by the
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
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
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
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
444 // The following options were previously available to users, but they
445 // really shouldn't be configured by anyone other than "power users".
447 // CompletionDocumentation enables documentation with completion results.
448 CompletionDocumentation bool
450 // CompleteUnimported enables completion for packages that you do not
452 CompleteUnimported bool
454 // DeepCompletion enables the ability to return completions from deep
455 // inside relevant entities, rather than just the locally accessible ones.
457 // Consider this example:
464 // type wrapString struct {
469 // x := wrapString{"hello world"}
474 // At the location of the `<>` in this program, deep completion would suggest the result `x.str`.
477 // TempModfile controls the use of the -modfile flag in Go 1.14.
481 type ImportShortcut string
484 Both ImportShortcut = "Both"
485 Link ImportShortcut = "Link"
486 Definition ImportShortcut = "Definition"
489 func (s ImportShortcut) ShowLinks() bool {
490 return s == Both || s == Link
493 func (s ImportShortcut) ShowDefinition() bool {
494 return s == Both || s == Definition
500 Fuzzy Matcher = "Fuzzy"
501 CaseInsensitive Matcher = "CaseInsensitive"
502 CaseSensitive Matcher = "CaseSensitive"
505 type SymbolMatcher string
508 SymbolFuzzy SymbolMatcher = "Fuzzy"
509 SymbolCaseInsensitive SymbolMatcher = "CaseInsensitive"
510 SymbolCaseSensitive SymbolMatcher = "CaseSensitive"
513 type SymbolStyle string
516 // PackageQualifiedSymbols is package qualified symbols i.e.
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
526 DynamicSymbols SymbolStyle = "Dynamic"
529 type HoverKind string
532 SingleLine HoverKind = "SingleLine"
533 NoDocumentation HoverKind = "NoDocumentation"
534 SynopsisDocumentation HoverKind = "SynopsisDocumentation"
535 FullDocumentation HoverKind = "FullDocumentation"
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.
541 // This should only be used by clients that support this behavior.
542 Structured HoverKind = "Structured"
545 type OptionResults []OptionResult
547 type OptionResult struct {
559 OptionHandled = OptionState(iota)
564 type LinkTarget string
566 func SetOptions(options *Options, opts interface{}) OptionResults {
567 var results OptionResults
568 switch opts := opts.(type) {
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()
580 seen := map[string]struct{}{}
581 for name, value := range opts {
582 results = append(results, options.set(name, value, seen))
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()
590 results = append(results, OptionResult{
592 Error: errors.Errorf("Invalid options type %T", opts),
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
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
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]
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
623 // Check if the client supports diagnostic related information.
624 o.RelatedInformationSupported = caps.TextDocument.PublishDiagnostics.RelatedInformation
627 func (o *Options) Clone() *Options {
629 ClientOptions: o.ClientOptions,
630 InternalOptions: o.InternalOptions,
632 GoDiff: o.Hooks.GoDiff,
633 ComputeEdits: o.Hooks.ComputeEdits,
634 GofumptFormat: o.GofumptFormat,
635 URLRegexp: o.URLRegexp,
637 ServerOptions: o.ServerOptions,
638 UserOptions: o.UserOptions,
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 {
649 result.Analyses = copyStringMap(o.Analyses)
650 result.Codelenses = copyStringMap(o.Codelenses)
652 copySlice := func(src []string) []string {
653 dst := make([]string, len(src))
657 result.SetEnvSlice(o.EnvSlice())
658 result.BuildFlags = copySlice(o.BuildFlags)
659 result.DirectoryFilters = copySlice(o.DirectoryFilters)
661 copyAnalyzerMap := func(src map[string]*Analyzer) map[string]*Analyzer {
662 dst := make(map[string]*Analyzer)
663 for k, v := range src {
668 result.DefaultAnalyzers = copyAnalyzerMap(o.DefaultAnalyzers)
669 result.TypeErrorAnalyzers = copyAnalyzerMap(o.TypeErrorAnalyzers)
670 result.ConvenienceAnalyzers = copyAnalyzerMap(o.ConvenienceAnalyzers)
671 result.StaticcheckAnalyzers = copyAnalyzerMap(o.StaticcheckAnalyzers)
675 func (o *Options) AddStaticcheckAnalyzer(a *analysis.Analyzer) {
676 o.StaticcheckAnalyzers[a.Name] = &Analyzer{Analyzer: a, Enabled: true}
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
686 func (o *Options) enableAllExperimentMaps() {
687 if _, ok := o.Codelenses[string(command.GCDetails)]; !ok {
688 o.Codelenses[string(command.GCDetails)] = true
690 if _, ok := o.Analyses[unusedparams.Analyzer.Name]; !ok {
691 o.Analyses[unusedparams.Analyzer.Name] = true
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]
700 result := OptionResult{Name: name, Value: value}
701 if _, ok := seen[name]; ok {
702 result.errorf("duplicate configuration for %s", name)
704 seen[name] = struct{}{}
708 menv, ok := value.(map[string]interface{})
710 result.errorf("invalid type %T, expect map", value)
714 o.Env = make(map[string]string)
716 for k, v := range menv {
717 o.Env[k] = fmt.Sprint(v)
721 iflags, ok := value.([]interface{})
723 result.errorf("invalid type %T, expect list", value)
726 flags := make([]string, 0, len(iflags))
727 for _, flag := range iflags {
728 flags = append(flags, fmt.Sprintf("%s", flag))
731 case "directoryFilters":
732 ifilters, ok := value.([]interface{})
734 result.errorf("invalid type %T, expect list", value)
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)
744 filters = append(filters, filepath.FromSlash(filter))
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)
758 if s, ok := result.asOneOf(
760 string(CaseSensitive),
761 string(CaseInsensitive),
763 o.Matcher = Matcher(s)
766 case "symbolMatcher":
767 if s, ok := result.asOneOf(
769 string(SymbolCaseInsensitive),
770 string(SymbolCaseSensitive),
772 o.SymbolMatcher = SymbolMatcher(s)
776 if s, ok := result.asOneOf(
777 string(FullyQualifiedSymbols),
778 string(PackageQualifiedSymbols),
779 string(DynamicSymbols),
781 o.SymbolStyle = SymbolStyle(s)
785 if s, ok := result.asOneOf(
786 string(NoDocumentation),
788 string(SynopsisDocumentation),
789 string(FullDocumentation),
792 o.HoverKind = HoverKind(s)
796 result.setString(&o.LinkTarget)
799 result.setBool(&o.LinksInHover)
801 case "importShortcut":
802 if s, ok := result.asOneOf(string(Both), string(Link), string(Definition)); ok {
803 o.ImportShortcut = ImportShortcut(s)
807 result.setBoolMap(&o.Analyses)
810 result.setAnnotationMap(&o.Annotations)
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)
819 for lens, enabled := range lensOverrides {
820 o.Codelenses[lens] = enabled
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"
832 result.setBool(&o.Staticcheck)
835 result.setString(&o.Local)
837 case "verboseOutput":
838 result.setBool(&o.VerboseOutput)
840 case "verboseWorkDoneProgress":
841 result.setBool(&o.VerboseWorkDoneProgress)
844 result.setBool(&o.TempModfile)
847 result.setBool(&o.Gofumpt)
849 case "semanticTokens":
850 result.setBool(&o.SemanticTokens)
852 case "expandWorkspaceToModule":
853 result.setBool(&o.ExpandWorkspaceToModule)
855 case "experimentalWorkspaceModule":
856 result.setBool(&o.ExperimentalWorkspaceModule)
858 case "experimentalDiagnosticsDelay":
859 result.setDuration(&o.ExperimentalDiagnosticsDelay)
861 case "experimentalPackageCacheKey":
862 result.setBool(&o.ExperimentalPackageCacheKey)
864 case "allowModfileModifications":
865 result.setBool(&o.AllowModfileModifications)
867 case "allowImplicitNetworkAccess":
868 result.setBool(&o.AllowImplicitNetworkAccess)
870 case "allExperiments":
871 // This setting should be handled before all of the other options are
872 // processed, so do nothing here.
874 // Replaced settings.
875 case "experimentalDisabledAnalyses":
876 result.State = OptionDeprecated
877 result.Replacement = "analyses"
879 case "disableDeepCompletion":
880 result.State = OptionDeprecated
881 result.Replacement = "deepCompletion"
883 case "disableFuzzyMatching":
884 result.State = OptionDeprecated
885 result.Replacement = "fuzzyMatching"
887 case "wantCompletionDocumentation":
888 result.State = OptionDeprecated
889 result.Replacement = "completionDocumentation"
891 case "wantUnimportedCompletions":
892 result.State = OptionDeprecated
893 result.Replacement = "completeUnimported"
895 case "fuzzyMatching":
896 result.State = OptionDeprecated
897 result.Replacement = "matcher"
899 case "caseSensitiveCompletion":
900 result.State = OptionDeprecated
901 result.Replacement = "matcher"
903 // Deprecated settings.
904 case "wantSuggestedFixes":
905 result.State = OptionDeprecated
907 case "noIncrementalSync":
908 result.State = OptionDeprecated
910 case "watchFileChanges":
911 result.State = OptionDeprecated
914 result.State = OptionDeprecated
917 result.State = OptionUnexpected
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...)
927 func (r *OptionResult) asBool() (bool, bool) {
928 b, ok := r.Value.(bool)
930 r.errorf("invalid type %T, expect bool", r.Value)
936 func (r *OptionResult) setBool(b *bool) {
937 if v, ok := r.asBool(); ok {
942 func (r *OptionResult) setDuration(d *time.Duration) {
943 if v, ok := r.asString(); ok {
944 parsed, err := time.ParseDuration(v)
946 r.errorf("failed to parse duration %q: %v", v, err)
953 func (r *OptionResult) setBoolMap(bm *map[string]bool) {
958 func (r *OptionResult) setAnnotationMap(bm *map[Annotation]bool) {
963 // Default to everything enabled by default.
964 m := make(map[Annotation]bool)
965 for k, enabled := range all {
974 // In case of an error, process any legacy values.
978 r.errorf(`"noEscape" is deprecated, set "Escape: false" instead`)
981 r.errorf(`"noNilcheck" is deprecated, set "Nil: false" instead`)
984 r.errorf(`"noInline" is deprecated, set "Inline: false" instead`)
987 r.errorf(`"noBounds" is deprecated, set "Bounds: false" instead`)
989 r.errorf(err.Error())
993 m[Annotation(a)] = enabled
998 func (r *OptionResult) asBoolMap() map[string]bool {
999 all, ok := r.Value.(map[string]interface{})
1001 r.errorf("invalid type %T for map[string]bool option", r.Value)
1004 m := make(map[string]bool)
1005 for a, enabled := range all {
1006 if enabled, ok := enabled.(bool); ok {
1009 r.errorf("invalid type %T for map key %q", enabled, a)
1016 func (r *OptionResult) asString() (string, bool) {
1017 b, ok := r.Value.(string)
1019 r.errorf("invalid type %T, expect string", r.Value)
1025 func (r *OptionResult) asOneOf(options ...string) (string, bool) {
1026 s, ok := r.asString()
1030 s, err := asOneOf(s, options...)
1032 r.errorf(err.Error())
1034 return s, err == nil
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 {
1044 return "", fmt.Errorf("invalid option %q for enum", str)
1047 func (r *OptionResult) setString(s *string) {
1048 if v, ok := r.asString(); ok {
1053 // EnabledAnalyzers returns all of the analyzers enabled for the given
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)
1061 for _, a := range snapshot.View().Options().TypeErrorAnalyzers {
1062 if a.IsEnabled(snapshot.View()) {
1063 analyzers = append(analyzers, a)
1066 for _, a := range snapshot.View().Options().ConvenienceAnalyzers {
1067 if a.IsEnabled(snapshot.View()) {
1068 analyzers = append(analyzers, a)
1071 for _, a := range snapshot.View().Options().StaticcheckAnalyzers {
1072 if a.IsEnabled(snapshot.View()) {
1073 analyzers = append(analyzers, a)
1079 func typeErrorAnalyzers() map[string]*Analyzer {
1080 return map[string]*Analyzer{
1081 fillreturns.Analyzer.Name: {
1082 Analyzer: fillreturns.Analyzer,
1083 ActionKind: protocol.SourceFixAll,
1086 nonewvars.Analyzer.Name: {
1087 Analyzer: nonewvars.Analyzer,
1090 noresultvalues.Analyzer.Name: {
1091 Analyzer: noresultvalues.Analyzer,
1094 undeclaredname.Analyzer.Name: {
1095 Analyzer: undeclaredname.Analyzer,
1096 Fix: UndeclaredName,
1102 func convenienceAnalyzers() map[string]*Analyzer {
1103 return map[string]*Analyzer{
1104 fillstruct.Analyzer.Name: {
1105 Analyzer: fillstruct.Analyzer,
1108 ActionKind: protocol.RefactorRewrite,
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},
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},
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},
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`)
1166 type APIJSON struct {
1167 Options map[string][]*OptionJSON
1168 Commands []*CommandJSON
1170 Analyzers []*AnalyzerJSON
1173 type OptionJSON struct {
1178 EnumValues []EnumValue
1184 type EnumKeys struct {
1189 type EnumKey struct {
1195 type EnumValue struct {
1200 type CommandJSON struct {
1207 type LensJSON struct {
1213 type AnalyzerJSON struct {