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.
15 "golang.org/x/tools/go/analysis"
16 "golang.org/x/tools/go/analysis/passes/asmdecl"
17 "golang.org/x/tools/go/analysis/passes/assign"
18 "golang.org/x/tools/go/analysis/passes/atomic"
19 "golang.org/x/tools/go/analysis/passes/atomicalign"
20 "golang.org/x/tools/go/analysis/passes/bools"
21 "golang.org/x/tools/go/analysis/passes/buildtag"
22 "golang.org/x/tools/go/analysis/passes/cgocall"
23 "golang.org/x/tools/go/analysis/passes/composite"
24 "golang.org/x/tools/go/analysis/passes/copylock"
25 "golang.org/x/tools/go/analysis/passes/deepequalerrors"
26 "golang.org/x/tools/go/analysis/passes/errorsas"
27 "golang.org/x/tools/go/analysis/passes/httpresponse"
28 "golang.org/x/tools/go/analysis/passes/loopclosure"
29 "golang.org/x/tools/go/analysis/passes/lostcancel"
30 "golang.org/x/tools/go/analysis/passes/nilfunc"
31 "golang.org/x/tools/go/analysis/passes/printf"
32 "golang.org/x/tools/go/analysis/passes/shift"
33 "golang.org/x/tools/go/analysis/passes/sortslice"
34 "golang.org/x/tools/go/analysis/passes/stdmethods"
35 "golang.org/x/tools/go/analysis/passes/structtag"
36 "golang.org/x/tools/go/analysis/passes/testinggoroutine"
37 "golang.org/x/tools/go/analysis/passes/tests"
38 "golang.org/x/tools/go/analysis/passes/unmarshal"
39 "golang.org/x/tools/go/analysis/passes/unreachable"
40 "golang.org/x/tools/go/analysis/passes/unsafeptr"
41 "golang.org/x/tools/go/analysis/passes/unusedresult"
42 "golang.org/x/tools/internal/lsp/analysis/fillreturns"
43 "golang.org/x/tools/internal/lsp/analysis/fillstruct"
44 "golang.org/x/tools/internal/lsp/analysis/nonewvars"
45 "golang.org/x/tools/internal/lsp/analysis/noresultvalues"
46 "golang.org/x/tools/internal/lsp/analysis/simplifycompositelit"
47 "golang.org/x/tools/internal/lsp/analysis/simplifyrange"
48 "golang.org/x/tools/internal/lsp/analysis/simplifyslice"
49 "golang.org/x/tools/internal/lsp/analysis/undeclaredname"
50 "golang.org/x/tools/internal/lsp/analysis/unusedparams"
51 "golang.org/x/tools/internal/lsp/diff"
52 "golang.org/x/tools/internal/lsp/diff/myers"
53 "golang.org/x/tools/internal/lsp/protocol"
54 errors "golang.org/x/xerrors"
59 defaultOptions *Options
62 //go:generate go run golang.org/x/tools/internal/lsp/source/genapijson -output api_json.go
64 // DefaultOptions is the options that are used for Gopls execution independent
65 // of any externally provided configuration (LSP initialization, command
67 func DefaultOptions() *Options {
68 optionsOnce.Do(func() {
70 for _, c := range Commands {
71 commands = append(commands, c.ID())
73 defaultOptions = &Options{
74 ClientOptions: ClientOptions{
75 InsertTextFormat: protocol.PlainTextTextFormat,
76 PreferredContentFormat: protocol.Markdown,
77 ConfigurationSupported: true,
78 DynamicConfigurationSupported: true,
79 DynamicWatchedFilesSupported: true,
80 LineFoldingOnly: false,
81 HierarchicalDocumentSymbolSupport: true,
83 ServerOptions: ServerOptions{
84 SupportedCodeActions: map[FileKind]map[protocol.CodeActionKind]bool{
86 protocol.SourceFixAll: true,
87 protocol.SourceOrganizeImports: true,
88 protocol.QuickFix: true,
89 protocol.RefactorRewrite: true,
90 protocol.RefactorExtract: true,
93 protocol.SourceOrganizeImports: true,
97 SupportedCommands: commands,
99 UserOptions: UserOptions{
100 HoverKind: FullDocumentation,
101 LinkTarget: "pkg.go.dev",
103 DebuggingOptions: DebuggingOptions{
104 CompletionBudget: 100 * time.Millisecond,
106 ExperimentalOptions: ExperimentalOptions{
108 ExpandWorkspaceToModule: true,
109 Codelens: map[string]bool{
110 CommandGenerate.Name: true,
111 CommandRegenerateCgo.Name: true,
112 CommandTidy.Name: true,
113 CommandToggleDetails.Name: false,
114 CommandUpgradeDependency.Name: true,
115 CommandVendor.Name: true,
118 CompleteUnimported: true,
119 CompletionDocumentation: true,
120 DeepCompletion: true,
121 ImportShortcut: Both,
123 SymbolMatcher: SymbolFuzzy,
124 SymbolStyle: PackageQualifiedSymbols,
126 InternalOptions: InternalOptions{
127 LiteralCompletions: true,
130 ComputeEdits: myers.ComputeEdits,
131 URLRegexp: urlRegexp(),
132 DefaultAnalyzers: defaultAnalyzers(),
133 TypeErrorAnalyzers: typeErrorAnalyzers(),
134 ConvenienceAnalyzers: convenienceAnalyzers(),
135 StaticcheckAnalyzers: map[string]Analyzer{},
140 return defaultOptions
143 // Options holds various configuration that affects Gopls execution, organized
144 // by the nature or origin of the settings.
145 type Options struct {
155 // ClientOptions holds LSP-specific configuration that is provided by the
157 type ClientOptions struct {
158 InsertTextFormat protocol.InsertTextFormat
159 ConfigurationSupported bool
160 DynamicConfigurationSupported bool
161 DynamicWatchedFilesSupported bool
162 PreferredContentFormat protocol.MarkupKind
164 HierarchicalDocumentSymbolSupport bool
167 // ServerOptions holds LSP-specific configuration that is provided by the
169 type ServerOptions struct {
170 SupportedCodeActions map[FileKind]map[protocol.CodeActionKind]bool
171 SupportedCommands []string
174 // UserOptions holds custom Gopls configuration (not part of the LSP) that is
175 // modified by the client.
176 type UserOptions struct {
177 // BuildFlags is the set of flags passed on to the build system when invoked.
178 // It is applied to queries like `go list`, which is used when discovering files.
179 // The most common use is to set `-tags`.
182 // Env adds environment variables to external commands run by `gopls`, most notably `go list`.
183 Env map[string]string
185 // HoverKind controls the information that appears in the hover text.
186 // SingleLine and Structured are intended for use only by authors of editor plugins.
189 // Placeholders enables placeholders for function parameters or struct fields in completion responses.
192 // LinkTarget controls where documentation links go.
193 // It might be one of:
198 // If company chooses to use its own `godoc.org`, its address can be used as well.
201 // Local is the equivalent of the `goimports -local` flag, which puts imports beginning with this string after 3rd-party packages.
202 // It should be the prefix of the import path whose imports should be grouped separately.
205 // Gofumpt indicates if we should run gofumpt formatting.
209 // EnvSlice returns Env as a slice of k=v strings.
210 func (u *UserOptions) EnvSlice() []string {
212 for k, v := range u.Env {
213 result = append(result, fmt.Sprintf("%v=%v", k, v))
218 // SetEnvSlice sets Env from a slice of k=v strings.
219 func (u *UserOptions) SetEnvSlice(env []string) {
220 u.Env = map[string]string{}
221 for _, kv := range env {
222 split := strings.SplitN(kv, "=", 2)
226 u.Env[split[0]] = split[1]
230 // Hooks contains configuration that is provided to the Gopls command by the
234 ComputeEdits diff.ComputeEdits
235 URLRegexp *regexp.Regexp
236 GofumptFormat func(ctx context.Context, src []byte) ([]byte, error)
237 DefaultAnalyzers map[string]Analyzer
238 TypeErrorAnalyzers map[string]Analyzer
239 ConvenienceAnalyzers map[string]Analyzer
240 StaticcheckAnalyzers map[string]Analyzer
243 // ExperimentalOptions defines configuration for features under active
244 // development. WARNING: This configuration will be changed in the future. It
245 // only exists while these features are under development.
246 type ExperimentalOptions struct {
247 // Analyses specify analyses that the user would like to enable or disable.
248 // A map of the names of analysis passes that should be enabled/disabled.
249 // A full list of analyzers that gopls uses can be found [here](analyzers.md)
255 // "unreachable": false, // Disable the unreachable analyzer.
256 // "unusedparams": true // Enable the unusedparams analyzer.
260 Analyses map[string]bool
262 // Codelens overrides the enabled/disabled state of code lenses. See the "Code Lenses"
263 // section of settings.md for the list of supported lenses.
270 // "generate": false, // Don't show the `go generate` lens.
271 // "gc_details": true // Show a code lens toggling the display of gc's choices.
276 Codelens map[string]bool
278 // CompletionDocumentation enables documentation with completion results.
279 CompletionDocumentation bool
281 // CompleteUnimported enables completion for packages that you do not currently import.
282 CompleteUnimported bool
284 // DeepCompletion enables the ability to return completions from deep inside relevant entities, rather than just the locally accessible ones.
286 // Consider this example:
293 // type wrapString struct {
298 // x := wrapString{"hello world"}
303 // At the location of the `<>` in this program, deep completion would suggest the result `x.str`.
306 // Matcher sets the algorithm that is used when calculating completion candidates.
309 // Annotations suppress various kinds of optimization diagnostics
310 // that would be reported by the gc_details command.
311 // * noNilcheck suppresses display of nilchecks.
312 // * noEscape suppresses escape choices.
313 // * noInline suppresses inlining choices.
314 // * noBounds suppresses bounds checking diagnostics.
315 Annotations map[string]bool
317 // Staticcheck enables additional analyses from staticcheck.io.
320 // SymbolMatcher sets the algorithm that is used when finding workspace symbols.
321 SymbolMatcher SymbolMatcher
323 // SymbolStyle controls how symbols are qualified in symbol responses.
329 // "symbolStyle": "dynamic",
333 SymbolStyle SymbolStyle
335 // LinksInHover toggles the presence of links to documentation in hover.
338 // TempModfile controls the use of the -modfile flag in Go 1.14.
341 // ImportShortcut specifies whether import statements should link to
342 // documentation or go to definitions.
343 ImportShortcut ImportShortcut
345 // VerboseWorkDoneProgress controls whether the LSP server should send
346 // progress reports for all work done outside the scope of an RPC.
347 VerboseWorkDoneProgress bool
349 // SemanticTokens controls whether the LSP server will send
350 // semantic tokens to the client.
353 // ExpandWorkspaceToModule instructs `gopls` to expand the scope of the workspace to include the
354 // modules containing the workspace folders. Set this to false to avoid loading
355 // your entire module. This is particularly useful for those working in a monorepo.
356 ExpandWorkspaceToModule bool
358 // ExperimentalWorkspaceModule opts a user into the experimental support
359 // for multi-module workspaces.
360 ExperimentalWorkspaceModule bool
362 // ExperimentalDiagnosticsDelay controls the amount of time that gopls waits
363 // after the most recent file modification before computing deep diagnostics.
364 // Simple diagnostics (parsing and type-checking) are always run immediately
365 // on recently modified packages.
367 // This option must be set to a valid duration string, for example `"250ms"`.
368 ExperimentalDiagnosticsDelay time.Duration
370 // ExperimentalPackageCacheKey controls whether to use a coarser cache key
371 // for package type information to increase cache hits. This setting removes
372 // the user's environment, build flags, and working directory from the cache
373 // key, which should be a safe change as all relevant inputs into the type
374 // checking pass are already hashed into the key. This is temporarily guarded
375 // by an experiment because caching behavior is subtle and difficult to
376 // comprehensively test.
377 ExperimentalPackageCacheKey bool
380 // DebuggingOptions should not affect the logical execution of Gopls, but may
381 // be altered for debugging purposes.
382 type DebuggingOptions struct {
383 // VerboseOutput enables additional debug logging.
386 // CompletionBudget is the soft latency goal for completion requests. Most
387 // requests finish in a couple milliseconds, but in some cases deep
388 // completions can take much longer. As we use up our budget we
389 // dynamically reduce the search scope to ensure we return timely
390 // results. Zero means unlimited.
391 CompletionBudget time.Duration
394 // InternalOptions contains settings that are not exposed to the user for various
395 // reasons, e.g. settings used by tests.
396 type InternalOptions struct {
397 // LiteralCompletions controls whether literal candidates such as
398 // "&someStruct{}" are offered. Tests disable this flag to simplify
399 // their expected values.
400 LiteralCompletions bool
403 type ImportShortcut string
406 Both ImportShortcut = "Both"
407 Link ImportShortcut = "Link"
408 Definition ImportShortcut = "Definition"
411 func (s ImportShortcut) ShowLinks() bool {
412 return s == Both || s == Link
415 func (s ImportShortcut) ShowDefinition() bool {
416 return s == Both || s == Definition
422 Fuzzy Matcher = "Fuzzy"
423 CaseInsensitive Matcher = "CaseInsensitive"
424 CaseSensitive Matcher = "CaseSensitive"
427 type SymbolMatcher string
430 SymbolFuzzy SymbolMatcher = "Fuzzy"
431 SymbolCaseInsensitive SymbolMatcher = "CaseInsensitive"
432 SymbolCaseSensitive SymbolMatcher = "CaseSensitive"
435 type SymbolStyle string
438 // PackageQualifiedSymbols is package qualified symbols i.e.
440 PackageQualifiedSymbols SymbolStyle = "Package"
441 // FullyQualifiedSymbols is fully qualified symbols, i.e.
442 // "path/to/pkg.Foo.Field".
443 FullyQualifiedSymbols SymbolStyle = "Full"
444 // DynamicSymbols uses whichever qualifier results in the highest scoring
445 // match for the given symbol query. Here a "qualifier" is any "/" or "."
446 // delimited suffix of the fully qualified symbol. i.e. "to/pkg.Foo.Field" or
448 DynamicSymbols SymbolStyle = "Dynamic"
451 type HoverKind string
454 SingleLine HoverKind = "SingleLine"
455 NoDocumentation HoverKind = "NoDocumentation"
456 SynopsisDocumentation HoverKind = "SynopsisDocumentation"
457 FullDocumentation HoverKind = "FullDocumentation"
459 // Structured is an experimental setting that returns a structured hover format.
460 // This format separates the signature from the documentation, so that the client
461 // can do more manipulation of these fields.
463 // This should only be used by clients that support this behavior.
464 Structured HoverKind = "Structured"
467 type OptionResults []OptionResult
469 type OptionResult struct {
481 OptionHandled = OptionState(iota)
486 type LinkTarget string
488 func SetOptions(options *Options, opts interface{}) OptionResults {
489 var results OptionResults
490 switch opts := opts.(type) {
492 case map[string]interface{}:
493 // If the user's settings contains "allExperiments", set that first,
494 // and then let them override individual settings independently.
495 var enableExperiments bool
496 for name, value := range opts {
497 if b, ok := value.(bool); name == "allExperiments" && ok && b {
498 enableExperiments = true
499 options.enableAllExperiments()
502 for name, value := range opts {
503 results = append(results, options.set(name, value))
505 // Finally, enable any experimental features that are specified in
506 // maps, which allows users to individually toggle them on or off.
507 if enableExperiments {
508 options.enableAllExperimentMaps()
511 results = append(results, OptionResult{
513 Error: errors.Errorf("Invalid options type %T", opts),
519 func (o *Options) ForClientCapabilities(caps protocol.ClientCapabilities) {
520 // Check if the client supports snippets in completion items.
521 if c := caps.TextDocument.Completion; c.CompletionItem.SnippetSupport {
522 o.InsertTextFormat = protocol.SnippetTextFormat
524 // Check if the client supports configuration messages.
525 o.ConfigurationSupported = caps.Workspace.Configuration
526 o.DynamicConfigurationSupported = caps.Workspace.DidChangeConfiguration.DynamicRegistration
527 o.DynamicWatchedFilesSupported = caps.Workspace.DidChangeWatchedFiles.DynamicRegistration
529 // Check which types of content format are supported by this client.
530 if hover := caps.TextDocument.Hover; len(hover.ContentFormat) > 0 {
531 o.PreferredContentFormat = hover.ContentFormat[0]
533 // Check if the client supports only line folding.
534 fr := caps.TextDocument.FoldingRange
535 o.LineFoldingOnly = fr.LineFoldingOnly
536 // Check if the client supports hierarchical document symbols.
537 o.HierarchicalDocumentSymbolSupport = caps.TextDocument.DocumentSymbol.HierarchicalDocumentSymbolSupport
540 func (o *Options) Clone() *Options {
542 ClientOptions: o.ClientOptions,
543 DebuggingOptions: o.DebuggingOptions,
544 ExperimentalOptions: o.ExperimentalOptions,
545 InternalOptions: o.InternalOptions,
547 GoDiff: o.Hooks.GoDiff,
548 ComputeEdits: o.Hooks.ComputeEdits,
549 GofumptFormat: o.GofumptFormat,
550 URLRegexp: o.URLRegexp,
552 ServerOptions: o.ServerOptions,
553 UserOptions: o.UserOptions,
555 // Fully clone any slice or map fields. Only Hooks, ExperimentalOptions,
556 // and UserOptions can be modified.
557 copyStringMap := func(src map[string]bool) map[string]bool {
558 dst := make(map[string]bool)
559 for k, v := range src {
564 result.Analyses = copyStringMap(o.Analyses)
565 result.Annotations = copyStringMap(o.Annotations)
566 result.Codelens = copyStringMap(o.Codelens)
568 copySlice := func(src []string) []string {
569 dst := make([]string, len(src))
573 result.SetEnvSlice(o.EnvSlice())
574 result.BuildFlags = copySlice(o.BuildFlags)
576 copyAnalyzerMap := func(src map[string]Analyzer) map[string]Analyzer {
577 dst := make(map[string]Analyzer)
578 for k, v := range src {
583 result.DefaultAnalyzers = copyAnalyzerMap(o.DefaultAnalyzers)
584 result.TypeErrorAnalyzers = copyAnalyzerMap(o.TypeErrorAnalyzers)
585 result.ConvenienceAnalyzers = copyAnalyzerMap(o.ConvenienceAnalyzers)
586 result.StaticcheckAnalyzers = copyAnalyzerMap(o.StaticcheckAnalyzers)
590 func (o *Options) AddStaticcheckAnalyzer(a *analysis.Analyzer) {
591 o.StaticcheckAnalyzers[a.Name] = Analyzer{Analyzer: a, Enabled: true}
594 // enableAllExperiments turns on all of the experimental "off-by-default"
595 // features offered by gopls.
596 // Any experimental features specified in maps should be enabled in
597 // enableAllExperimentMaps.
598 func (o *Options) enableAllExperiments() {
599 o.ExperimentalDiagnosticsDelay = 200 * time.Millisecond
600 o.ExperimentalPackageCacheKey = true
601 o.SymbolStyle = DynamicSymbols
604 func (o *Options) enableAllExperimentMaps() {
605 if _, ok := o.Codelens[CommandToggleDetails.Name]; !ok {
606 o.Codelens[CommandToggleDetails.Name] = true
608 if _, ok := o.Analyses[unusedparams.Analyzer.Name]; !ok {
609 o.Analyses[unusedparams.Analyzer.Name] = true
613 func (o *Options) set(name string, value interface{}) OptionResult {
614 result := OptionResult{Name: name, Value: value}
617 menv, ok := value.(map[string]interface{})
619 result.errorf("invalid type %T, expect map", value)
622 for k, v := range menv {
623 o.Env[k] = fmt.Sprint(v)
627 iflags, ok := value.([]interface{})
629 result.errorf("invalid type %T, expect list", value)
632 flags := make([]string, 0, len(iflags))
633 for _, flag := range iflags {
634 flags = append(flags, fmt.Sprintf("%s", flag))
638 case "completionDocumentation":
639 result.setBool(&o.CompletionDocumentation)
640 case "usePlaceholders":
641 result.setBool(&o.UsePlaceholders)
642 case "deepCompletion":
643 result.setBool(&o.DeepCompletion)
644 case "completeUnimported":
645 result.setBool(&o.CompleteUnimported)
646 case "completionBudget":
647 result.setDuration(&o.CompletionBudget)
649 if s, ok := result.asOneOf(
651 string(CaseSensitive),
652 string(CaseInsensitive),
654 o.Matcher = Matcher(s)
657 case "symbolMatcher":
658 if s, ok := result.asOneOf(
660 string(SymbolCaseInsensitive),
661 string(SymbolCaseSensitive),
663 o.SymbolMatcher = SymbolMatcher(s)
667 if s, ok := result.asOneOf(
668 string(FullyQualifiedSymbols),
669 string(PackageQualifiedSymbols),
670 string(DynamicSymbols),
672 o.SymbolStyle = SymbolStyle(s)
676 if s, ok := result.asOneOf(
677 string(NoDocumentation),
679 string(SynopsisDocumentation),
680 string(FullDocumentation),
683 o.HoverKind = HoverKind(s)
687 result.setString(&o.LinkTarget)
690 result.setBool(&o.LinksInHover)
692 case "importShortcut":
693 if s, ok := result.asOneOf(string(Both), string(Link), string(Definition)); ok {
694 o.ImportShortcut = ImportShortcut(s)
698 result.setBoolMap(&o.Analyses)
701 result.setBoolMap(&o.Annotations)
702 for k := range o.Annotations {
704 case "noEscape", "noNilcheck", "noInline", "noBounds":
707 result.Name += ":" + k // put mistake(s) in the message
708 result.State = OptionUnexpected
713 var lensOverrides map[string]bool
714 result.setBoolMap(&lensOverrides)
715 if result.Error == nil {
716 if o.Codelens == nil {
717 o.Codelens = make(map[string]bool)
719 for lens, enabled := range lensOverrides {
720 o.Codelens[lens] = enabled
725 result.setBool(&o.Staticcheck)
728 result.setString(&o.Local)
730 case "verboseOutput":
731 result.setBool(&o.VerboseOutput)
733 case "verboseWorkDoneProgress":
734 result.setBool(&o.VerboseWorkDoneProgress)
737 result.setBool(&o.TempModfile)
740 result.setBool(&o.Gofumpt)
742 case "semanticTokens":
743 result.setBool(&o.SemanticTokens)
745 case "expandWorkspaceToModule":
746 result.setBool(&o.ExpandWorkspaceToModule)
748 case "experimentalWorkspaceModule":
749 result.setBool(&o.ExperimentalWorkspaceModule)
751 case "experimentalDiagnosticsDelay":
752 result.setDuration(&o.ExperimentalDiagnosticsDelay)
754 case "experimentalPackageCacheKey":
755 result.setBool(&o.ExperimentalPackageCacheKey)
757 case "allExperiments":
758 // This setting should be handled before all of the other options are
759 // processed, so do nothing here.
761 // Replaced settings.
762 case "experimentalDisabledAnalyses":
763 result.State = OptionDeprecated
764 result.Replacement = "analyses"
766 case "disableDeepCompletion":
767 result.State = OptionDeprecated
768 result.Replacement = "deepCompletion"
770 case "disableFuzzyMatching":
771 result.State = OptionDeprecated
772 result.Replacement = "fuzzyMatching"
774 case "wantCompletionDocumentation":
775 result.State = OptionDeprecated
776 result.Replacement = "completionDocumentation"
778 case "wantUnimportedCompletions":
779 result.State = OptionDeprecated
780 result.Replacement = "completeUnimported"
782 case "fuzzyMatching":
783 result.State = OptionDeprecated
784 result.Replacement = "matcher"
786 case "caseSensitiveCompletion":
787 result.State = OptionDeprecated
788 result.Replacement = "matcher"
790 // Deprecated settings.
791 case "wantSuggestedFixes":
792 result.State = OptionDeprecated
794 case "noIncrementalSync":
795 result.State = OptionDeprecated
797 case "watchFileChanges":
798 result.State = OptionDeprecated
801 result.State = OptionDeprecated
804 result.State = OptionUnexpected
809 func (r *OptionResult) errorf(msg string, values ...interface{}) {
810 prefix := fmt.Sprintf("parsing setting %q: ", r.Name)
811 r.Error = errors.Errorf(prefix+msg, values...)
814 func (r *OptionResult) asBool() (bool, bool) {
815 b, ok := r.Value.(bool)
817 r.errorf("invalid type %T, expect bool", r.Value)
823 func (r *OptionResult) setBool(b *bool) {
824 if v, ok := r.asBool(); ok {
829 func (r *OptionResult) setDuration(d *time.Duration) {
830 if v, ok := r.asString(); ok {
831 parsed, err := time.ParseDuration(v)
833 r.errorf("failed to parse duration %q: %v", v, err)
840 func (r *OptionResult) setBoolMap(bm *map[string]bool) {
841 all, ok := r.Value.(map[string]interface{})
843 r.errorf("invalid type %T for map[string]bool option", r.Value)
846 m := make(map[string]bool)
847 for a, enabled := range all {
848 if enabled, ok := enabled.(bool); ok {
851 r.errorf("invalid type %T for map key %q", enabled, a)
858 func (r *OptionResult) asString() (string, bool) {
859 b, ok := r.Value.(string)
861 r.errorf("invalid type %T, expect string", r.Value)
867 func (r *OptionResult) asOneOf(options ...string) (string, bool) {
868 s, ok := r.asString()
872 lower := strings.ToLower(s)
873 for _, opt := range options {
874 if strings.ToLower(opt) == lower {
878 r.errorf("invalid option %q for enum", r.Value)
882 func (r *OptionResult) setString(s *string) {
883 if v, ok := r.asString(); ok {
888 // EnabledAnalyzers returns all of the analyzers enabled for the given
890 func EnabledAnalyzers(snapshot Snapshot) (analyzers []Analyzer) {
891 for _, a := range snapshot.View().Options().DefaultAnalyzers {
892 if a.IsEnabled(snapshot.View()) {
893 analyzers = append(analyzers, a)
896 for _, a := range snapshot.View().Options().TypeErrorAnalyzers {
897 if a.IsEnabled(snapshot.View()) {
898 analyzers = append(analyzers, a)
901 for _, a := range snapshot.View().Options().ConvenienceAnalyzers {
902 if a.IsEnabled(snapshot.View()) {
903 analyzers = append(analyzers, a)
906 for _, a := range snapshot.View().Options().StaticcheckAnalyzers {
907 if a.IsEnabled(snapshot.View()) {
908 analyzers = append(analyzers, a)
914 func typeErrorAnalyzers() map[string]Analyzer {
915 return map[string]Analyzer{
916 fillreturns.Analyzer.Name: {
917 Analyzer: fillreturns.Analyzer,
918 FixesError: fillreturns.FixesError,
919 HighConfidence: true,
922 nonewvars.Analyzer.Name: {
923 Analyzer: nonewvars.Analyzer,
924 FixesError: nonewvars.FixesError,
927 noresultvalues.Analyzer.Name: {
928 Analyzer: noresultvalues.Analyzer,
929 FixesError: noresultvalues.FixesError,
932 undeclaredname.Analyzer.Name: {
933 Analyzer: undeclaredname.Analyzer,
934 FixesError: undeclaredname.FixesError,
935 Command: CommandUndeclaredName,
941 func convenienceAnalyzers() map[string]Analyzer {
942 return map[string]Analyzer{
943 fillstruct.Analyzer.Name: {
944 Analyzer: fillstruct.Analyzer,
945 Command: CommandFillStruct,
951 func defaultAnalyzers() map[string]Analyzer {
952 return map[string]Analyzer{
953 // The traditional vet suite:
954 asmdecl.Analyzer.Name: {Analyzer: asmdecl.Analyzer, Enabled: true},
955 assign.Analyzer.Name: {Analyzer: assign.Analyzer, Enabled: true},
956 atomic.Analyzer.Name: {Analyzer: atomic.Analyzer, Enabled: true},
957 atomicalign.Analyzer.Name: {Analyzer: atomicalign.Analyzer, Enabled: true},
958 bools.Analyzer.Name: {Analyzer: bools.Analyzer, Enabled: true},
959 buildtag.Analyzer.Name: {Analyzer: buildtag.Analyzer, Enabled: true},
960 cgocall.Analyzer.Name: {Analyzer: cgocall.Analyzer, Enabled: true},
961 composite.Analyzer.Name: {Analyzer: composite.Analyzer, Enabled: true},
962 copylock.Analyzer.Name: {Analyzer: copylock.Analyzer, Enabled: true},
963 errorsas.Analyzer.Name: {Analyzer: errorsas.Analyzer, Enabled: true},
964 httpresponse.Analyzer.Name: {Analyzer: httpresponse.Analyzer, Enabled: true},
965 loopclosure.Analyzer.Name: {Analyzer: loopclosure.Analyzer, Enabled: true},
966 lostcancel.Analyzer.Name: {Analyzer: lostcancel.Analyzer, Enabled: true},
967 nilfunc.Analyzer.Name: {Analyzer: nilfunc.Analyzer, Enabled: true},
968 printf.Analyzer.Name: {Analyzer: printf.Analyzer, Enabled: true},
969 shift.Analyzer.Name: {Analyzer: shift.Analyzer, Enabled: true},
970 stdmethods.Analyzer.Name: {Analyzer: stdmethods.Analyzer, Enabled: true},
971 structtag.Analyzer.Name: {Analyzer: structtag.Analyzer, Enabled: true},
972 tests.Analyzer.Name: {Analyzer: tests.Analyzer, Enabled: true},
973 unmarshal.Analyzer.Name: {Analyzer: unmarshal.Analyzer, Enabled: true},
974 unreachable.Analyzer.Name: {Analyzer: unreachable.Analyzer, Enabled: true},
975 unsafeptr.Analyzer.Name: {Analyzer: unsafeptr.Analyzer, Enabled: true},
976 unusedresult.Analyzer.Name: {Analyzer: unusedresult.Analyzer, Enabled: true},
978 // Non-vet analyzers:
979 deepequalerrors.Analyzer.Name: {Analyzer: deepequalerrors.Analyzer, Enabled: true},
980 sortslice.Analyzer.Name: {Analyzer: sortslice.Analyzer, Enabled: true},
981 testinggoroutine.Analyzer.Name: {Analyzer: testinggoroutine.Analyzer, Enabled: true},
982 unusedparams.Analyzer.Name: {Analyzer: unusedparams.Analyzer, Enabled: false},
985 simplifycompositelit.Analyzer.Name: {Analyzer: simplifycompositelit.Analyzer, Enabled: true, HighConfidence: true},
986 simplifyrange.Analyzer.Name: {Analyzer: simplifyrange.Analyzer, Enabled: true, HighConfidence: true},
987 simplifyslice.Analyzer.Name: {Analyzer: simplifyslice.Analyzer, Enabled: true, HighConfidence: true},
991 func urlRegexp() *regexp.Regexp {
992 // Ensure links are matched as full words, not anywhere.
993 re := regexp.MustCompile(`\b(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?\b`)
998 type APIJSON struct {
999 Options map[string][]*OptionJSON
1000 Commands []*CommandJSON
1004 type OptionJSON struct {
1008 EnumValues []EnumValue
1012 type EnumValue struct {
1017 type CommandJSON struct {
1023 type LensJSON struct {