Advertisement
kosx

options.go

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