diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3a20f22cbb..148a7523ea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,80 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
## Unreleased
+### Changes
+
+* Introduced quick pick separator in command `Go: Choose Go Environment` showing
+diff between options locally discovered and options available for download.
+* Added support for golangci-lint v2 ([Issue 3732](https://github.com/golang/vscode-go/issues/3732))
+ * Added a new lint tool, `golangci-lint-v2`. It's added as an installable tool, so you can install it via the `Go: Install/Update Tools` command.
+ * You can switch v1 and v2 per workspace by using `golangci-lint` and `golangci-lint-v2` option. You must keep the `golangci-lint` executable version on your machine to v1 for that.
+ * You can also use `golangci-lint` executable updated to v2. Just keep using the `golangci-lint` option for that.
+ * The `path-mode` flag set by vscode-go can be overridden by the`go.lintFlags` option.
+ * Looking for a way to format your code with golangci-lint v2 on VS Code? Check the [golangci-lint documentation](https://golangci-lint.run/welcome/integrations/#visual-studio-code).
+
+### Fixes
+
+* Addressed an issue that caused a `Cannot read properties of null (reading 'Token')`
+error during command execution when the command result did not include a token.
+([Issue 3698](https://github.com/golang/vscode-go/issues/3698))
+* Addressed an issue that broke the `Debug Subtest At Cursor` command. ([Issue 3718](https://github.com/golang/vscode-go/issues/3718))
+
+## v0.47.4 (prerelease)
+
+Date: 2025-06-23
+
+This is the [pre-release version](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#prerelease-extensions) of v0.48.
+
+**Full Changelog**: https://github.com/golang/vscode-go/compare/v0.46.0-rc.1...v0.47.4
+**Milestone**: https://github.com/golang/vscode-go/issues?q=milestone%3Av0.48.0
+
+## v0.47.3 (prerelease)
+
+Date: 2025-06-05
+
+This is the [pre-release version](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#prerelease-extensions) of v0.48.
+
+**Full Changelog**: https://github.com/golang/vscode-go/compare/v0.46.0-rc.1...v0.47.3
+**Milestone**: https://github.com/golang/vscode-go/issues?q=milestone%3Av0.48.0
+
+## v0.47.2 (prerelease)
+
+Date: 2025-04-15
+
+This is the [pre-release version](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#prerelease-extensions) of v0.48.
+
+**Full Changelog**: https://github.com/golang/vscode-go/compare/v0.46.0-rc.1...v0.47.2
+**Milestone**: https://github.com/golang/vscode-go/issues?q=milestone%3Av0.48.0
+
+## v0.46.1
+
+Date: 2025-03-04
+
+**Full Changelog**: https://github.com/golang/vscode-go/compare/v0.46.0...v0.46.1
+**Milestone**: https://github.com/golang/vscode-go/issues?q=milestone%3Av0.46.1
+
+## v0.47.1 (prerelease)
+
+Date: 2025-03-04
+
+This is the [pre-release version](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#prerelease-extensions) of v0.48.
+
+**Full Changelog**: https://github.com/golang/vscode-go/compare/v0.46.0-rc.1...v0.47.1
+**Milestone**: https://github.com/golang/vscode-go/issues?q=milestone%3Av0.48.0
+
+## v0.47.0 (prerelease)
+
+Date: 2025-02-27
+
+This is the [pre-release version](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#prerelease-extensions) of v0.48.
+
+**Full Changelog**: https://github.com/golang/vscode-go/compare/v0.46.0-rc.1...v0.47.0
+**Milestone**: https://github.com/golang/vscode-go/issues?q=milestone%3Av0.48.0
+
+## v0.46.0
+
+Date: 2025-02-27
+
### Code Health
* The testing framework is migrated from `Kokoro` to `LUCI`. The presubmit tests will be triggered against multiple go versions.
diff --git a/README.md b/README.md
index f78618bd16..3f74266473 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ provides rich language support for the
## Requirements
-* Visual Studio Code 1.75 or newer (or editors compatible with VS Code 1.75+ APIs)
+* Visual Studio Code 1.90 or newer (or editors compatible with VS Code 1.90+ APIs)
* Go 1.21 or newer.
## Quick Start
diff --git a/docs/advanced.md b/docs/advanced.md
index a2c0ba0c53..a79c2b3231 100644
--- a/docs/advanced.md
+++ b/docs/advanced.md
@@ -63,7 +63,7 @@ name.
The extension uses pinned versions of command-line tools. See the pinned versions
in tools information
-[here](https://github.com/golang/vscode-go/blob/master/src/goToolsInformation.ts).
+[here](https://github.com/golang/vscode-go/blob/master/extension/src/goToolsInformation.ts).
To use an alternate version of a tool install it manually with with go install.
## Using a custom linter
diff --git a/docs/commands.md b/docs/commands.md
index cd61af788b..6730c7caeb 100644
--- a/docs/commands.md
+++ b/docs/commands.md
@@ -169,11 +169,11 @@ Start the Go language server's maintainer interface (a web server).
### `Go: Add Tags To Struct Fields`
-Add tags configured in go.addTags setting to selected struct using gomodifytags
+Add tags configured in go.addTags setting to selected struct using gomodifytags (via gopls)
### `Go: Remove Tags From Struct Fields`
-Remove tags configured in go.removeTags setting from selected struct using gomodifytags
+Remove tags configured in go.removeTags setting from selected struct using gomodifytags (via gopls)
### `Go: Show All Commands...`
diff --git a/docs/contributing.md b/docs/contributing.md
index 9442080e40..501e2cf941 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -101,7 +101,7 @@ When running them from terminal:
You can supply environment variables (e.g. `MOCHA_GREP`) by modifying the launch configuration entry's `env` property.
- `Launch Unit Tests`: runs unit tests in `test/unit` (same as `npm run unit-test`)
- `Launch Extension Tests`: runs tests in `test/integration` directory (similar to `npm run test` but runs only tests under `test/integration` directory)
- - `Launch Extension Tests with Gopls`: runs tests in `test/gopls directory (similar to `npm run test` but runs only tests under `test/gopls` directory)
+ - `Launch Extension Tests with Gopls`: runs tests in `test/gopls` directory (similar to `npm run test` but runs only tests under `test/gopls` directory)
When you want to filter tests while debugging, utilize the `MOCAH_GREP` environment variable discussed previously - i.e., set the environment variable in the `env` property of the launch configuration.
diff --git a/docs/features.md b/docs/features.md
index 953ac4bd1f..4396c32301 100644
--- a/docs/features.md
+++ b/docs/features.md
@@ -253,7 +253,7 @@ For known issues with this feature see [golang/go#37170](https://github.com/gola
### Add or remove struct tags
-Use the [`Go: Add Tags to Struct Fields`](commands.md#go-add-tags-to-struct-fields) command to automatically generate or remove [tags](https://pkg.go.dev/reflect?tab=doc#StructTag) for your struct. This feature is provided by the [`gomodifytags`](tools.md#gomodifytags) tool.
+Use the [`Go: Add Tags to Struct Fields`](commands.md#go-add-tags-to-struct-fields) command to automatically generate or remove [tags](https://pkg.go.dev/reflect?tab=doc#StructTag) for your struct. This feature is provided by the [`gomodifytags`](tools.md#gomodifytags) tool invoked via gopls.
diff --git a/docs/settings.md b/docs/settings.md
index fa4abf37a6..7052e18e98 100644
--- a/docs/settings.md
+++ b/docs/settings.md
@@ -362,7 +362,7 @@ Default: `"package"`
### `go.lintTool`
Specifies Lint tool name.
-Allowed Options: `staticcheck`, `golint`, `golangci-lint`, `revive`
+Allowed Options: `staticcheck`, `golint`, `golangci-lint`, `golangci-lint-v2`, `revive`
Default: `"staticcheck"`
### `go.logging.level (deprecated)`
@@ -676,12 +676,12 @@ Example Usage:
| --- | --- |
| `generate` | `"generate"`: Run `go generate` This codelens source annotates any `//go:generate` comments with commands to run `go generate` in this directory, on all directories recursively beneath this one. See [Generating code](https://go.dev/blog/generate) for more details.
Default: `true` |
| `regenerate_cgo` | `"regenerate_cgo"`: Re-generate cgo declarations This codelens source annotates an `import "C"` declaration with a command to re-run the [cgo command](https://pkg.go.dev/cmd/cgo) to regenerate the corresponding Go declarations. Use this after editing the C code in comments attached to the import, or in C header files included by it.
Default: `true` |
-| `run_govulncheck` | `"run_govulncheck"`: Run govulncheck (legacy) This codelens source annotates the `module` directive in a go.mod file with a command to run Govulncheck asynchronously. [Govulncheck](https://go.dev/blog/vuln) is a static analysis tool that computes the set of functions reachable within your application, including dependencies; queries a database of known security vulnerabilities; and reports any potential problems it finds.
Default: `false` |
+| `run_govulncheck` | (Experimental) `"run_govulncheck"`: Run govulncheck (legacy) This codelens source annotates the `module` directive in a go.mod file with a command to run Govulncheck asynchronously. [Govulncheck](https://go.dev/blog/vuln) is a static analysis tool that computes the set of functions reachable within your application, including dependencies; queries a database of known security vulnerabilities; and reports any potential problems it finds.
Default: `false` |
| `test` | `"test"`: Run tests and benchmarks This codelens source annotates each `Test` and `Benchmark` function in a `*_test.go` file with a command to run it. This source is off by default because VS Code has a client-side custom UI for testing, and because progress notifications are not a great UX for streamed test output. See: - golang/go#67400 for a discussion of this feature. - https://github.com/joaotavora/eglot/discussions/1402 for an alternative approach.
Default: `false` |
| `tidy` | `"tidy"`: Tidy go.mod file This codelens source annotates the `module` directive in a go.mod file with a command to run [`go mod tidy`](https://go.dev/ref/mod#go-mod-tidy), which ensures that the go.mod file matches the source code in the module.
Default: `true` |
| `upgrade_dependency` | `"upgrade_dependency"`: Update dependencies This codelens source annotates the `module` directive in a go.mod file with commands to: - check for available upgrades, - upgrade direct dependencies, and - upgrade all dependencies transitively.
Default: `true` |
| `vendor` | `"vendor"`: Update vendor directory This codelens source annotates the `module` directive in a go.mod file with a command to run [`go mod vendor`](https://go.dev/ref/mod#go-mod-vendor), which creates or updates the directory named `vendor` in the module root so that it contains an up-to-date copy of all necessary package dependencies.
Default: `true` |
-| `vulncheck` | `"vulncheck"`: Run govulncheck This codelens source annotates the `module` directive in a go.mod file with a command to run govulncheck synchronously. [Govulncheck](https://go.dev/blog/vuln) is a static analysis tool that computes the set of functions reachable within your application, including dependencies; queries a database of known security vulnerabilities; and reports any potential problems it finds.
Default: `false` |
+| `vulncheck` | (Experimental) `"vulncheck"`: Run govulncheck This codelens source annotates the `module` directive in a go.mod file with a command to run govulncheck synchronously. [Govulncheck](https://go.dev/blog/vuln) is a static analysis tool that computes the set of functions reachable within your application, including dependencies; queries a database of known security vulnerabilities; and reports any potential problems it finds.
Default: `false` |
### `ui.completion.completeFunctionCalls`
completeFunctionCalls enables function call completion.
@@ -744,6 +744,161 @@ Example Usage:
| Properties | Description |
| --- | --- |
+| `QF1001` | Apply De Morgan's law Available since 2021.1
Default: `false` |
+| `QF1002` | Convert untagged switch to tagged switch An untagged switch that compares a single variable against a series of values can be replaced with a tagged switch. Before: switch { case x == 1 || x == 2, x == 3: ... case x == 4: ... default: ... } After: switch x { case 1, 2, 3: ... case 4: ... default: ... } Available since 2021.1
Default: `true` |
+| `QF1003` | Convert if/else-if chain to tagged switch A series of if/else-if checks comparing the same variable against values can be replaced with a tagged switch. Before: if x == 1 || x == 2 { ... } else if x == 3 { ... } else { ... } After: switch x { case 1, 2: ... case 3: ... default: ... } Available since 2021.1
Default: `true` |
+| `QF1004` | Use strings.ReplaceAll instead of strings.Replace with n == -1 Available since 2021.1
Default: `true` |
+| `QF1005` | Expand call to math.Pow Some uses of math.Pow can be simplified to basic multiplication. Before: math.Pow(x, 2) After: x * x Available since 2021.1
Default: `false` |
+| `QF1006` | Lift if+break into loop condition Before: for { if done { break } ... } After: for !done { ... } Available since 2021.1
Default: `false` |
+| `QF1007` | Merge conditional assignment into variable declaration Before: x := false if someCondition { x = true } After: x := someCondition Available since 2021.1
Default: `false` |
+| `QF1008` | Omit embedded fields from selector expression Available since 2021.1
Default: `false` |
+| `QF1009` | Use time.Time.Equal instead of == operator Available since 2021.1
Default: `true` |
+| `QF1010` | Convert slice of bytes to string when printing it Available since 2021.1
Default: `true` |
+| `QF1011` | Omit redundant type from variable declaration Available since 2021.1
Default: `false` |
+| `QF1012` | Use fmt.Fprintf(x, ...) instead of x.Write(fmt.Sprintf(...)) Available since 2022.1
Default: `true` |
+| `S1000` | Use plain channel send or receive instead of single-case select Select statements with a single case can be replaced with a simple send or receive. Before: select { case x := <-ch: fmt.Println(x) } After: x := <-ch fmt.Println(x) Available since 2017.1
Default: `true` |
+| `S1001` | Replace for loop with call to copy Use copy() for copying elements from one slice to another. For arrays of identical size, you can use simple assignment. Before: for i, x := range src { dst[i] = x } After: copy(dst, src) Available since 2017.1
Default: `true` |
+| `S1002` | Omit comparison with boolean constant Before: if x == true {} After: if x {} Available since 2017.1
Default: `false` |
+| `S1003` | Replace call to strings.Index with strings.Contains Before: if strings.Index(x, y) != -1 {} After: if strings.Contains(x, y) {} Available since 2017.1
Default: `true` |
+| `S1004` | Replace call to bytes.Compare with bytes.Equal Before: if bytes.Compare(x, y) == 0 {} After: if bytes.Equal(x, y) {} Available since 2017.1
Default: `true` |
+| `S1005` | Drop unnecessary use of the blank identifier In many cases, assigning to the blank identifier is unnecessary. Before: for _ = range s {} x, _ = someMap[key] _ = <-ch After: for range s{} x = someMap[key] <-ch Available since 2017.1
Default: `false` |
+| `S1006` | Use 'for { ... }' for infinite loops For infinite loops, using for { ... } is the most idiomatic choice. Available since 2017.1
Default: `false` |
+| `S1007` | Simplify regular expression by using raw string literal Raw string literals use backticks instead of quotation marks and do not support any escape sequences. This means that the backslash can be used freely, without the need of escaping. Since regular expressions have their own escape sequences, raw strings can improve their readability. Before: regexp.Compile("\\A(\\w+) profile: total \\d+\\n\\z") After: regexp.Compile(`\A(\w+) profile: total \d+\n\z`) Available since 2017.1
Default: `true` |
+| `S1008` | Simplify returning boolean expression Before: if { return true } return false After: return Available since 2017.1
Default: `false` |
+| `S1009` | Omit redundant nil check on slices, maps, and channels The len function is defined for all slices, maps, and channels, even nil ones, which have a length of zero. It is not necessary to check for nil before checking that their length is not zero. Before: if x != nil && len(x) != 0 {} After: if len(x) != 0 {} Available since 2017.1
Default: `true` |
+| `S1010` | Omit default slice index When slicing, the second index defaults to the length of the value, making s[n:len(s)] and s[n:] equivalent. Available since 2017.1
Default: `true` |
+| `S1011` | Use a single append to concatenate two slices Before: for _, e := range y { x = append(x, e) } for i := range y { x = append(x, y[i]) } for i := range y { v := y[i] x = append(x, v) } After: x = append(x, y...) x = append(x, y...) x = append(x, y...) Available since 2017.1
Default: `false` |
+| `S1012` | Replace time.Now().Sub(x) with time.Since(x) The time.Since helper has the same effect as using time.Now().Sub(x) but is easier to read. Before: time.Now().Sub(x) After: time.Since(x) Available since 2017.1
Default: `true` |
+| `S1016` | Use a type conversion instead of manually copying struct fields Two struct types with identical fields can be converted between each other. In older versions of Go, the fields had to have identical struct tags. Since Go 1.8, however, struct tags are ignored during conversions. It is thus not necessary to manually copy every field individually. Before: var x T1 y := T2{ Field1: x.Field1, Field2: x.Field2, } After: var x T1 y := T2(x) Available since 2017.1
Default: `false` |
+| `S1017` | Replace manual trimming with strings.TrimPrefix Instead of using strings.HasPrefix and manual slicing, use the strings.TrimPrefix function. If the string doesn't start with the prefix, the original string will be returned. Using strings.TrimPrefix reduces complexity, and avoids common bugs, such as off-by-one mistakes. Before: if strings.HasPrefix(str, prefix) { str = str[len(prefix):] } After: str = strings.TrimPrefix(str, prefix) Available since 2017.1
Default: `true` |
+| `S1018` | Use 'copy' for sliding elements copy() permits using the same source and destination slice, even with overlapping ranges. This makes it ideal for sliding elements in a slice. Before: for i := 0; i < n; i++ { bs[i] = bs[offset+i] } After: copy(bs[:n], bs[offset:]) Available since 2017.1
Default: `true` |
+| `S1019` | Simplify 'make' call by omitting redundant arguments The 'make' function has default values for the length and capacity arguments. For channels, the length defaults to zero, and for slices, the capacity defaults to the length. Available since 2017.1
Default: `true` |
+| `S1020` | Omit redundant nil check in type assertion Before: if _, ok := i.(T); ok && i != nil {} After: if _, ok := i.(T); ok {} Available since 2017.1
Default: `true` |
+| `S1021` | Merge variable declaration and assignment Before: var x uint x = 1 After: var x uint = 1 Available since 2017.1
Default: `false` |
+| `S1023` | Omit redundant control flow Functions that have no return value do not need a return statement as the final statement of the function. Switches in Go do not have automatic fallthrough, unlike languages like C. It is not necessary to have a break statement as the final statement in a case block. Available since 2017.1
Default: `true` |
+| `S1024` | Replace x.Sub(time.Now()) with time.Until(x) The time.Until helper has the same effect as using x.Sub(time.Now()) but is easier to read. Before: x.Sub(time.Now()) After: time.Until(x) Available since 2017.1
Default: `true` |
+| `S1025` | Don't use fmt.Sprintf("%s", x) unnecessarily In many instances, there are easier and more efficient ways of getting a value's string representation. Whenever a value's underlying type is a string already, or the type has a String method, they should be used directly. Given the following shared definitions type T1 string type T2 int func (T2) String() string { return "Hello, world" } var x string var y T1 var z T2 we can simplify fmt.Sprintf("%s", x) fmt.Sprintf("%s", y) fmt.Sprintf("%s", z) to x string(y) z.String() Available since 2017.1
Default: `false` |
+| `S1028` | Simplify error construction with fmt.Errorf Before: errors.New(fmt.Sprintf(...)) After: fmt.Errorf(...) Available since 2017.1
Default: `true` |
+| `S1029` | Range over the string directly Ranging over a string will yield byte offsets and runes. If the offset isn't used, this is functionally equivalent to converting the string to a slice of runes and ranging over that. Ranging directly over the string will be more performant, however, as it avoids allocating a new slice, the size of which depends on the length of the string. Before: for _, r := range []rune(s) {} After: for _, r := range s {} Available since 2017.1
Default: `false` |
+| `S1030` | Use bytes.Buffer.String or bytes.Buffer.Bytes bytes.Buffer has both a String and a Bytes method. It is almost never necessary to use string(buf.Bytes()) or []byte(buf.String()) – simply use the other method. The only exception to this are map lookups. Due to a compiler optimization, m[string(buf.Bytes())] is more efficient than m[buf.String()]. Available since 2017.1
Default: `true` |
+| `S1031` | Omit redundant nil check around loop You can use range on nil slices and maps, the loop will simply never execute. This makes an additional nil check around the loop unnecessary. Before: if s != nil { for _, x := range s { ... } } After: for _, x := range s { ... } Available since 2017.1
Default: `true` |
+| `S1032` | Use sort.Ints(x), sort.Float64s(x), and sort.Strings(x) The sort.Ints, sort.Float64s and sort.Strings functions are easier to read than sort.Sort(sort.IntSlice(x)), sort.Sort(sort.Float64Slice(x)) and sort.Sort(sort.StringSlice(x)). Before: sort.Sort(sort.StringSlice(x)) After: sort.Strings(x) Available since 2019.1
Default: `true` |
+| `S1033` | Unnecessary guard around call to 'delete' Calling delete on a nil map is a no-op. Available since 2019.2
Default: `true` |
+| `S1034` | Use result of type assertion to simplify cases Available since 2019.2
Default: `true` |
+| `S1035` | Redundant call to net/http.CanonicalHeaderKey in method call on net/http.Header The methods on net/http.Header, namely Add, Del, Get and Set, already canonicalize the given header name. Available since 2020.1
Default: `true` |
+| `S1036` | Unnecessary guard around map access When accessing a map key that doesn't exist yet, one receives a zero value. Often, the zero value is a suitable value, for example when using append or doing integer math. The following if _, ok := m["foo"]; ok { m["foo"] = append(m["foo"], "bar") } else { m["foo"] = []string{"bar"} } can be simplified to m["foo"] = append(m["foo"], "bar") and if _, ok := m2["k"]; ok { m2["k"] += 4 } else { m2["k"] = 4 } can be simplified to m["k"] += 4 Available since 2020.1
Default: `true` |
+| `S1037` | Elaborate way of sleeping Using a select statement with a single case receiving from the result of time.After is a very elaborate way of sleeping that can much simpler be expressed with a simple call to time.Sleep. Available since 2020.1
Default: `true` |
+| `S1038` | Unnecessarily complex way of printing formatted string Instead of using fmt.Print(fmt.Sprintf(...)), one can use fmt.Printf(...). Available since 2020.1
Default: `true` |
+| `S1039` | Unnecessary use of fmt.Sprint Calling fmt.Sprint with a single string argument is unnecessary and identical to using the string directly. Available since 2020.1
Default: `true` |
+| `S1040` | Type assertion to current type The type assertion x.(SomeInterface), when x already has type SomeInterface, can only fail if x is nil. Usually, this is left-over code from when x had a different type and you can safely delete the type assertion. If you want to check that x is not nil, consider being explicit and using an actual if x == nil comparison instead of relying on the type assertion panicking. Available since 2021.1
Default: `true` |
+| `SA1000` | Invalid regular expression Available since 2017.1
Default: `false` |
+| `SA1001` | Invalid template Available since 2017.1
Default: `true` |
+| `SA1002` | Invalid format in time.Parse Available since 2017.1
Default: `false` |
+| `SA1003` | Unsupported argument to functions in encoding/binary The encoding/binary package can only serialize types with known sizes. This precludes the use of the int and uint types, as their sizes differ on different architectures. Furthermore, it doesn't support serializing maps, channels, strings, or functions. Before Go 1.8, bool wasn't supported, either. Available since 2017.1
Default: `false` |
+| `SA1004` | Suspiciously small untyped constant in time.Sleep The time.Sleep function takes a time.Duration as its only argument. Durations are expressed in nanoseconds. Thus, calling time.Sleep(1) will sleep for 1 nanosecond. This is a common source of bugs, as sleep functions in other languages often accept seconds or milliseconds. The time package provides constants such as time.Second to express large durations. These can be combined with arithmetic to express arbitrary durations, for example 5 * time.Second for 5 seconds. If you truly meant to sleep for a tiny amount of time, use n * time.Nanosecond to signal to Staticcheck that you did mean to sleep for some amount of nanoseconds. Available since 2017.1
Default: `true` |
+| `SA1005` | Invalid first argument to exec.Command os/exec runs programs directly (using variants of the fork and exec system calls on Unix systems). This shouldn't be confused with running a command in a shell. The shell will allow for features such as input redirection, pipes, and general scripting. The shell is also responsible for splitting the user's input into a program name and its arguments. For example, the equivalent to ls / /tmp would be exec.Command("ls", "/", "/tmp") If you want to run a command in a shell, consider using something like the following – but be aware that not all systems, particularly Windows, will have a /bin/sh program: exec.Command("/bin/sh", "-c", "ls | grep Awesome") Available since 2017.1
Default: `true` |
+| `SA1007` | Invalid URL in net/url.Parse Available since 2017.1
Default: `false` |
+| `SA1008` | Non-canonical key in http.Header map Keys in http.Header maps are canonical, meaning they follow a specific combination of uppercase and lowercase letters. Methods such as http.Header.Add and http.Header.Del convert inputs into this canonical form before manipulating the map. When manipulating http.Header maps directly, as opposed to using the provided methods, care should be taken to stick to canonical form in order to avoid inconsistencies. The following piece of code demonstrates one such inconsistency: h := http.Header{} h["etag"] = []string{"1234"} h.Add("etag", "5678") fmt.Println(h) // Output: // map[Etag:[5678] etag:[1234]] The easiest way of obtaining the canonical form of a key is to use http.CanonicalHeaderKey. Available since 2017.1
Default: `true` |
+| `SA1010` | (*regexp.Regexp).FindAll called with n == 0, which will always return zero results If n >= 0, the function returns at most n matches/submatches. To return all results, specify a negative number. Available since 2017.1
Default: `false` |
+| `SA1011` | Various methods in the 'strings' package expect valid UTF-8, but invalid input is provided Available since 2017.1
Default: `false` |
+| `SA1012` | A nil context.Context is being passed to a function, consider using context.TODO instead Available since 2017.1
Default: `true` |
+| `SA1013` | io.Seeker.Seek is being called with the whence constant as the first argument, but it should be the second Available since 2017.1
Default: `true` |
+| `SA1014` | Non-pointer value passed to Unmarshal or Decode Available since 2017.1
Default: `false` |
+| `SA1015` | Using time.Tick in a way that will leak. Consider using time.NewTicker, and only use time.Tick in tests, commands and endless functions Before Go 1.23, time.Tickers had to be closed to be able to be garbage collected. Since time.Tick doesn't make it possible to close the underlying ticker, using it repeatedly would leak memory. Go 1.23 fixes this by allowing tickers to be collected even if they weren't closed. Available since 2017.1
Default: `false` |
+| `SA1016` | Trapping a signal that cannot be trapped Not all signals can be intercepted by a process. Specifically, on UNIX-like systems, the syscall.SIGKILL and syscall.SIGSTOP signals are never passed to the process, but instead handled directly by the kernel. It is therefore pointless to try and handle these signals. Available since 2017.1
Default: `true` |
+| `SA1017` | Channels used with os/signal.Notify should be buffered The os/signal package uses non-blocking channel sends when delivering signals. If the receiving end of the channel isn't ready and the channel is either unbuffered or full, the signal will be dropped. To avoid missing signals, the channel should be buffered and of the appropriate size. For a channel used for notification of just one signal value, a buffer of size 1 is sufficient. Available since 2017.1
Default: `false` |
+| `SA1018` | strings.Replace called with n == 0, which does nothing With n == 0, zero instances will be replaced. To replace all instances, use a negative number, or use strings.ReplaceAll. Available since 2017.1
Default: `false` |
+| `SA1020` | Using an invalid host:port pair with a net.Listen-related function Available since 2017.1
Default: `false` |
+| `SA1021` | Using bytes.Equal to compare two net.IP A net.IP stores an IPv4 or IPv6 address as a slice of bytes. The length of the slice for an IPv4 address, however, can be either 4 or 16 bytes long, using different ways of representing IPv4 addresses. In order to correctly compare two net.IPs, the net.IP.Equal method should be used, as it takes both representations into account. Available since 2017.1
Default: `false` |
+| `SA1023` | Modifying the buffer in an io.Writer implementation Write must not modify the slice data, even temporarily. Available since 2017.1
Default: `false` |
+| `SA1024` | A string cutset contains duplicate characters The strings.TrimLeft and strings.TrimRight functions take cutsets, not prefixes. A cutset is treated as a set of characters to remove from a string. For example, strings.TrimLeft("42133word", "1234") will result in the string "word" – any characters that are 1, 2, 3 or 4 are cut from the left of the string. In order to remove one string from another, use strings.TrimPrefix instead. Available since 2017.1
Default: `false` |
+| `SA1025` | It is not possible to use (*time.Timer).Reset's return value correctly Available since 2019.1
Default: `false` |
+| `SA1026` | Cannot marshal channels or functions Available since 2019.2
Default: `false` |
+| `SA1027` | Atomic access to 64-bit variable must be 64-bit aligned On ARM, x86-32, and 32-bit MIPS, it is the caller's responsibility to arrange for 64-bit alignment of 64-bit words accessed atomically. The first word in a variable or in an allocated struct, array, or slice can be relied upon to be 64-bit aligned. You can use the structlayout tool to inspect the alignment of fields in a struct. Available since 2019.2
Default: `false` |
+| `SA1028` | sort.Slice can only be used on slices The first argument of sort.Slice must be a slice. Available since 2020.1
Default: `false` |
+| `SA1029` | Inappropriate key in call to context.WithValue The provided key must be comparable and should not be of type string or any other built-in type to avoid collisions between packages using context. Users of WithValue should define their own types for keys. To avoid allocating when assigning to an interface{}, context keys often have concrete type struct{}. Alternatively, exported context key variables' static type should be a pointer or interface. Available since 2020.1
Default: `false` |
+| `SA1030` | Invalid argument in call to a strconv function This check validates the format, number base and bit size arguments of the various parsing and formatting functions in strconv. Available since 2021.1
Default: `false` |
+| `SA1031` | Overlapping byte slices passed to an encoder In an encoding function of the form Encode(dst, src), dst and src were found to reference the same memory. This can result in src bytes being overwritten before they are read, when the encoder writes more than one byte per src byte. Available since 2024.1
Default: `false` |
+| `SA1032` | Wrong order of arguments to errors.Is The first argument of the function errors.Is is the error that we have and the second argument is the error we're trying to match against. For example:
if errors.Is(err, io.EOF) { ... }
This check detects some cases where the two arguments have been swapped. It flags any calls where the first argument is referring to a package-level error variable, such as
if errors.Is(io.EOF, err) { /* this is wrong */ }
Available since 2024.1
Default: `false` |
+| `SA2001` | Empty critical section, did you mean to defer the unlock? Empty critical sections of the kind mu.Lock() mu.Unlock() are very often a typo, and the following was intended instead: mu.Lock() defer mu.Unlock() Do note that sometimes empty critical sections can be useful, as a form of signaling to wait on another goroutine. Many times, there are simpler ways of achieving the same effect. When that isn't the case, the code should be amply commented to avoid confusion. Combining such comments with a //lint:ignore directive can be used to suppress this rare false positive. Available since 2017.1
Default: `true` |
+| `SA2002` | Called testing.T.FailNow or SkipNow in a goroutine, which isn't allowed Available since 2017.1
Default: `false` |
+| `SA2003` | Deferred Lock right after locking, likely meant to defer Unlock instead Available since 2017.1
Default: `false` |
+| `SA3000` | TestMain doesn't call os.Exit, hiding test failures Test executables (and in turn 'go test') exit with a non-zero status code if any tests failed. When specifying your own TestMain function, it is your responsibility to arrange for this, by calling os.Exit with the correct code. The correct code is returned by (*testing.M).Run, so the usual way of implementing TestMain is to end it with os.Exit(m.Run()). Available since 2017.1
Default: `true` |
+| `SA3001` | Assigning to b.N in benchmarks distorts the results The testing package dynamically sets b.N to improve the reliability of benchmarks and uses it in computations to determine the duration of a single operation. Benchmark code must not alter b.N as this would falsify results. Available since 2017.1
Default: `true` |
+| `SA4000` | Binary operator has identical expressions on both sides Available since 2017.1
Default: `true` |
+| `SA4001` | &*x gets simplified to x, it does not copy x Available since 2017.1
Default: `true` |
+| `SA4003` | Comparing unsigned values against negative values is pointless Available since 2017.1
Default: `true` |
+| `SA4004` | The loop exits unconditionally after one iteration Available since 2017.1
Default: `true` |
+| `SA4005` | Field assignment that will never be observed. Did you mean to use a pointer receiver? Available since 2021.1
Default: `false` |
+| `SA4006` | A value assigned to a variable is never read before being overwritten. Forgotten error check or dead code? Available since 2017.1
Default: `false` |
+| `SA4008` | The variable in the loop condition never changes, are you incrementing the wrong variable? For example:
for i := 0; i < 10; j++ { ... }
This may also occur when a loop can only execute once because of unconditional control flow that terminates the loop. For example, when a loop body contains an unconditional break, return, or panic:
func f() { panic("oops") } func g() { for i := 0; i < 10; i++ { // f unconditionally calls panic, which means "i" is // never incremented. f() } }
Available since 2017.1
Default: `false` |
+| `SA4009` | A function argument is overwritten before its first use Available since 2017.1
Default: `false` |
+| `SA4010` | The result of append will never be observed anywhere Available since 2017.1
Default: `false` |
+| `SA4011` | Break statement with no effect. Did you mean to break out of an outer loop? Available since 2017.1
Default: `true` |
+| `SA4012` | Comparing a value against NaN even though no value is equal to NaN Available since 2017.1
Default: `false` |
+| `SA4013` | Negating a boolean twice (!!b) is the same as writing b. This is either redundant, or a typo. Available since 2017.1
Default: `true` |
+| `SA4014` | An if/else if chain has repeated conditions and no side-effects; if the condition didn't match the first time, it won't match the second time, either Available since 2017.1
Default: `true` |
+| `SA4015` | Calling functions like math.Ceil on floats converted from integers doesn't do anything useful Available since 2017.1
Default: `false` |
+| `SA4016` | Certain bitwise operations, such as x ^ 0, do not do anything useful Available since 2017.1
Default: `true` |
+| `SA4017` | Discarding the return values of a function without side effects, making the call pointless Available since 2017.1
Default: `false` |
+| `SA4018` | Self-assignment of variables Available since 2017.1
Default: `false` |
+| `SA4019` | Multiple, identical build constraints in the same file Available since 2017.1
Default: `true` |
+| `SA4020` | Unreachable case clause in a type switch In a type switch like the following type T struct{} func (T) Read(b []byte) (int, error) { return 0, nil } var v any = T{} switch v.(type) { case io.Reader: // ... case T: // unreachable } the second case clause can never be reached because T implements io.Reader and case clauses are evaluated in source order. Another example: type T struct{} func (T) Read(b []byte) (int, error) { return 0, nil } func (T) Close() error { return nil } var v any = T{} switch v.(type) { case io.Reader: // ... case io.ReadCloser: // unreachable } Even though T has a Close method and thus implements io.ReadCloser, io.Reader will always match first. The method set of io.Reader is a subset of io.ReadCloser. Thus it is impossible to match the second case without matching the first case.
Structurally equivalent interfaces A special case of the previous example are structurally identical interfaces. Given these declarations type T error type V error func doSomething() error { err, ok := doAnotherThing() if ok { return T(err) } return U(err) } the following type switch will have an unreachable case clause: switch doSomething().(type) { case T: // ... case V: // unreachable } T will always match before V because they are structurally equivalent and therefore doSomething()'s return value implements both. Available since 2019.2
Default: `true` |
+| `SA4022` | Comparing the address of a variable against nil Code such as 'if &x == nil' is meaningless, because taking the address of a variable always yields a non-nil pointer. Available since 2020.1
Default: `true` |
+| `SA4023` | Impossible comparison of interface value with untyped nil Under the covers, interfaces are implemented as two elements, a type T and a value V. V is a concrete value such as an int, struct or pointer, never an interface itself, and has type T. For instance, if we store the int value 3 in an interface, the resulting interface value has, schematically, (T=int, V=3). The value V is also known as the interface's dynamic value, since a given interface variable might hold different values V (and corresponding types T) during the execution of the program. An interface value is nil only if the V and T are both unset, (T=nil, V is not set), In particular, a nil interface will always hold a nil type. If we store a nil pointer of type *int inside an interface value, the inner type will be *int regardless of the value of the pointer: (T=*int, V=nil). Such an interface value will therefore be non-nil even when the pointer value V inside is nil. This situation can be confusing, and arises when a nil value is stored inside an interface value such as an error return: func returnsError() error { var p *MyError = nil if bad() { p = ErrBad } return p // Will always return a non-nil error. } If all goes well, the function returns a nil p, so the return value is an error interface value holding (T=*MyError, V=nil). This means that if the caller compares the returned error to nil, it will always look as if there was an error even if nothing bad happened. To return a proper nil error to the caller, the function must return an explicit nil: func returnsError() error { if bad() { return ErrBad } return nil } It's a good idea for functions that return errors always to use the error type in their signature (as we did above) rather than a concrete type such as *MyError, to help guarantee the error is created correctly. As an example, os.Open returns an error even though, if not nil, it's always of concrete type *os.PathError. Similar situations to those described here can arise whenever interfaces are used. Just keep in mind that if any concrete value has been stored in the interface, the interface will not be nil. For more information, see The Laws of Reflection at https://golang.org/doc/articles/laws_of_reflection.html. This text has been copied from https://golang.org/doc/faq#nil_error, licensed under the Creative Commons Attribution 3.0 License. Available since 2020.2
Default: `false` |
+| `SA4024` | Checking for impossible return value from a builtin function Return values of the len and cap builtins cannot be negative. See https://golang.org/pkg/builtin/#len and https://golang.org/pkg/builtin/#cap. Example: if len(slice) < 0 { fmt.Println("unreachable code") } Available since 2021.1
Default: `true` |
+| `SA4025` | Integer division of literals that results in zero When dividing two integer constants, the result will also be an integer. Thus, a division such as 2 / 3 results in 0. This is true for all of the following examples:
Staticcheck will flag such divisions if both sides of the division are integer literals, as it is highly unlikely that the division was intended to truncate to zero. Staticcheck will not flag integer division involving named constants, to avoid noisy positives. Available since 2021.1
Default: `true` |
+| `SA4026` | Go constants cannot express negative zero In IEEE 754 floating point math, zero has a sign and can be positive or negative. This can be useful in certain numerical code. Go constants, however, cannot express negative zero. This means that the literals -0.0 and 0.0 have the same ideal value (zero) and will both represent positive zero at runtime. To explicitly and reliably create a negative zero, you can use the math.Copysign function: math.Copysign(0, -1). Available since 2021.1
Default: `true` |
+| `SA4027` | (*net/url.URL).Query returns a copy, modifying it doesn't change the URL (*net/url.URL).Query parses the current value of net/url.URL.RawQuery and returns it as a map of type net/url.Values. Subsequent changes to this map will not affect the URL unless the map gets encoded and assigned to the URL's RawQuery. As a consequence, the following code pattern is an expensive no-op: u.Query().Add(key, value). Available since 2021.1
Default: `true` |
+| `SA4028` | x % 1 is always zero Available since 2022.1
Default: `true` |
+| `SA4029` | Ineffective attempt at sorting slice sort.Float64Slice, sort.IntSlice, and sort.StringSlice are types, not functions. Doing x = sort.StringSlice(x) does nothing, especially not sort any values. The correct usage is sort.Sort(sort.StringSlice(x)) or sort.StringSlice(x).Sort(), but there are more convenient helpers, namely sort.Float64s, sort.Ints, and sort.Strings. Available since 2022.1
Default: `true` |
+| `SA4030` | Ineffective attempt at generating random number Functions in the math/rand package that accept upper limits, such as Intn, generate random numbers in the half-open interval [0,n). In other words, the generated numbers will be >= 0 and < n – they don't include n. rand.Intn(1) therefore doesn't generate 0 or 1, it always generates 0. Available since 2022.1
Default: `true` |
+| `SA4031` | Checking never-nil value against nil Available since 2022.1
Default: `false` |
+| `SA4032` | Comparing runtime.GOOS or runtime.GOARCH against impossible value Available since 2024.1
Default: `true` |
+| `SA5000` | Assignment to nil map Available since 2017.1
Default: `false` |
+| `SA5001` | Deferring Close before checking for a possible error Available since 2017.1
Default: `true` |
+| `SA5002` | The empty for loop ('for {}') spins and can block the scheduler Available since 2017.1
Default: `false` |
+| `SA5003` | Defers in infinite loops will never execute Defers are scoped to the surrounding function, not the surrounding block. In a function that never returns, i.e. one containing an infinite loop, defers will never execute. Available since 2017.1
Default: `true` |
+| `SA5004` | 'for { select { ...' with an empty default branch spins Available since 2017.1
Default: `true` |
+| `SA5005` | The finalizer references the finalized object, preventing garbage collection A finalizer is a function associated with an object that runs when the garbage collector is ready to collect said object, that is when the object is no longer referenced by anything. If the finalizer references the object, however, it will always remain as the final reference to that object, preventing the garbage collector from collecting the object. The finalizer will never run, and the object will never be collected, leading to a memory leak. That is why the finalizer should instead use its first argument to operate on the object. That way, the number of references can temporarily go to zero before the object is being passed to the finalizer. Available since 2017.1
Default: `false` |
+| `SA5007` | Infinite recursive call A function that calls itself recursively needs to have an exit condition. Otherwise it will recurse forever, until the system runs out of memory. This issue can be caused by simple bugs such as forgetting to add an exit condition. It can also happen "on purpose". Some languages have tail call optimization which makes certain infinite recursive calls safe to use. Go, however, does not implement TCO, and as such a loop should be used instead. Available since 2017.1
Default: `false` |
+| `SA5008` | Invalid struct tag Available since 2019.2
Default: `true` |
+| `SA5010` | Impossible type assertion Some type assertions can be statically proven to be impossible. This is the case when the method sets of both arguments of the type assertion conflict with each other, for example by containing the same method with different signatures. The Go compiler already applies this check when asserting from an interface value to a concrete type. If the concrete type misses methods from the interface, or if function signatures don't match, then the type assertion can never succeed. This check applies the same logic when asserting from one interface to another. If both interface types contain the same method but with different signatures, then the type assertion can never succeed, either. Available since 2020.1
Default: `false` |
+| `SA5011` | Possible nil pointer dereference A pointer is being dereferenced unconditionally, while also being checked against nil in another place. This suggests that the pointer may be nil and dereferencing it may panic. This is commonly a result of improperly ordered code or missing return statements. Consider the following examples: func fn(x *int) { fmt.Println(*x) // This nil check is equally important for the previous dereference if x != nil { foo(*x) } } func TestFoo(t *testing.T) { x := compute() if x == nil { t.Errorf("nil pointer received") } // t.Errorf does not abort the test, so if x is nil, the next line will panic. foo(*x) } Staticcheck tries to deduce which functions abort control flow. For example, it is aware that a function will not continue execution after a call to panic or log.Fatal. However, sometimes this detection fails, in particular in the presence of conditionals. Consider the following example: func Log(msg string, level int) { fmt.Println(msg) if level == levelFatal { os.Exit(1) } } func Fatal(msg string) { Log(msg, levelFatal) } func fn(x *int) { if x == nil { Fatal("unexpected nil pointer") } fmt.Println(*x) } Staticcheck will flag the dereference of x, even though it is perfectly safe. Staticcheck is not able to deduce that a call to Fatal will exit the program. For the time being, the easiest workaround is to modify the definition of Fatal like so: func Fatal(msg string) { Log(msg, levelFatal) panic("unreachable") } We also hard-code functions from common logging packages such as logrus. Please file an issue if we're missing support for a popular package. Available since 2020.1
Default: `false` |
+| `SA5012` | Passing odd-sized slice to function expecting even size Some functions that take slices as parameters expect the slices to have an even number of elements. Often, these functions treat elements in a slice as pairs. For example, strings.NewReplacer takes pairs of old and new strings, and calling it with an odd number of elements would be an error. Available since 2020.2
Default: `false` |
+| `SA6000` | Using regexp.Match or related in a loop, should use regexp.Compile Available since 2017.1
Default: `false` |
+| `SA6001` | Missing an optimization opportunity when indexing maps by byte slices Map keys must be comparable, which precludes the use of byte slices. This usually leads to using string keys and converting byte slices to strings. Normally, a conversion of a byte slice to a string needs to copy the data and causes allocations. The compiler, however, recognizes m[string(b)] and uses the data of b directly, without copying it, because it knows that the data can't change during the map lookup. This leads to the counter-intuitive situation that k := string(b) println(m[k]) println(m[k]) will be less efficient than println(m[string(b)]) println(m[string(b)]) because the first version needs to copy and allocate, while the second one does not. For some history on this optimization, check out commit f5f5a8b6209f84961687d993b93ea0d397f5d5bf in the Go repository. Available since 2017.1
Default: `false` |
+| `SA6002` | Storing non-pointer values in sync.Pool allocates memory A sync.Pool is used to avoid unnecessary allocations and reduce the amount of work the garbage collector has to do. When passing a value that is not a pointer to a function that accepts an interface, the value needs to be placed on the heap, which means an additional allocation. Slices are a common thing to put in sync.Pools, and they're structs with 3 fields (length, capacity, and a pointer to an array). In order to avoid the extra allocation, one should store a pointer to the slice instead. See the comments on https://go-review.googlesource.com/c/go/+/24371 that discuss this problem. Available since 2017.1
Default: `false` |
+| `SA6003` | Converting a string to a slice of runes before ranging over it You may want to loop over the runes in a string. Instead of converting the string to a slice of runes and looping over that, you can loop over the string itself. That is, for _, r := range s {} and for _, r := range []rune(s) {} will yield the same values. The first version, however, will be faster and avoid unnecessary memory allocations. Do note that if you are interested in the indices, ranging over a string and over a slice of runes will yield different indices. The first one yields byte offsets, while the second one yields indices in the slice of runes. Available since 2017.1
Default: `false` |
+| `SA6005` | Inefficient string comparison with strings.ToLower or strings.ToUpper Converting two strings to the same case and comparing them like so if strings.ToLower(s1) == strings.ToLower(s2) { ... } is significantly more expensive than comparing them with strings.EqualFold(s1, s2). This is due to memory usage as well as computational complexity. strings.ToLower will have to allocate memory for the new strings, as well as convert both strings fully, even if they differ on the very first byte. strings.EqualFold, on the other hand, compares the strings one character at a time. It doesn't need to create two intermediate strings and can return as soon as the first non-matching character has been found. For a more in-depth explanation of this issue, see https://blog.digitalocean.com/how-to-efficiently-compare-strings-in-go/ Available since 2019.2
Default: `true` |
+| `SA6006` | Using io.WriteString to write []byte Using io.WriteString to write a slice of bytes, as in io.WriteString(w, string(b)) is both unnecessary and inefficient. Converting from []byte to string has to allocate and copy the data, and we could simply use w.Write(b) instead. Available since 2024.1
Default: `true` |
+| `SA9001` | Defers in range loops may not run when you expect them to Available since 2017.1
Default: `false` |
+| `SA9002` | Using a non-octal os.FileMode that looks like it was meant to be in octal. Available since 2017.1
Default: `true` |
+| `SA9003` | Empty body in an if or else branch Available since 2017.1, non-default
Default: `false` |
+| `SA9004` | Only the first constant has an explicit type In a constant declaration such as the following: const ( First byte = 1 Second = 2 ) the constant Second does not have the same type as the constant First. This construct shouldn't be confused with const ( First byte = iota Second ) where First and Second do indeed have the same type. The type is only passed on when no explicit value is assigned to the constant. When declaring enumerations with explicit values it is therefore important not to write const ( EnumFirst EnumType = 1 EnumSecond = 2 EnumThird = 3 ) This discrepancy in types can cause various confusing behaviors and bugs.
Wrong type in variable declarations The most obvious issue with such incorrect enumerations expresses itself as a compile error: package pkg const ( EnumFirst uint8 = 1 EnumSecond = 2 ) func fn(useFirst bool) { x := EnumSecond if useFirst { x = EnumFirst } } fails to compile with ./const.go:11:5: cannot use EnumFirst (type uint8) as type int in assignment
Losing method sets A more subtle issue occurs with types that have methods and optional interfaces. Consider the following: package main import "fmt" type Enum int func (e Enum) String() string { return "an enum" } const ( EnumFirst Enum = 1 EnumSecond = 2 ) func main() { fmt.Println(EnumFirst) fmt.Println(EnumSecond) } This code will output an enum 2 as EnumSecond has no explicit type, and thus defaults to int. Available since 2019.1
Default: `true` |
+| `SA9005` | Trying to marshal a struct with no public fields nor custom marshaling The encoding/json and encoding/xml packages only operate on exported fields in structs, not unexported ones. It is usually an error to try to (un)marshal structs that only consist of unexported fields. This check will not flag calls involving types that define custom marshaling behavior, e.g. via MarshalJSON methods. It will also not flag empty structs. Available since 2019.2
Default: `false` |
+| `SA9006` | Dubious bit shifting of a fixed size integer value Bit shifting a value past its size will always clear the value. For instance: v := int8(42) v >>= 8 will always result in 0. This check flags bit shifting operations on fixed size integer values only. That is, int, uint and uintptr are never flagged to avoid potential false positives in somewhat exotic but valid bit twiddling tricks: // Clear any value above 32 bits if integers are more than 32 bits. func f(i int) int { v := i >> 32 v = v << 32 return i-v } Available since 2020.2
Default: `true` |
+| `SA9007` | Deleting a directory that shouldn't be deleted It is virtually never correct to delete system directories such as /tmp or the user's home directory. However, it can be fairly easy to do by mistake, for example by mistakenly using os.TempDir instead of ioutil.TempDir, or by forgetting to add a suffix to the result of os.UserHomeDir. Writing d := os.TempDir() defer os.RemoveAll(d) in your unit tests will have a devastating effect on the stability of your system. This check flags attempts at deleting the following directories: - os.TempDir - os.UserCacheDir - os.UserConfigDir - os.UserHomeDir Available since 2022.1
Default: `false` |
+| `SA9008` | else branch of a type assertion is probably not reading the right value When declaring variables as part of an if statement (like in 'if foo := ...; foo {'), the same variables will also be in the scope of the else branch. This means that in the following example if x, ok := x.(int); ok { // ... } else { fmt.Printf("unexpected type %T", x) } x in the else branch will refer to the x from x, ok :=; it will not refer to the x that is being type-asserted. The result of a failed type assertion is the zero value of the type that is being asserted to, so x in the else branch will always have the value 0 and the type int. Available since 2022.1
Default: `false` |
+| `SA9009` | Ineffectual Go compiler directive A potential Go compiler directive was found, but is ineffectual as it begins with whitespace. Available since 2024.1
Default: `true` |
+| `ST1000` | Incorrect or missing package comment Packages must have a package comment that is formatted according to the guidelines laid out in https://go.dev/wiki/CodeReviewComments#package-comments. Available since 2019.1, non-default
Default: `false` |
+| `ST1001` | Dot imports are discouraged Dot imports that aren't in external test packages are discouraged. The dot_import_whitelist option can be used to whitelist certain imports. Quoting Go Code Review Comments: > The import . form can be useful in tests that, due to circular > dependencies, cannot be made part of the package being tested: > > package foo_test > > import ( > "bar/testutil" // also imports "foo" > . "foo" > ) > > In this case, the test file cannot be in package foo because it > uses bar/testutil, which imports foo. So we use the import . > form to let the file pretend to be part of package foo even though > it is not. Except for this one case, do not use import . in your > programs. It makes the programs much harder to read because it is > unclear whether a name like Quux is a top-level identifier in the > current package or in an imported package. Available since 2019.1 Options dot_import_whitelist
Default: `false` |
+| `ST1003` | Poorly chosen identifier Identifiers, such as variable and package names, follow certain rules. See the following links for details: - https://go.dev/doc/effective_go#package-names - https://go.dev/doc/effective_go#mixed-caps - https://go.dev/wiki/CodeReviewComments#initialisms - https://go.dev/wiki/CodeReviewComments#variable-names Available since 2019.1, non-default Options initialisms
Default: `false` |
+| `ST1005` | Incorrectly formatted error string Error strings follow a set of guidelines to ensure uniformity and good composability. Quoting Go Code Review Comments: > Error strings should not be capitalized (unless beginning with > proper nouns or acronyms) or end with punctuation, since they are > usually printed following other context. That is, use > fmt.Errorf("something bad") not fmt.Errorf("Something bad"), so > that log.Printf("Reading %s: %v", filename, err) formats without a > spurious capital letter mid-message. Available since 2019.1
Default: `false` |
+| `ST1006` | Poorly chosen receiver name Quoting Go Code Review Comments: > The name of a method's receiver should be a reflection of its > identity; often a one or two letter abbreviation of its type > suffices (such as "c" or "cl" for "Client"). Don't use generic > names such as "me", "this" or "self", identifiers typical of > object-oriented languages that place more emphasis on methods as > opposed to functions. The name need not be as descriptive as that > of a method argument, as its role is obvious and serves no > documentary purpose. It can be very short as it will appear on > almost every line of every method of the type; familiarity admits > brevity. Be consistent, too: if you call the receiver "c" in one > method, don't call it "cl" in another. Available since 2019.1
Default: `false` |
+| `ST1008` | A function's error value should be its last return value A function's error value should be its last return value. Available since 2019.1
Default: `false` |
+| `ST1011` | Poorly chosen name for variable of type time.Duration time.Duration values represent an amount of time, which is represented as a count of nanoseconds. An expression like 5 * time.Microsecond yields the value 5000. It is therefore not appropriate to suffix a variable of type time.Duration with any time unit, such as Msec or Milli. Available since 2019.1
Default: `false` |
+| `ST1012` | Poorly chosen name for error variable Error variables that are part of an API should be called errFoo or ErrFoo. Available since 2019.1
Default: `false` |
+| `ST1013` | Should use constants for HTTP error codes, not magic numbers HTTP has a tremendous number of status codes. While some of those are well known (200, 400, 404, 500), most of them are not. The net/http package provides constants for all status codes that are part of the various specifications. It is recommended to use these constants instead of hard-coding magic numbers, to vastly improve the readability of your code. Available since 2019.1 Options http_status_code_whitelist
Default: `false` |
+| `ST1015` | A switch's default case should be the first or last case Available since 2019.1
Default: `false` |
+| `ST1016` | Use consistent method receiver names Available since 2019.1, non-default
Default: `false` |
+| `ST1017` | Don't use Yoda conditions Yoda conditions are conditions of the kind 'if 42 == x', where the literal is on the left side of the comparison. These are a common idiom in languages in which assignment is an expression, to avoid bugs of the kind 'if (x = 42)'. In Go, which doesn't allow for this kind of bug, we prefer the more idiomatic 'if x == 42'. Available since 2019.2
Default: `false` |
+| `ST1018` | Avoid zero-width and control characters in string literals Available since 2019.2
Default: `false` |
+| `ST1019` | Importing the same package multiple times Go allows importing the same package multiple times, as long as different import aliases are being used. That is, the following bit of code is valid: import ( "fmt" fumpt "fmt" format "fmt" _ "fmt" ) However, this is very rarely done on purpose. Usually, it is a sign of code that got refactored, accidentally adding duplicate import statements. It is also a rarely known feature, which may contribute to confusion. Do note that sometimes, this feature may be used intentionally (see for example https://github.com/golang/go/commit/3409ce39bfd7584523b7a8c150a310cea92d879d) – if you want to allow this pattern in your code base, you're advised to disable this check. Available since 2020.1
Default: `false` |
+| `ST1020` | The documentation of an exported function should start with the function's name Doc comments work best as complete sentences, which allow a wide variety of automated presentations. The first sentence should be a one-sentence summary that starts with the name being declared. If every doc comment begins with the name of the item it describes, you can use the doc subcommand of the go tool and run the output through grep. See https://go.dev/doc/effective_go#commentary for more information on how to write good documentation. Available since 2020.1, non-default
Default: `false` |
+| `ST1021` | The documentation of an exported type should start with type's name Doc comments work best as complete sentences, which allow a wide variety of automated presentations. The first sentence should be a one-sentence summary that starts with the name being declared. If every doc comment begins with the name of the item it describes, you can use the doc subcommand of the go tool and run the output through grep. See https://go.dev/doc/effective_go#commentary for more information on how to write good documentation. Available since 2020.1, non-default
Default: `false` |
+| `ST1022` | The documentation of an exported variable or constant should start with variable's name Doc comments work best as complete sentences, which allow a wide variety of automated presentations. The first sentence should be a one-sentence summary that starts with the name being declared. If every doc comment begins with the name of the item it describes, you can use the doc subcommand of the go tool and run the output through grep. See https://go.dev/doc/effective_go#commentary for more information on how to write good documentation. Available since 2020.1, non-default
Default: `false` |
+| `ST1023` | Redundant type in variable declaration Available since 2021.1, non-default
Default: `false` |
| `appends` | check for missing values after append This checker reports calls to append that pass no values to be appended to the slice.
s := []string{"a", "b", "c"} _ = append(s)
Such calls are always no-ops and often indicate an underlying mistake. Default: `true` |
| `asmdecl` | report mismatches between assembly files and Go declarations Default: `true` |
| `assign` | check for useless assignments This checker reports assignments of the form x = x or a[i] = a[i]. These are almost always useless, and even when they aren't they are usually a mistake. Default: `true` |
@@ -762,19 +917,21 @@ Example Usage:
| `errorsas` | report passing non-pointer or non-error values to errors.As The errorsas analysis reports calls to errors.As where the type of the second argument is not a pointer to a type implementing error. Default: `true` |
| `fillreturns` | suggest fixes for errors due to an incorrect number of return values This checker provides suggested fixes for type errors of the type "wrong number of return values (want %d, got %d)". For example:
This functionality is similar to https://github.com/sqs/goreturns. Default: `true` |
| `framepointer` | report assembly that clobbers the frame pointer before saving it Default: `true` |
-| `gofix` | apply fixes based on go:fix comment directives The gofix analyzer inlines functions and constants that are marked for inlining. Default: `true` |
+| `gofix` | apply fixes based on go:fix comment directives The gofix analyzer inlines functions and constants that are marked for inlining. ## Functions Given a function that is marked for inlining, like this one:
this analyzer will recommend that calls to the function elsewhere, in the same or other packages, should be inlined. Inlining can be used to move off of a deprecated function:
It can also be used to move off of an obsolete package, as when the import path has changed or a higher major version is available:
package pkg
import pkg2 "pkg/v2"
//go:fix inline func F() { pkg2.F(nil) }
Replacing a call pkg.F() by pkg2.F(nil) can have no effect on the program, so this mechanism provides a low-risk way to update large numbers of calls. We recommend, where possible, expressing the old API in terms of the new one to enable automatic migration. The inliner takes care to avoid behavior changes, even subtle ones, such as changes to the order in which argument expressions are evaluated. When it cannot safely eliminate all parameter variables, it may introduce a "binding declaration" of the form
var params = args
to evaluate argument expressions in the correct order and bind them to parameter variables. Since the resulting code transformation may be stylistically suboptimal, such inlinings may be disabled by specifying the -gofix.allow_binding_decl=false flag to the analyzer driver. (In cases where it is not safe to "reduce" a call—that is, to replace a call f(x) by the body of function f, suitably substituted—the inliner machinery is capable of replacing f by a function literal, func(){...}(). However, the gofix analyzer discards all such "literalizations" unconditionally, again on grounds of style.) ## Constants Given a constant that is marked for inlining, like this one:
//go:fix inline const Ptr = Pointer
this analyzer will recommend that uses of Ptr should be replaced with Pointer. As with functions, inlining can be used to replace deprecated constants and constants in obsolete packages. A constant definition can be marked for inlining only if it refers to another named constant. The "//go:fix inline" comment must appear before a single const declaration on its own, as above; before a const declaration that is part of a group, as in this case:
const ( C = 1 //go:fix inline Ptr = Pointer )
or before a group, applying to every constant in the group:
//go:fix inline const ( Ptr = Pointer Val = Value )
The proposal https://go.dev/issue/32816 introduces the "//go:fix" directives. You can use this (officially unsupported) command to apply gofix fixes en masse:
$ go run golang.org/x/tools/internal/gofix/cmd/gofix@latest -test ./...
(Do not use "go get -tool" to add gopls as a dependency of your module; gopls commands must be built from their release branch.) Default: `true` |
| `hostport` | check format of addresses passed to net.Dial This analyzer flags code that produce network address strings using fmt.Sprintf, as in this example: addr := fmt.Sprintf("%s:%d", host, 12345) // "will not work with IPv6" ... conn, err := net.Dial("tcp", addr) // "when passed to dial here" The analyzer suggests a fix to use the correct approach, a call to net.JoinHostPort: addr := net.JoinHostPort(host, "12345") ... conn, err := net.Dial("tcp", addr) A similar diagnostic and fix are produced for a format string of "%s:%s".
Default: `true` |
| `httpresponse` | check for mistakes using HTTP responses A common mistake when using the net/http package is to defer a function call to close the http.Response Body before checking the error that determines whether the response is valid:
This checker helps uncover latent nil dereference bugs by reporting a diagnostic for such mistakes. Default: `true` |
| `ifaceassert` | detect impossible interface-to-interface type assertions This checker flags type assertions v.(T) and corresponding type-switch cases in which the static type V of v is an interface that cannot possibly implement the target interface T. This occurs when V and T contain methods with the same name but different signatures. Example:
var v interface { Read() } _ = v.(io.Reader)
The Read method in v has a different signature than the Read method in io.Reader, so this assertion cannot succeed. Default: `true` |
| `infertypeargs` | check for unnecessary type arguments in call expressions Explicit type arguments may be omitted from call expressions if they can be inferred from function arguments, or from other type arguments:
func f[T any](T) {}
func _() { f[string]("foo") // string could be inferred }
Default: `true` |
| `loopclosure` | check references to loop variables from within nested functions This analyzer reports places where a function literal references the iteration variable of an enclosing loop, and the loop calls the function in such a way (e.g. with go or defer) that it may outlive the loop iteration and possibly observe the wrong value of the variable. Note: An iteration variable can only outlive a loop iteration in Go versions <=1.21. In Go 1.22 and later, the loop variable lifetimes changed to create a new iteration variable per loop iteration. (See go.dev/issue/60078.) In this example, all the deferred functions run after the loop has completed, so all observe the final value of v [
for _, v := range list { defer func() { use(v) // incorrect }() }
One fix is to create a new variable for each iteration of the loop:
for _, v := range list { v := v // new var per iteration defer func() { use(v) // ok }() }
After Go version 1.22, the previous two for loops are equivalent and both are correct. The next example uses a go statement and has a similar problem [
for _, v := range elem { go func() { use(v) // incorrect, and a data race }() }
A fix is the same as before. The checker also reports problems in goroutines started by golang.org/x/sync/errgroup.Group. A hard-to-spot variant of this form is common in parallel tests:
func Test(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { t.Parallel() use(test) // incorrect, and a data race }) } }
The t.Parallel() call causes the rest of the function to execute concurrent with the loop [ The analyzer reports references only in the last statement, as it is not deep enough to understand the effects of subsequent statements that might render the reference benign. ("Last statement" is defined recursively in compound statements such as if, switch, and select.) See: https://golang.org/doc/go_faq.html#closures_and_goroutines Default: `true` |
| `lostcancel` | check cancel func returned by context.WithCancel is called The cancellation function returned by context.WithCancel, WithTimeout, WithDeadline and variants such as WithCancelCause must be called, or the new context will remain live until its parent context is cancelled. (The background context is never cancelled.) Default: `true` |
-| `modernize` | simplify code by using modern constructs This analyzer reports opportunities for simplifying and clarifying existing code by using more modern features of Go, such as: - replacing an if/else conditional assignment by a call to the built-in min or max functions added in go1.21; - replacing sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21; - replacing interface{} by the 'any' type added in go1.18; - replacing append([]T(nil), s...) by slices.Clone(s) or slices.Concat(s), added in go1.21; - replacing a loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21; - replacing []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19; - replacing uses of context.WithCancel in tests with t.Context, added in go1.24; - replacing omitempty by omitzero on structs, added in go1.24; - replacing append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1), added in go1.21 - replacing a 3-clause for i := 0; i < n; i++ {} loop by for i := range n {}, added in go1.22; - replacing Split in "for range strings.Split(...)" by go1.24's more efficient SplitSeq; To apply all modernization fixes en masse, you can use the following command:
$ go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -test ./...
If the tool warns of conflicting fixes, you may need to run it more than once until it has applied all fixes cleanly. This command is not an officially supported interface and may change in the future. Default: `true` |
+| `maprange` | checks for unnecessary calls to maps.Keys and maps.Values in range statements Consider a loop written like this:
for val := range maps.Values(m) { fmt.Println(val) }
This should instead be written without the call to maps.Values:
for _, val := range m { fmt.Println(val) }
golang.org/x/exp/maps returns slices for Keys/Values instead of iterators, but unnecessary calls should similarly be removed:
for _, key := range maps.Keys(m) { fmt.Println(key) }
should be rewritten as:
for key := range m { fmt.Println(key) }
Default: `true` |
+| `modernize` | simplify code by using modern constructs This analyzer reports opportunities for simplifying and clarifying existing code by using more modern features of Go and its standard library. Each diagnostic provides a fix. Our intent is that these fixes may be safely applied en masse without changing the behavior of your program. In some cases the suggested fixes are imperfect and may lead to (for example) unused imports or unused local variables, causing build breakage. However, these problems are generally trivial to fix. We regard any modernizer whose fix changes program behavior to have a serious bug and will endeavor to fix it. To apply all modernization fixes en masse, you can use the following command:
$ go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
(Do not use "go get -tool" to add gopls as a dependency of your module; gopls commands must be built from their release branch.) If the tool warns of conflicting fixes, you may need to run it more than once until it has applied all fixes cleanly. This command is not an officially supported interface and may change in the future. Changes produced by this tool should be reviewed as usual before being merged. In some cases, a loop may be replaced by a simple function call, causing comments within the loop to be discarded. Human judgment may be required to avoid losing comments of value. Each diagnostic reported by modernize has a specific category. (The categories are listed below.) Diagnostics in some categories, such as "efaceany" (which replaces "interface{}" with "any" where it is safe to do so) are particularly numerous. It may ease the burden of code review to apply fixes in two passes, the first change consisting only of fixes of category "efaceany", the second consisting of all others. This can be achieved using the -category flag:
Categories of modernize diagnostic: - forvar: remove x := x variable declarations made unnecessary by the new semantics of loops in go1.22. - slicescontains: replace 'for i, elem := range s { if elem == needle { ...; break }' by a call to slices.Contains, added in go1.21. - minmax: replace an if/else conditional assignment by a call to the built-in min or max functions added in go1.21. - sortslice: replace sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] } by a call to slices.Sort(s), added in go1.21. - efaceany: replace interface{} by the 'any' type added in go1.18. - mapsloop: replace a loop around an m[k]=v map update by a call to one of the Collect, Copy, Clone, or Insert functions from the maps package, added in go1.21. - fmtappendf: replace []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...), added in go1.19. - testingcontext: replace uses of context.WithCancel in tests with t.Context, added in go1.24. - omitzero: replace omitempty by omitzero on structs, added in go1.24. - bloop: replace "for i := range b.N" or "for range b.N" in a benchmark with "for b.Loop()", and remove any preceding calls to b.StopTimer, b.StartTimer, and b.ResetTimer. B.Loop intentionally defeats compiler optimizations such as inlining so that the benchmark is not entirely optimized away. Currently, however, it may cause benchmarks to become slower in some cases due to increased allocation; see https://go.dev/issue/73137. - rangeint: replace a 3-clause "for i := 0; i < n; i++" loop by "for i := range n", added in go1.22. - stringsseq: replace Split in "for range strings.Split(...)" by go1.24's more efficient SplitSeq, or Fields with FieldSeq. - stringscutprefix: replace some uses of HasPrefix followed by TrimPrefix with CutPrefix, added to the strings package in go1.20. - waitgroup: replace old complex usages of sync.WaitGroup by less complex WaitGroup.Go method in go1.25. Default: `true` |
| `nilfunc` | check for useless comparisons between functions and nil A useless comparison is one like f == nil as opposed to f() == nil. Default: `true` |
| `nilness` | check for redundant or impossible nil comparisons The nilness checker inspects the control-flow graph of each function in a package and reports nil pointer dereferences, degenerate nil pointers, and panics with nil values. A degenerate comparison is of the form x==nil or x!=nil where x is statically known to be nil or non-nil. These are often a mistake, especially in control flow related to errors. Panics with nil values are checked because they are not detectable by
if r := recover(); r != nil {
This check reports conditions such as:
if f == nil { // impossible condition (f is a function) }
and:
p := &v ... if p != nil { // tautological condition }
and:
if p == nil { print(*p) // nil dereference }
and:
if p == nil { panic(p) }
Sometimes the control flow may be quite complex, making bugs hard to spot. In the example below, the err.Error expression is guaranteed to panic because, after the first return, err must be nil. The intervening loop is just a distraction.
... err := g.Wait() if err != nil { return err } partialSuccess := false for _, err := range errs { if err == nil { partialSuccess = true break } } if partialSuccess { reportStatus(StatusMessage{ Code: code.ERROR, Detail: err.Error(), // "nil dereference in dynamic method call" }) return nil }
... Default: `true` |
| `nonewvars` | suggested fixes for "no new vars on left side of :=" This checker provides suggested fixes for type errors of the type "no new vars on left side of :=". For example:
z := 1 z := 2
will turn into
z := 1 z = 2
Default: `true` |
| `noresultvalues` | suggested fixes for unexpected return values This checker provides suggested fixes for type errors of the type "no result values expected" or "too many return values". For example:
func z() { return nil }
will turn into
func z() { return }
Default: `true` |
| `printf` | check consistency of Printf format strings and arguments The check applies to calls of the formatting functions such as [fmt.Printf] and [fmt.Sprintf], as well as any detected wrappers of those functions such as [log.Printf]. It reports a variety of mistakes such as syntax errors in the format string and mismatches (of number and type) between the verbs and their arguments. See the documentation of the fmt package for the complete set of format operators and their operand types. Default: `true` |
+| `recursiveiter` | check for inefficient recursive iterators This analyzer reports when a function that returns an iterator (iter.Seq or iter.Seq2) calls itself as the operand of a range statement, as this is inefficient. When implementing an iterator (e.g. iter.Seq[T]) for a recursive data type such as a tree or linked list, it is tempting to recursively range over the iterator for each child element. Here's an example of a naive iterator over a binary tree:
type tree struct { value int left, right *tree }
func (t *tree) All() iter.Seq[int] { return func(yield func(int) bool) { if t != nil { for elem := range t.left.All() { // "inefficient recursive iterator" if !yield(elem) { return } } if !yield(t.value) { return } for elem := range t.right.All() { // "inefficient recursive iterator" if !yield(elem) { return } } } } }
Though it correctly enumerates the elements of the tree, it hides a significant performance problem--two, in fact. Consider a balanced tree of N nodes. Iterating the root node will cause All to be called once on every node of the tree. This results in a chain of nested active range-over-func statements when yield(t.value) is called on a leaf node. The first performance problem is that each range-over-func statement must typically heap-allocate a variable, so iteration of the tree allocates as many variables as there are elements in the tree, for a total of O(N) allocations, all unnecessary. The second problem is that each call to yield for a leaf of the tree causes each of the enclosing range loops to receive a value, which they then immediately pass on to their respective yield function. This results in a chain of log(N) dynamic yield calls per element, a total of O(N*log N) dynamic calls overall, when only O(N) are necessary. A better implementation strategy for recursive iterators is to first define the "every" operator for your recursive data type, where every(f) reports whether f(x) is true for every element x in the data type. For our tree, the every function would be:
In effect, tree.All computes whether yield returns true for each element, short-circuiting if it every returns false, then discards the final boolean result. This has much better performance characteristics: it makes one dynamic call per element of the tree, and it doesn't heap-allocate anything. It is also clearer. Default: `true` |
| `shadow` | check for possible unintended shadowing of variables This analyzer check for shadowed variables. A shadowed variable is a variable declared in an inner scope with the same name and type as a variable in an outer scope, and where the outer variable is mentioned after the inner one is declared. (This definition can be refined; the module generates too many false positives and is not yet enabled by default.) For example:
func BadRead(f *os.File, buf []byte) error { var err error for { n, err := f.Read(buf) // shadows the function variable 'err' if err != nil { break // causes return of wrong value } foo(buf) } return err }
Default: `false` |
| `shift` | check for shifts that equal or exceed the width of the integer Default: `true` |
| `sigchanyzer` | check for unbuffered channel of os.Signal This checker reports call expression of the form
signal.Notify(c <-chan os.Signal, sig ...os.Signal),
where c is an unbuffered channel, which can be at risk of missing the signal. Default: `true` |
@@ -814,6 +971,26 @@ filesystem, so subsequent analysis should be faster.
Default: `true`
+### `ui.diagnostic.annotations`
+
+annotations specifies the various kinds of compiler
+optimization details that should be reported as diagnostics
+when enabled for a package by the "Toggle compiler
+optimization details" (`gopls.gc_details`) command.
+
+(Some users care only about one kind of annotation in their
+profiling efforts. More importantly, in large packages, the
+number of annotations can sometimes overwhelm the user
+interface and exceed the per-file diagnostic limit.)
+
+TODO(adonovan): rename this field to CompilerOptDetail.
+
+| Properties | Description |
+| --- | --- |
+| `bounds` | `"bounds"` controls bounds checking diagnostics.
Default: `true` |
### `ui.diagnostic.diagnosticsDelay`
(Advanced) diagnosticsDelay controls the amount of time that gopls waits
@@ -839,10 +1016,25 @@ or configuration change will still trigger diagnostics.
Default: `"Edit"`
### `ui.diagnostic.staticcheck`
-(Experimental) staticcheck enables additional analyses from staticcheck.io.
+(Experimental) staticcheck configures the default set of analyses staticcheck.io.
These analyses are documented on
[Staticcheck's website](https://staticcheck.io/docs/checks/).
+The "staticcheck" option has three values:
+- false: disable all staticcheck analyzers
+- true: enable all staticcheck analyzers
+- unset: enable a subset of staticcheck analyzers
+ selected by gopls maintainers for runtime efficiency
+ and analytic precision.
+
+Regardless of this setting, individual analyzers can be
+selectively enabled or disabled using the `analyses` setting.
+
+
+Default: `false`
+### `ui.diagnostic.staticcheckProvided`
+
+(Experimental)
Default: `false`
### `ui.documentation.hoverKind`
diff --git a/docs/tools.md b/docs/tools.md
index 10ff1edc85..fc09e84679 100644
--- a/docs/tools.md
+++ b/docs/tools.md
@@ -48,7 +48,9 @@ This tool provides support for the [`Go: Run on Go Playground`](features.md#go-p
### [`gomodifytags`](https://pkg.go.dev/github.com/fatih/gomodifytags?tab=overview)
-This tool provides support for the [`Go: Add Tags to Struct Fields`](features.md#add-or-remove-struct-tags) and [`Go: Remove Tags From Struct Fields`](features.md#add-or-remove-struct-tags) commands.
+This tool provides support for the [`Go: Add Tags to Struct Fields`](features.md#add-or-remove-struct-tags) and [`Go: Remove Tags From Struct Fields`](features.md#add-or-remove-struct-tags) commands when using older versions of gopls. The latest
+version of gopls has a gopls.modify_tags command which directly invokes the
+gomodifytags library.
### [`impl`](https://github.com/josharian/impl)
diff --git a/extension/package-lock.json b/extension/package-lock.json
index fd2cbee086..2d885cc49f 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "go",
- "version": "0.46.0-dev",
+ "version": "0.48.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "go",
- "version": "0.46.0-dev",
+ "version": "0.48.0",
"license": "MIT",
"dependencies": {
"diff": "4.0.2",
@@ -31,9 +31,9 @@
"@types/node-fetch": "2.6.9",
"@types/semver": "7.3.4",
"@types/sinon": "9.0.11",
- "@types/vscode": "1.75.0",
- "@vscode/debugadapter-testsupport": "1.58.0",
- "@vscode/test-electron": "2.3.8",
+ "@types/vscode": "1.90.0",
+ "@vscode/debugadapter-testsupport": "1.68.0",
+ "@vscode/test-electron": "2.5.2",
"@vscode/vsce": "2.23.0",
"adm-zip": "0.4.16",
"esbuild": "0.17.10",
@@ -638,15 +638,6 @@
"node": ">=10"
}
},
- "node_modules/@tootallnate/once": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
- "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/@types/adm-zip": {
"version": "0.4.33",
"resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.4.33.tgz",
@@ -779,10 +770,11 @@
"dev": true
},
"node_modules/@types/vscode": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.75.0.tgz",
- "integrity": "sha512-SAr0PoOhJS6FUq5LjNr8C/StBKALZwDVm3+U4pjF/3iYkt3GioJOPV/oB1Sf1l7lROe4TgrMyL5N1yaEgTWycw==",
- "dev": true
+ "version": "1.90.0",
+ "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.90.0.tgz",
+ "integrity": "sha512-oT+ZJL7qHS9Z8bs0+WKf/kQ27qWYR3trsXpq46YDjFqBsMLG4ygGGjPaJ2tyrH0wJzjOEmDyg9PDJBBhWg9pkQ==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.30.5",
@@ -1070,38 +1062,79 @@
"dev": true
},
"node_modules/@vscode/debugadapter-testsupport": {
- "version": "1.58.0",
- "resolved": "https://registry.npmjs.org/@vscode/debugadapter-testsupport/-/debugadapter-testsupport-1.58.0.tgz",
- "integrity": "sha512-a6Q4K6jTG0J5+yb7bRKiAPu3Ob+rnkRJRSagK5SHsZi64s4JhEpqf842IeTqqEjAmjt9/FXcpk1WViqEtx53qw==",
+ "version": "1.68.0",
+ "resolved": "https://registry.npmjs.org/@vscode/debugadapter-testsupport/-/debugadapter-testsupport-1.68.0.tgz",
+ "integrity": "sha512-UpbaPsCGMKyjIvJFtqFKDD1MVvME50xuOtRBPrqY1WdhAOLjWQN7FcKEoHv3X85twfNL21jW2M54FYwEdEQv4Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@vscode/debugprotocol": "1.58.0"
+ "@vscode/debugprotocol": "1.68.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@vscode/debugprotocol": {
- "version": "1.58.0",
- "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.58.0.tgz",
- "integrity": "sha512-64gY3PdU7jmYDwLRJFZ5XL2BC8TK5mdhZ60XLTZn17yfbJPKCcmFDuQAkVfOPsjn7o4f6YWFy3AXSR0V9gY6jA==",
- "dev": true
+ "version": "1.68.0",
+ "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.68.0.tgz",
+ "integrity": "sha512-2J27dysaXmvnfuhFGhfeuxfHRXunqNPxtBoR3koiTOA9rdxWNDTa1zIFLCFMSHJ9MPTPKFcBeblsyaCJCIlQxg==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@vscode/test-electron": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.8.tgz",
- "integrity": "sha512-b4aZZsBKtMGdDljAsOPObnAi7+VWIaYl3ylCz1jTs+oV6BZ4TNHcVNC3xUn0azPeszBmwSBDQYfFESIaUQnrOg==",
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz",
+ "integrity": "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "http-proxy-agent": "^4.0.1",
- "https-proxy-agent": "^5.0.0",
+ "http-proxy-agent": "^7.0.2",
+ "https-proxy-agent": "^7.0.5",
"jszip": "^3.10.1",
- "semver": "^7.5.2"
+ "ora": "^8.1.0",
+ "semver": "^7.6.2"
},
"engines": {
"node": ">=16"
}
},
+ "node_modules/@vscode/test-electron/node_modules/agent-base": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
+ "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/@vscode/test-electron/node_modules/https-proxy-agent": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/@vscode/test-electron/node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/@vscode/vsce": {
"version": "2.23.0",
"resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.23.0.tgz",
@@ -1742,6 +1775,19 @@
"node": ">=8"
}
},
+ "node_modules/cli-spinners": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+ "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/cli-width": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
@@ -1834,10 +1880,11 @@
"dev": true
},
"node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -2813,6 +2860,19 @@
"node": "6.* || 8.* || >= 10.*"
}
},
+ "node_modules/get-east-asian-width": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz",
+ "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
@@ -3117,19 +3177,54 @@
"integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg=="
},
"node_modules/http-proxy-agent": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
- "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@tootallnate/once": "1",
- "agent-base": "6",
- "debug": "4"
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
},
"engines": {
- "node": ">= 6"
+ "node": ">= 14"
+ }
+ },
+ "node_modules/http-proxy-agent/node_modules/agent-base": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
+ "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/http-proxy-agent/node_modules/debug": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
}
},
+ "node_modules/http-proxy-agent/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/http2-wrapper": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
@@ -3363,6 +3458,19 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-interactive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
+ "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -3833,6 +3941,19 @@
"node": ">=6"
}
},
+ "node_modules/mimic-function": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
+ "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
@@ -4288,6 +4409,202 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/ora": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz",
+ "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^5.3.0",
+ "cli-cursor": "^5.0.0",
+ "cli-spinners": "^2.9.2",
+ "is-interactive": "^2.0.0",
+ "is-unicode-supported": "^2.0.0",
+ "log-symbols": "^6.0.0",
+ "stdin-discarder": "^0.2.2",
+ "string-width": "^7.2.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/ansi-regex": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+ "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/ora/node_modules/chalk": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
+ "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/ora/node_modules/cli-cursor": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+ "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "restore-cursor": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/emoji-regex": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
+ "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/ora/node_modules/is-unicode-supported": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+ "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/log-symbols": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz",
+ "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^5.3.0",
+ "is-unicode-supported": "^1.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
+ "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/onetime": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+ "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mimic-function": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/restore-cursor": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+ "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "onetime": "^7.0.0",
+ "signal-exit": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/ora/node_modules/string-width": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
"node_modules/os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
@@ -5223,6 +5540,19 @@
"spdx-ranges": "^2.0.0"
}
},
+ "node_modules/stdin-discarder": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
+ "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -5304,10 +5634,11 @@
}
},
"node_modules/tar-fs": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
- "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz",
+ "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==",
"dev": true,
+ "license": "MIT",
"optional": true,
"dependencies": {
"chownr": "^1.1.1",
@@ -6269,12 +6600,6 @@
"defer-to-connect": "^2.0.0"
}
},
- "@tootallnate/once": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
- "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
- "dev": true
- },
"@types/adm-zip": {
"version": "0.4.33",
"resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.4.33.tgz",
@@ -6407,9 +6732,9 @@
"dev": true
},
"@types/vscode": {
- "version": "1.75.0",
- "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.75.0.tgz",
- "integrity": "sha512-SAr0PoOhJS6FUq5LjNr8C/StBKALZwDVm3+U4pjF/3iYkt3GioJOPV/oB1Sf1l7lROe4TgrMyL5N1yaEgTWycw==",
+ "version": "1.90.0",
+ "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.90.0.tgz",
+ "integrity": "sha512-oT+ZJL7qHS9Z8bs0+WKf/kQ27qWYR3trsXpq46YDjFqBsMLG4ygGGjPaJ2tyrH0wJzjOEmDyg9PDJBBhWg9pkQ==",
"dev": true
},
"@typescript-eslint/eslint-plugin": {
@@ -6575,30 +6900,55 @@
"dev": true
},
"@vscode/debugadapter-testsupport": {
- "version": "1.58.0",
- "resolved": "https://registry.npmjs.org/@vscode/debugadapter-testsupport/-/debugadapter-testsupport-1.58.0.tgz",
- "integrity": "sha512-a6Q4K6jTG0J5+yb7bRKiAPu3Ob+rnkRJRSagK5SHsZi64s4JhEpqf842IeTqqEjAmjt9/FXcpk1WViqEtx53qw==",
+ "version": "1.68.0",
+ "resolved": "https://registry.npmjs.org/@vscode/debugadapter-testsupport/-/debugadapter-testsupport-1.68.0.tgz",
+ "integrity": "sha512-UpbaPsCGMKyjIvJFtqFKDD1MVvME50xuOtRBPrqY1WdhAOLjWQN7FcKEoHv3X85twfNL21jW2M54FYwEdEQv4Q==",
"dev": true,
"requires": {
- "@vscode/debugprotocol": "1.58.0"
+ "@vscode/debugprotocol": "1.68.0"
}
},
"@vscode/debugprotocol": {
- "version": "1.58.0",
- "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.58.0.tgz",
- "integrity": "sha512-64gY3PdU7jmYDwLRJFZ5XL2BC8TK5mdhZ60XLTZn17yfbJPKCcmFDuQAkVfOPsjn7o4f6YWFy3AXSR0V9gY6jA==",
+ "version": "1.68.0",
+ "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.68.0.tgz",
+ "integrity": "sha512-2J27dysaXmvnfuhFGhfeuxfHRXunqNPxtBoR3koiTOA9rdxWNDTa1zIFLCFMSHJ9MPTPKFcBeblsyaCJCIlQxg==",
"dev": true
},
"@vscode/test-electron": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.8.tgz",
- "integrity": "sha512-b4aZZsBKtMGdDljAsOPObnAi7+VWIaYl3ylCz1jTs+oV6BZ4TNHcVNC3xUn0azPeszBmwSBDQYfFESIaUQnrOg==",
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz",
+ "integrity": "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==",
"dev": true,
"requires": {
- "http-proxy-agent": "^4.0.1",
- "https-proxy-agent": "^5.0.0",
+ "http-proxy-agent": "^7.0.2",
+ "https-proxy-agent": "^7.0.5",
"jszip": "^3.10.1",
- "semver": "^7.5.2"
+ "ora": "^8.1.0",
+ "semver": "^7.6.2"
+ },
+ "dependencies": {
+ "agent-base": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
+ "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
+ "dev": true
+ },
+ "https-proxy-agent": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+ "dev": true,
+ "requires": {
+ "agent-base": "^7.1.2",
+ "debug": "4"
+ }
+ },
+ "semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "dev": true
+ }
}
},
"@vscode/vsce": {
@@ -7070,6 +7420,12 @@
"restore-cursor": "^3.1.0"
}
},
+ "cli-spinners": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+ "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
+ "dev": true
+ },
"cli-width": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
@@ -7146,9 +7502,9 @@
"dev": true
},
"cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"requires": {
"path-key": "^3.1.0",
@@ -7871,6 +8227,12 @@
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
+ "get-east-asian-width": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz",
+ "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==",
+ "dev": true
+ },
"get-intrinsic": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
@@ -8082,14 +8444,36 @@
"integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg=="
},
"http-proxy-agent": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
- "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
"dev": true,
"requires": {
- "@tootallnate/once": "1",
- "agent-base": "6",
- "debug": "4"
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
+ },
+ "dependencies": {
+ "agent-base": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
+ "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
+ "dev": true
+ },
+ "debug": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.3"
+ }
+ },
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ }
}
},
"http2-wrapper": {
@@ -8262,6 +8646,12 @@
"is-extglob": "^2.1.1"
}
},
+ "is-interactive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
+ "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
+ "dev": true
+ },
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -8628,6 +9018,12 @@
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
},
+ "mimic-function": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
+ "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
+ "dev": true
+ },
"mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
@@ -8963,6 +9359,121 @@
"word-wrap": "^1.2.3"
}
},
+ "ora": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz",
+ "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==",
+ "dev": true,
+ "requires": {
+ "chalk": "^5.3.0",
+ "cli-cursor": "^5.0.0",
+ "cli-spinners": "^2.9.2",
+ "is-interactive": "^2.0.0",
+ "is-unicode-supported": "^2.0.0",
+ "log-symbols": "^6.0.0",
+ "stdin-discarder": "^0.2.2",
+ "string-width": "^7.2.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+ "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "dev": true
+ },
+ "chalk": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
+ "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
+ "dev": true
+ },
+ "cli-cursor": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+ "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^5.0.0"
+ }
+ },
+ "emoji-regex": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
+ "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
+ "dev": true
+ },
+ "is-unicode-supported": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+ "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
+ "dev": true
+ },
+ "log-symbols": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz",
+ "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==",
+ "dev": true,
+ "requires": {
+ "chalk": "^5.3.0",
+ "is-unicode-supported": "^1.3.0"
+ },
+ "dependencies": {
+ "is-unicode-supported": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
+ "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+ "dev": true
+ }
+ }
+ },
+ "onetime": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+ "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
+ "dev": true,
+ "requires": {
+ "mimic-function": "^5.0.0"
+ }
+ },
+ "restore-cursor": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+ "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
+ "dev": true,
+ "requires": {
+ "onetime": "^7.0.0",
+ "signal-exit": "^4.1.0"
+ }
+ },
+ "signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^6.0.1"
+ }
+ }
+ }
+ },
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
@@ -9657,6 +10168,12 @@
"spdx-ranges": "^2.0.0"
}
},
+ "stdin-discarder": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
+ "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==",
+ "dev": true
+ },
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -9717,9 +10234,9 @@
}
},
"tar-fs": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
- "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz",
+ "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==",
"dev": true,
"optional": true,
"requires": {
diff --git a/extension/package.json b/extension/package.json
index 12755b0c38..27f705f17b 100644
--- a/extension/package.json
+++ b/extension/package.json
@@ -1,7 +1,7 @@
{
"name": "go",
"displayName": "Go",
- "version": "0.46.0-dev",
+ "version": "0.48.0",
"publisher": "golang",
"description": "Rich Go language support for Visual Studio Code",
"author": {
@@ -74,9 +74,9 @@
"@types/node-fetch": "2.6.9",
"@types/semver": "7.3.4",
"@types/sinon": "9.0.11",
- "@types/vscode": "1.75.0",
- "@vscode/debugadapter-testsupport": "1.58.0",
- "@vscode/test-electron": "2.3.8",
+ "@types/vscode": "1.90.0",
+ "@vscode/debugadapter-testsupport": "1.68.0",
+ "@vscode/test-electron": "2.5.2",
"@vscode/vsce": "2.23.0",
"adm-zip": "0.4.16",
"esbuild": "0.17.10",
@@ -91,13 +91,14 @@
"yarn": "1.22.22"
},
"engines": {
- "vscode": "^1.75.0",
+ "vscode": "^1.90.0",
"node": ">=16.14.2"
},
"activationEvents": [
"onLanguage:go",
"onLanguage:go.sum",
"onLanguage:gotmpl",
+ "onLanguage:go.asm",
"onDebugInitialConfigurations",
"onDebugResolve:go",
"onWebviewPanel:welcomeGo"
@@ -129,6 +130,15 @@
"Go"
]
},
+ {
+ "id": "go.asm",
+ "extensions": [
+ ".s"
+ ],
+ "aliases": [
+ "Go Assembly"
+ ]
+ },
{
"id": "go.mod",
"filenames": [
@@ -391,12 +401,12 @@
{
"command": "go.add.tags",
"title": "Go: Add Tags To Struct Fields",
- "description": "Add tags configured in go.addTags setting to selected struct using gomodifytags"
+ "description": "Add tags configured in go.addTags setting to selected struct using gomodifytags (via gopls)"
},
{
"command": "go.remove.tags",
"title": "Go: Remove Tags From Struct Fields",
- "description": "Remove tags configured in go.removeTags setting from selected struct using gomodifytags"
+ "description": "Remove tags configured in go.removeTags setting from selected struct using gomodifytags (via gopls)"
},
{
"command": "go.show.commands",
@@ -1174,6 +1184,7 @@
"staticcheck",
"golint",
"golangci-lint",
+ "golangci-lint-v2",
"revive"
]
},
@@ -2032,7 +2043,7 @@
},
"run_govulncheck": {
"type": "boolean",
- "markdownDescription": "`\"run_govulncheck\"`: Run govulncheck (legacy)\n\nThis codelens source annotates the `module` directive in a go.mod file\nwith a command to run Govulncheck asynchronously.\n\n[Govulncheck](https://go.dev/blog/vuln) is a static analysis tool that\ncomputes the set of functions reachable within your application, including\ndependencies; queries a database of known security vulnerabilities; and\nreports any potential problems it finds.\n",
+ "markdownDescription": "(Experimental) `\"run_govulncheck\"`: Run govulncheck (legacy)\n\nThis codelens source annotates the `module` directive in a go.mod file\nwith a command to run Govulncheck asynchronously.\n\n[Govulncheck](https://go.dev/blog/vuln) is a static analysis tool that\ncomputes the set of functions reachable within your application, including\ndependencies; queries a database of known security vulnerabilities; and\nreports any potential problems it finds.\n",
"default": false
},
"test": {
@@ -2057,7 +2068,7 @@
},
"vulncheck": {
"type": "boolean",
- "markdownDescription": "`\"vulncheck\"`: Run govulncheck\n\nThis codelens source annotates the `module` directive in a go.mod file\nwith a command to run govulncheck synchronously.\n\n[Govulncheck](https://go.dev/blog/vuln) is a static analysis tool that\ncomputes the set of functions reachable within your application, including\ndependencies; queries a database of known security vulnerabilities; and\nreports any potential problems it finds.\n",
+ "markdownDescription": "(Experimental) `\"vulncheck\"`: Run govulncheck\n\nThis codelens source annotates the `module` directive in a go.mod file\nwith a command to run govulncheck synchronously.\n\n[Govulncheck](https://go.dev/blog/vuln) is a static analysis tool that\ncomputes the set of functions reachable within your application, including\ndependencies; queries a database of known security vulnerabilities; and\nreports any potential problems it finds.\n",
"default": false
}
}
@@ -2107,6 +2118,781 @@
"markdownDescription": "analyses specify analyses that the user would like to enable or disable.\nA map of the names of analysis passes that should be enabled/disabled.\nA full list of analyzers that gopls uses can be found in\n[analyzers.md](https://github.com/golang/tools/blob/master/gopls/doc/analyzers.md).\n\nExample Usage:\n\n```json5\n...\n\"analyses\": {\n \"unreachable\": false, // Disable the unreachable analyzer.\n \"unusedvariable\": true // Enable the unusedvariable analyzer.\n}\n...\n```\n",
"scope": "resource",
"properties": {
+ "QF1001": {
+ "type": "boolean",
+ "markdownDescription": "Apply De Morgan's law\n\nAvailable since\n 2021.1\n",
+ "default": false
+ },
+ "QF1002": {
+ "type": "boolean",
+ "markdownDescription": "Convert untagged switch to tagged switch\n\nAn untagged switch that compares a single variable against a series of\nvalues can be replaced with a tagged switch.\n\nBefore:\n\n switch {\n case x == 1 || x == 2, x == 3:\n ...\n case x == 4:\n ...\n default:\n ...\n }\n\nAfter:\n\n switch x {\n case 1, 2, 3:\n ...\n case 4:\n ...\n default:\n ...\n }\n\nAvailable since\n 2021.1\n",
+ "default": true
+ },
+ "QF1003": {
+ "type": "boolean",
+ "markdownDescription": "Convert if/else-if chain to tagged switch\n\nA series of if/else-if checks comparing the same variable against\nvalues can be replaced with a tagged switch.\n\nBefore:\n\n if x == 1 || x == 2 {\n ...\n } else if x == 3 {\n ...\n } else {\n ...\n }\n\nAfter:\n\n switch x {\n case 1, 2:\n ...\n case 3:\n ...\n default:\n ...\n }\n\nAvailable since\n 2021.1\n",
+ "default": true
+ },
+ "QF1004": {
+ "type": "boolean",
+ "markdownDescription": "Use strings.ReplaceAll instead of strings.Replace with n == -1\n\nAvailable since\n 2021.1\n",
+ "default": true
+ },
+ "QF1005": {
+ "type": "boolean",
+ "markdownDescription": "Expand call to math.Pow\n\nSome uses of math.Pow can be simplified to basic multiplication.\n\nBefore:\n\n math.Pow(x, 2)\n\nAfter:\n\n x * x\n\nAvailable since\n 2021.1\n",
+ "default": false
+ },
+ "QF1006": {
+ "type": "boolean",
+ "markdownDescription": "Lift if+break into loop condition\n\nBefore:\n\n for {\n if done {\n break\n }\n ...\n }\n\nAfter:\n\n for !done {\n ...\n }\n\nAvailable since\n 2021.1\n",
+ "default": false
+ },
+ "QF1007": {
+ "type": "boolean",
+ "markdownDescription": "Merge conditional assignment into variable declaration\n\nBefore:\n\n x := false\n if someCondition {\n x = true\n }\n\nAfter:\n\n x := someCondition\n\nAvailable since\n 2021.1\n",
+ "default": false
+ },
+ "QF1008": {
+ "type": "boolean",
+ "markdownDescription": "Omit embedded fields from selector expression\n\nAvailable since\n 2021.1\n",
+ "default": false
+ },
+ "QF1009": {
+ "type": "boolean",
+ "markdownDescription": "Use time.Time.Equal instead of == operator\n\nAvailable since\n 2021.1\n",
+ "default": true
+ },
+ "QF1010": {
+ "type": "boolean",
+ "markdownDescription": "Convert slice of bytes to string when printing it\n\nAvailable since\n 2021.1\n",
+ "default": true
+ },
+ "QF1011": {
+ "type": "boolean",
+ "markdownDescription": "Omit redundant type from variable declaration\n\nAvailable since\n 2021.1\n",
+ "default": false
+ },
+ "QF1012": {
+ "type": "boolean",
+ "markdownDescription": "Use fmt.Fprintf(x, ...) instead of x.Write(fmt.Sprintf(...))\n\nAvailable since\n 2022.1\n",
+ "default": true
+ },
+ "S1000": {
+ "type": "boolean",
+ "markdownDescription": "Use plain channel send or receive instead of single-case select\n\nSelect statements with a single case can be replaced with a simple\nsend or receive.\n\nBefore:\n\n select {\n case x := <-ch:\n fmt.Println(x)\n }\n\nAfter:\n\n x := <-ch\n fmt.Println(x)\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1001": {
+ "type": "boolean",
+ "markdownDescription": "Replace for loop with call to copy\n\nUse copy() for copying elements from one slice to another. For\narrays of identical size, you can use simple assignment.\n\nBefore:\n\n for i, x := range src {\n dst[i] = x\n }\n\nAfter:\n\n copy(dst, src)\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1002": {
+ "type": "boolean",
+ "markdownDescription": "Omit comparison with boolean constant\n\nBefore:\n\n if x == true {}\n\nAfter:\n\n if x {}\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "S1003": {
+ "type": "boolean",
+ "markdownDescription": "Replace call to strings.Index with strings.Contains\n\nBefore:\n\n if strings.Index(x, y) != -1 {}\n\nAfter:\n\n if strings.Contains(x, y) {}\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1004": {
+ "type": "boolean",
+ "markdownDescription": "Replace call to bytes.Compare with bytes.Equal\n\nBefore:\n\n if bytes.Compare(x, y) == 0 {}\n\nAfter:\n\n if bytes.Equal(x, y) {}\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1005": {
+ "type": "boolean",
+ "markdownDescription": "Drop unnecessary use of the blank identifier\n\nIn many cases, assigning to the blank identifier is unnecessary.\n\nBefore:\n\n for _ = range s {}\n x, _ = someMap[key]\n _ = <-ch\n\nAfter:\n\n for range s{}\n x = someMap[key]\n <-ch\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "S1006": {
+ "type": "boolean",
+ "markdownDescription": "Use 'for { ... }' for infinite loops\n\nFor infinite loops, using for { ... } is the most idiomatic choice.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "S1007": {
+ "type": "boolean",
+ "markdownDescription": "Simplify regular expression by using raw string literal\n\nRaw string literals use backticks instead of quotation marks and do not support\nany escape sequences. This means that the backslash can be used\nfreely, without the need of escaping.\n\nSince regular expressions have their own escape sequences, raw strings\ncan improve their readability.\n\nBefore:\n\n regexp.Compile(\"\\\\A(\\\\w+) profile: total \\\\d+\\\\n\\\\z\")\n\nAfter:\n\n regexp.Compile(`\\A(\\w+) profile: total \\d+\\n\\z`)\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1008": {
+ "type": "boolean",
+ "markdownDescription": "Simplify returning boolean expression\n\nBefore:\n\n if {\n return true\n }\n return false\n\nAfter:\n\n return \n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "S1009": {
+ "type": "boolean",
+ "markdownDescription": "Omit redundant nil check on slices, maps, and channels\n\nThe len function is defined for all slices, maps, and\nchannels, even nil ones, which have a length of zero. It is not necessary to\ncheck for nil before checking that their length is not zero.\n\nBefore:\n\n if x != nil && len(x) != 0 {}\n\nAfter:\n\n if len(x) != 0 {}\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1010": {
+ "type": "boolean",
+ "markdownDescription": "Omit default slice index\n\nWhen slicing, the second index defaults to the length of the value,\nmaking s[n:len(s)] and s[n:] equivalent.\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1011": {
+ "type": "boolean",
+ "markdownDescription": "Use a single append to concatenate two slices\n\nBefore:\n\n for _, e := range y {\n x = append(x, e)\n }\n \n for i := range y {\n x = append(x, y[i])\n }\n \n for i := range y {\n v := y[i]\n x = append(x, v)\n }\n\nAfter:\n\n x = append(x, y...)\n x = append(x, y...)\n x = append(x, y...)\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "S1012": {
+ "type": "boolean",
+ "markdownDescription": "Replace time.Now().Sub(x) with time.Since(x)\n\nThe time.Since helper has the same effect as using time.Now().Sub(x)\nbut is easier to read.\n\nBefore:\n\n time.Now().Sub(x)\n\nAfter:\n\n time.Since(x)\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1016": {
+ "type": "boolean",
+ "markdownDescription": "Use a type conversion instead of manually copying struct fields\n\nTwo struct types with identical fields can be converted between each\nother. In older versions of Go, the fields had to have identical\nstruct tags. Since Go 1.8, however, struct tags are ignored during\nconversions. It is thus not necessary to manually copy every field\nindividually.\n\nBefore:\n\n var x T1\n y := T2{\n Field1: x.Field1,\n Field2: x.Field2,\n }\n\nAfter:\n\n var x T1\n y := T2(x)\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "S1017": {
+ "type": "boolean",
+ "markdownDescription": "Replace manual trimming with strings.TrimPrefix\n\nInstead of using strings.HasPrefix and manual slicing, use the\nstrings.TrimPrefix function. If the string doesn't start with the\nprefix, the original string will be returned. Using strings.TrimPrefix\nreduces complexity, and avoids common bugs, such as off-by-one\nmistakes.\n\nBefore:\n\n if strings.HasPrefix(str, prefix) {\n str = str[len(prefix):]\n }\n\nAfter:\n\n str = strings.TrimPrefix(str, prefix)\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1018": {
+ "type": "boolean",
+ "markdownDescription": "Use 'copy' for sliding elements\n\ncopy() permits using the same source and destination slice, even with\noverlapping ranges. This makes it ideal for sliding elements in a\nslice.\n\nBefore:\n\n for i := 0; i < n; i++ {\n bs[i] = bs[offset+i]\n }\n\nAfter:\n\n copy(bs[:n], bs[offset:])\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1019": {
+ "type": "boolean",
+ "markdownDescription": "Simplify 'make' call by omitting redundant arguments\n\nThe 'make' function has default values for the length and capacity\narguments. For channels, the length defaults to zero, and for slices,\nthe capacity defaults to the length.\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1020": {
+ "type": "boolean",
+ "markdownDescription": "Omit redundant nil check in type assertion\n\nBefore:\n\n if _, ok := i.(T); ok && i != nil {}\n\nAfter:\n\n if _, ok := i.(T); ok {}\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1021": {
+ "type": "boolean",
+ "markdownDescription": "Merge variable declaration and assignment\n\nBefore:\n\n var x uint\n x = 1\n\nAfter:\n\n var x uint = 1\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "S1023": {
+ "type": "boolean",
+ "markdownDescription": "Omit redundant control flow\n\nFunctions that have no return value do not need a return statement as\nthe final statement of the function.\n\nSwitches in Go do not have automatic fallthrough, unlike languages\nlike C. It is not necessary to have a break statement as the final\nstatement in a case block.\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1024": {
+ "type": "boolean",
+ "markdownDescription": "Replace x.Sub(time.Now()) with time.Until(x)\n\nThe time.Until helper has the same effect as using x.Sub(time.Now())\nbut is easier to read.\n\nBefore:\n\n x.Sub(time.Now())\n\nAfter:\n\n time.Until(x)\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1025": {
+ "type": "boolean",
+ "markdownDescription": "Don't use fmt.Sprintf(\"%s\", x) unnecessarily\n\nIn many instances, there are easier and more efficient ways of getting\na value's string representation. Whenever a value's underlying type is\na string already, or the type has a String method, they should be used\ndirectly.\n\nGiven the following shared definitions\n\n type T1 string\n type T2 int\n\n func (T2) String() string { return \"Hello, world\" }\n\n var x string\n var y T1\n var z T2\n\nwe can simplify\n\n fmt.Sprintf(\"%s\", x)\n fmt.Sprintf(\"%s\", y)\n fmt.Sprintf(\"%s\", z)\n\nto\n\n x\n string(y)\n z.String()\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "S1028": {
+ "type": "boolean",
+ "markdownDescription": "Simplify error construction with fmt.Errorf\n\nBefore:\n\n errors.New(fmt.Sprintf(...))\n\nAfter:\n\n fmt.Errorf(...)\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1029": {
+ "type": "boolean",
+ "markdownDescription": "Range over the string directly\n\nRanging over a string will yield byte offsets and runes. If the offset\nisn't used, this is functionally equivalent to converting the string\nto a slice of runes and ranging over that. Ranging directly over the\nstring will be more performant, however, as it avoids allocating a new\nslice, the size of which depends on the length of the string.\n\nBefore:\n\n for _, r := range []rune(s) {}\n\nAfter:\n\n for _, r := range s {}\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "S1030": {
+ "type": "boolean",
+ "markdownDescription": "Use bytes.Buffer.String or bytes.Buffer.Bytes\n\nbytes.Buffer has both a String and a Bytes method. It is almost never\nnecessary to use string(buf.Bytes()) or []byte(buf.String()) – simply\nuse the other method.\n\nThe only exception to this are map lookups. Due to a compiler optimization,\nm[string(buf.Bytes())] is more efficient than m[buf.String()].\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1031": {
+ "type": "boolean",
+ "markdownDescription": "Omit redundant nil check around loop\n\nYou can use range on nil slices and maps, the loop will simply never\nexecute. This makes an additional nil check around the loop\nunnecessary.\n\nBefore:\n\n if s != nil {\n for _, x := range s {\n ...\n }\n }\n\nAfter:\n\n for _, x := range s {\n ...\n }\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "S1032": {
+ "type": "boolean",
+ "markdownDescription": "Use sort.Ints(x), sort.Float64s(x), and sort.Strings(x)\n\nThe sort.Ints, sort.Float64s and sort.Strings functions are easier to\nread than sort.Sort(sort.IntSlice(x)), sort.Sort(sort.Float64Slice(x))\nand sort.Sort(sort.StringSlice(x)).\n\nBefore:\n\n sort.Sort(sort.StringSlice(x))\n\nAfter:\n\n sort.Strings(x)\n\nAvailable since\n 2019.1\n",
+ "default": true
+ },
+ "S1033": {
+ "type": "boolean",
+ "markdownDescription": "Unnecessary guard around call to 'delete'\n\nCalling delete on a nil map is a no-op.\n\nAvailable since\n 2019.2\n",
+ "default": true
+ },
+ "S1034": {
+ "type": "boolean",
+ "markdownDescription": "Use result of type assertion to simplify cases\n\nAvailable since\n 2019.2\n",
+ "default": true
+ },
+ "S1035": {
+ "type": "boolean",
+ "markdownDescription": "Redundant call to net/http.CanonicalHeaderKey in method call on net/http.Header\n\nThe methods on net/http.Header, namely Add, Del, Get\nand Set, already canonicalize the given header name.\n\nAvailable since\n 2020.1\n",
+ "default": true
+ },
+ "S1036": {
+ "type": "boolean",
+ "markdownDescription": "Unnecessary guard around map access\n\nWhen accessing a map key that doesn't exist yet, one receives a zero\nvalue. Often, the zero value is a suitable value, for example when\nusing append or doing integer math.\n\nThe following\n\n if _, ok := m[\"foo\"]; ok {\n m[\"foo\"] = append(m[\"foo\"], \"bar\")\n } else {\n m[\"foo\"] = []string{\"bar\"}\n }\n\ncan be simplified to\n\n m[\"foo\"] = append(m[\"foo\"], \"bar\")\n\nand\n\n if _, ok := m2[\"k\"]; ok {\n m2[\"k\"] += 4\n } else {\n m2[\"k\"] = 4\n }\n\ncan be simplified to\n\n m[\"k\"] += 4\n\nAvailable since\n 2020.1\n",
+ "default": true
+ },
+ "S1037": {
+ "type": "boolean",
+ "markdownDescription": "Elaborate way of sleeping\n\nUsing a select statement with a single case receiving\nfrom the result of time.After is a very elaborate way of sleeping that\ncan much simpler be expressed with a simple call to time.Sleep.\n\nAvailable since\n 2020.1\n",
+ "default": true
+ },
+ "S1038": {
+ "type": "boolean",
+ "markdownDescription": "Unnecessarily complex way of printing formatted string\n\nInstead of using fmt.Print(fmt.Sprintf(...)), one can use fmt.Printf(...).\n\nAvailable since\n 2020.1\n",
+ "default": true
+ },
+ "S1039": {
+ "type": "boolean",
+ "markdownDescription": "Unnecessary use of fmt.Sprint\n\nCalling fmt.Sprint with a single string argument is unnecessary\nand identical to using the string directly.\n\nAvailable since\n 2020.1\n",
+ "default": true
+ },
+ "S1040": {
+ "type": "boolean",
+ "markdownDescription": "Type assertion to current type\n\nThe type assertion x.(SomeInterface), when x already has type\nSomeInterface, can only fail if x is nil. Usually, this is\nleft-over code from when x had a different type and you can safely\ndelete the type assertion. If you want to check that x is not nil,\nconsider being explicit and using an actual if x == nil comparison\ninstead of relying on the type assertion panicking.\n\nAvailable since\n 2021.1\n",
+ "default": true
+ },
+ "SA1000": {
+ "type": "boolean",
+ "markdownDescription": "Invalid regular expression\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1001": {
+ "type": "boolean",
+ "markdownDescription": "Invalid template\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA1002": {
+ "type": "boolean",
+ "markdownDescription": "Invalid format in time.Parse\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1003": {
+ "type": "boolean",
+ "markdownDescription": "Unsupported argument to functions in encoding/binary\n\nThe encoding/binary package can only serialize types with known sizes.\nThis precludes the use of the int and uint types, as their sizes\ndiffer on different architectures. Furthermore, it doesn't support\nserializing maps, channels, strings, or functions.\n\nBefore Go 1.8, bool wasn't supported, either.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1004": {
+ "type": "boolean",
+ "markdownDescription": "Suspiciously small untyped constant in time.Sleep\n\nThe time.Sleep function takes a time.Duration as its only argument.\nDurations are expressed in nanoseconds. Thus, calling time.Sleep(1)\nwill sleep for 1 nanosecond. This is a common source of bugs, as sleep\nfunctions in other languages often accept seconds or milliseconds.\n\nThe time package provides constants such as time.Second to express\nlarge durations. These can be combined with arithmetic to express\narbitrary durations, for example 5 * time.Second for 5 seconds.\n\nIf you truly meant to sleep for a tiny amount of time, use\nn * time.Nanosecond to signal to Staticcheck that you did mean to sleep\nfor some amount of nanoseconds.\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA1005": {
+ "type": "boolean",
+ "markdownDescription": "Invalid first argument to exec.Command\n\nos/exec runs programs directly (using variants of the fork and exec\nsystem calls on Unix systems). This shouldn't be confused with running\na command in a shell. The shell will allow for features such as input\nredirection, pipes, and general scripting. The shell is also\nresponsible for splitting the user's input into a program name and its\narguments. For example, the equivalent to\n\n ls / /tmp\n\nwould be\n\n exec.Command(\"ls\", \"/\", \"/tmp\")\n\nIf you want to run a command in a shell, consider using something like\nthe following – but be aware that not all systems, particularly\nWindows, will have a /bin/sh program:\n\n exec.Command(\"/bin/sh\", \"-c\", \"ls | grep Awesome\")\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA1007": {
+ "type": "boolean",
+ "markdownDescription": "Invalid URL in net/url.Parse\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1008": {
+ "type": "boolean",
+ "markdownDescription": "Non-canonical key in http.Header map\n\nKeys in http.Header maps are canonical, meaning they follow a specific\ncombination of uppercase and lowercase letters. Methods such as\nhttp.Header.Add and http.Header.Del convert inputs into this canonical\nform before manipulating the map.\n\nWhen manipulating http.Header maps directly, as opposed to using the\nprovided methods, care should be taken to stick to canonical form in\norder to avoid inconsistencies. The following piece of code\ndemonstrates one such inconsistency:\n\n h := http.Header{}\n h[\"etag\"] = []string{\"1234\"}\n h.Add(\"etag\", \"5678\")\n fmt.Println(h)\n\n // Output:\n // map[Etag:[5678] etag:[1234]]\n\nThe easiest way of obtaining the canonical form of a key is to use\nhttp.CanonicalHeaderKey.\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA1010": {
+ "type": "boolean",
+ "markdownDescription": "(*regexp.Regexp).FindAll called with n == 0, which will always return zero results\n\nIf n >= 0, the function returns at most n matches/submatches. To\nreturn all results, specify a negative number.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1011": {
+ "type": "boolean",
+ "markdownDescription": "Various methods in the 'strings' package expect valid UTF-8, but invalid input is provided\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1012": {
+ "type": "boolean",
+ "markdownDescription": "A nil context.Context is being passed to a function, consider using context.TODO instead\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA1013": {
+ "type": "boolean",
+ "markdownDescription": "io.Seeker.Seek is being called with the whence constant as the first argument, but it should be the second\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA1014": {
+ "type": "boolean",
+ "markdownDescription": "Non-pointer value passed to Unmarshal or Decode\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1015": {
+ "type": "boolean",
+ "markdownDescription": "Using time.Tick in a way that will leak. Consider using time.NewTicker, and only use time.Tick in tests, commands and endless functions\n\nBefore Go 1.23, time.Tickers had to be closed to be able to be garbage\ncollected. Since time.Tick doesn't make it possible to close the underlying\nticker, using it repeatedly would leak memory.\n\nGo 1.23 fixes this by allowing tickers to be collected even if they weren't closed.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1016": {
+ "type": "boolean",
+ "markdownDescription": "Trapping a signal that cannot be trapped\n\nNot all signals can be intercepted by a process. Specifically, on\nUNIX-like systems, the syscall.SIGKILL and syscall.SIGSTOP signals are\nnever passed to the process, but instead handled directly by the\nkernel. It is therefore pointless to try and handle these signals.\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA1017": {
+ "type": "boolean",
+ "markdownDescription": "Channels used with os/signal.Notify should be buffered\n\nThe os/signal package uses non-blocking channel sends when delivering\nsignals. If the receiving end of the channel isn't ready and the\nchannel is either unbuffered or full, the signal will be dropped. To\navoid missing signals, the channel should be buffered and of the\nappropriate size. For a channel used for notification of just one\nsignal value, a buffer of size 1 is sufficient.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1018": {
+ "type": "boolean",
+ "markdownDescription": "strings.Replace called with n == 0, which does nothing\n\nWith n == 0, zero instances will be replaced. To replace all\ninstances, use a negative number, or use strings.ReplaceAll.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1020": {
+ "type": "boolean",
+ "markdownDescription": "Using an invalid host:port pair with a net.Listen-related function\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1021": {
+ "type": "boolean",
+ "markdownDescription": "Using bytes.Equal to compare two net.IP\n\nA net.IP stores an IPv4 or IPv6 address as a slice of bytes. The\nlength of the slice for an IPv4 address, however, can be either 4 or\n16 bytes long, using different ways of representing IPv4 addresses. In\norder to correctly compare two net.IPs, the net.IP.Equal method should\nbe used, as it takes both representations into account.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1023": {
+ "type": "boolean",
+ "markdownDescription": "Modifying the buffer in an io.Writer implementation\n\nWrite must not modify the slice data, even temporarily.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1024": {
+ "type": "boolean",
+ "markdownDescription": "A string cutset contains duplicate characters\n\nThe strings.TrimLeft and strings.TrimRight functions take cutsets, not\nprefixes. A cutset is treated as a set of characters to remove from a\nstring. For example,\n\n strings.TrimLeft(\"42133word\", \"1234\")\n\nwill result in the string \"word\" – any characters that are 1, 2, 3 or\n4 are cut from the left of the string.\n\nIn order to remove one string from another, use strings.TrimPrefix instead.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA1025": {
+ "type": "boolean",
+ "markdownDescription": "It is not possible to use (*time.Timer).Reset's return value correctly\n\nAvailable since\n 2019.1\n",
+ "default": false
+ },
+ "SA1026": {
+ "type": "boolean",
+ "markdownDescription": "Cannot marshal channels or functions\n\nAvailable since\n 2019.2\n",
+ "default": false
+ },
+ "SA1027": {
+ "type": "boolean",
+ "markdownDescription": "Atomic access to 64-bit variable must be 64-bit aligned\n\nOn ARM, x86-32, and 32-bit MIPS, it is the caller's responsibility to\narrange for 64-bit alignment of 64-bit words accessed atomically. The\nfirst word in a variable or in an allocated struct, array, or slice\ncan be relied upon to be 64-bit aligned.\n\nYou can use the structlayout tool to inspect the alignment of fields\nin a struct.\n\nAvailable since\n 2019.2\n",
+ "default": false
+ },
+ "SA1028": {
+ "type": "boolean",
+ "markdownDescription": "sort.Slice can only be used on slices\n\nThe first argument of sort.Slice must be a slice.\n\nAvailable since\n 2020.1\n",
+ "default": false
+ },
+ "SA1029": {
+ "type": "boolean",
+ "markdownDescription": "Inappropriate key in call to context.WithValue\n\nThe provided key must be comparable and should not be\nof type string or any other built-in type to avoid collisions between\npackages using context. Users of WithValue should define their own\ntypes for keys.\n\nTo avoid allocating when assigning to an interface{},\ncontext keys often have concrete type struct{}. Alternatively,\nexported context key variables' static type should be a pointer or\ninterface.\n\nAvailable since\n 2020.1\n",
+ "default": false
+ },
+ "SA1030": {
+ "type": "boolean",
+ "markdownDescription": "Invalid argument in call to a strconv function\n\nThis check validates the format, number base and bit size arguments of\nthe various parsing and formatting functions in strconv.\n\nAvailable since\n 2021.1\n",
+ "default": false
+ },
+ "SA1031": {
+ "type": "boolean",
+ "markdownDescription": "Overlapping byte slices passed to an encoder\n\nIn an encoding function of the form Encode(dst, src), dst and\nsrc were found to reference the same memory. This can result in\nsrc bytes being overwritten before they are read, when the encoder\nwrites more than one byte per src byte.\n\nAvailable since\n 2024.1\n",
+ "default": false
+ },
+ "SA1032": {
+ "type": "boolean",
+ "markdownDescription": "Wrong order of arguments to errors.Is\n\nThe first argument of the function errors.Is is the error\nthat we have and the second argument is the error we're trying to match against.\nFor example:\n\n\tif errors.Is(err, io.EOF) { ... }\n\nThis check detects some cases where the two arguments have been swapped. It\nflags any calls where the first argument is referring to a package-level error\nvariable, such as\n\n\tif errors.Is(io.EOF, err) { /* this is wrong */ }\n\nAvailable since\n 2024.1\n",
+ "default": false
+ },
+ "SA2001": {
+ "type": "boolean",
+ "markdownDescription": "Empty critical section, did you mean to defer the unlock?\n\nEmpty critical sections of the kind\n\n mu.Lock()\n mu.Unlock()\n\nare very often a typo, and the following was intended instead:\n\n mu.Lock()\n defer mu.Unlock()\n\nDo note that sometimes empty critical sections can be useful, as a\nform of signaling to wait on another goroutine. Many times, there are\nsimpler ways of achieving the same effect. When that isn't the case,\nthe code should be amply commented to avoid confusion. Combining such\ncomments with a //lint:ignore directive can be used to suppress this\nrare false positive.\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA2002": {
+ "type": "boolean",
+ "markdownDescription": "Called testing.T.FailNow or SkipNow in a goroutine, which isn't allowed\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA2003": {
+ "type": "boolean",
+ "markdownDescription": "Deferred Lock right after locking, likely meant to defer Unlock instead\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA3000": {
+ "type": "boolean",
+ "markdownDescription": "TestMain doesn't call os.Exit, hiding test failures\n\nTest executables (and in turn 'go test') exit with a non-zero status\ncode if any tests failed. When specifying your own TestMain function,\nit is your responsibility to arrange for this, by calling os.Exit with\nthe correct code. The correct code is returned by (*testing.M).Run, so\nthe usual way of implementing TestMain is to end it with\nos.Exit(m.Run()).\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA3001": {
+ "type": "boolean",
+ "markdownDescription": "Assigning to b.N in benchmarks distorts the results\n\nThe testing package dynamically sets b.N to improve the reliability of\nbenchmarks and uses it in computations to determine the duration of a\nsingle operation. Benchmark code must not alter b.N as this would\nfalsify results.\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA4000": {
+ "type": "boolean",
+ "markdownDescription": "Binary operator has identical expressions on both sides\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA4001": {
+ "type": "boolean",
+ "markdownDescription": "&*x gets simplified to x, it does not copy x\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA4003": {
+ "type": "boolean",
+ "markdownDescription": "Comparing unsigned values against negative values is pointless\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA4004": {
+ "type": "boolean",
+ "markdownDescription": "The loop exits unconditionally after one iteration\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA4005": {
+ "type": "boolean",
+ "markdownDescription": "Field assignment that will never be observed. Did you mean to use a pointer receiver?\n\nAvailable since\n 2021.1\n",
+ "default": false
+ },
+ "SA4006": {
+ "type": "boolean",
+ "markdownDescription": "A value assigned to a variable is never read before being overwritten. Forgotten error check or dead code?\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA4008": {
+ "type": "boolean",
+ "markdownDescription": "The variable in the loop condition never changes, are you incrementing the wrong variable?\n\nFor example:\n\n\tfor i := 0; i < 10; j++ { ... }\n\nThis may also occur when a loop can only execute once because of unconditional\ncontrol flow that terminates the loop. For example, when a loop body contains an\nunconditional break, return, or panic:\n\n\tfunc f() {\n\t\tpanic(\"oops\")\n\t}\n\tfunc g() {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\t// f unconditionally calls panic, which means \"i\" is\n\t\t\t// never incremented.\n\t\t\tf()\n\t\t}\n\t}\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA4009": {
+ "type": "boolean",
+ "markdownDescription": "A function argument is overwritten before its first use\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA4010": {
+ "type": "boolean",
+ "markdownDescription": "The result of append will never be observed anywhere\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA4011": {
+ "type": "boolean",
+ "markdownDescription": "Break statement with no effect. Did you mean to break out of an outer loop?\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA4012": {
+ "type": "boolean",
+ "markdownDescription": "Comparing a value against NaN even though no value is equal to NaN\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA4013": {
+ "type": "boolean",
+ "markdownDescription": "Negating a boolean twice (!!b) is the same as writing b. This is either redundant, or a typo.\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA4014": {
+ "type": "boolean",
+ "markdownDescription": "An if/else if chain has repeated conditions and no side-effects; if the condition didn't match the first time, it won't match the second time, either\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA4015": {
+ "type": "boolean",
+ "markdownDescription": "Calling functions like math.Ceil on floats converted from integers doesn't do anything useful\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA4016": {
+ "type": "boolean",
+ "markdownDescription": "Certain bitwise operations, such as x ^ 0, do not do anything useful\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA4017": {
+ "type": "boolean",
+ "markdownDescription": "Discarding the return values of a function without side effects, making the call pointless\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA4018": {
+ "type": "boolean",
+ "markdownDescription": "Self-assignment of variables\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA4019": {
+ "type": "boolean",
+ "markdownDescription": "Multiple, identical build constraints in the same file\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA4020": {
+ "type": "boolean",
+ "markdownDescription": "Unreachable case clause in a type switch\n\nIn a type switch like the following\n\n type T struct{}\n func (T) Read(b []byte) (int, error) { return 0, nil }\n\n var v any = T{}\n\n switch v.(type) {\n case io.Reader:\n // ...\n case T:\n // unreachable\n }\n\nthe second case clause can never be reached because T implements\nio.Reader and case clauses are evaluated in source order.\n\nAnother example:\n\n type T struct{}\n func (T) Read(b []byte) (int, error) { return 0, nil }\n func (T) Close() error { return nil }\n\n var v any = T{}\n\n switch v.(type) {\n case io.Reader:\n // ...\n case io.ReadCloser:\n // unreachable\n }\n\nEven though T has a Close method and thus implements io.ReadCloser,\nio.Reader will always match first. The method set of io.Reader is a\nsubset of io.ReadCloser. Thus it is impossible to match the second\ncase without matching the first case.\n\n\nStructurally equivalent interfaces\n\nA special case of the previous example are structurally identical\ninterfaces. Given these declarations\n\n type T error\n type V error\n\n func doSomething() error {\n err, ok := doAnotherThing()\n if ok {\n return T(err)\n }\n\n return U(err)\n }\n\nthe following type switch will have an unreachable case clause:\n\n switch doSomething().(type) {\n case T:\n // ...\n case V:\n // unreachable\n }\n\nT will always match before V because they are structurally equivalent\nand therefore doSomething()'s return value implements both.\n\nAvailable since\n 2019.2\n",
+ "default": true
+ },
+ "SA4022": {
+ "type": "boolean",
+ "markdownDescription": "Comparing the address of a variable against nil\n\nCode such as 'if &x == nil' is meaningless, because taking the address of a variable always yields a non-nil pointer.\n\nAvailable since\n 2020.1\n",
+ "default": true
+ },
+ "SA4023": {
+ "type": "boolean",
+ "markdownDescription": "Impossible comparison of interface value with untyped nil\n\nUnder the covers, interfaces are implemented as two elements, a\ntype T and a value V. V is a concrete value such as an int,\nstruct or pointer, never an interface itself, and has type T. For\ninstance, if we store the int value 3 in an interface, the\nresulting interface value has, schematically, (T=int, V=3). The\nvalue V is also known as the interface's dynamic value, since a\ngiven interface variable might hold different values V (and\ncorresponding types T) during the execution of the program.\n\nAn interface value is nil only if the V and T are both\nunset, (T=nil, V is not set), In particular, a nil interface will\nalways hold a nil type. If we store a nil pointer of type *int\ninside an interface value, the inner type will be *int regardless\nof the value of the pointer: (T=*int, V=nil). Such an interface\nvalue will therefore be non-nil even when the pointer value V\ninside is nil.\n\nThis situation can be confusing, and arises when a nil value is\nstored inside an interface value such as an error return:\n\n func returnsError() error {\n var p *MyError = nil\n if bad() {\n p = ErrBad\n }\n return p // Will always return a non-nil error.\n }\n\nIf all goes well, the function returns a nil p, so the return\nvalue is an error interface value holding (T=*MyError, V=nil).\nThis means that if the caller compares the returned error to nil,\nit will always look as if there was an error even if nothing bad\nhappened. To return a proper nil error to the caller, the\nfunction must return an explicit nil:\n\n func returnsError() error {\n if bad() {\n return ErrBad\n }\n return nil\n }\n\nIt's a good idea for functions that return errors always to use\nthe error type in their signature (as we did above) rather than a\nconcrete type such as *MyError, to help guarantee the error is\ncreated correctly. As an example, os.Open returns an error even\nthough, if not nil, it's always of concrete type *os.PathError.\n\nSimilar situations to those described here can arise whenever\ninterfaces are used. Just keep in mind that if any concrete value\nhas been stored in the interface, the interface will not be nil.\nFor more information, see The Laws of\nReflection at https://golang.org/doc/articles/laws_of_reflection.html.\n\nThis text has been copied from\nhttps://golang.org/doc/faq#nil_error, licensed under the Creative\nCommons Attribution 3.0 License.\n\nAvailable since\n 2020.2\n",
+ "default": false
+ },
+ "SA4024": {
+ "type": "boolean",
+ "markdownDescription": "Checking for impossible return value from a builtin function\n\nReturn values of the len and cap builtins cannot be negative.\n\nSee https://golang.org/pkg/builtin/#len and https://golang.org/pkg/builtin/#cap.\n\nExample:\n\n if len(slice) < 0 {\n fmt.Println(\"unreachable code\")\n }\n\nAvailable since\n 2021.1\n",
+ "default": true
+ },
+ "SA4025": {
+ "type": "boolean",
+ "markdownDescription": "Integer division of literals that results in zero\n\nWhen dividing two integer constants, the result will\nalso be an integer. Thus, a division such as 2 / 3 results in 0.\nThis is true for all of the following examples:\n\n\t_ = 2 / 3\n\tconst _ = 2 / 3\n\tconst _ float64 = 2 / 3\n\t_ = float64(2 / 3)\n\nStaticcheck will flag such divisions if both sides of the division are\ninteger literals, as it is highly unlikely that the division was\nintended to truncate to zero. Staticcheck will not flag integer\ndivision involving named constants, to avoid noisy positives.\n\nAvailable since\n 2021.1\n",
+ "default": true
+ },
+ "SA4026": {
+ "type": "boolean",
+ "markdownDescription": "Go constants cannot express negative zero\n\nIn IEEE 754 floating point math, zero has a sign and can be positive\nor negative. This can be useful in certain numerical code.\n\nGo constants, however, cannot express negative zero. This means that\nthe literals -0.0 and 0.0 have the same ideal value (zero) and\nwill both represent positive zero at runtime.\n\nTo explicitly and reliably create a negative zero, you can use the\nmath.Copysign function: math.Copysign(0, -1).\n\nAvailable since\n 2021.1\n",
+ "default": true
+ },
+ "SA4027": {
+ "type": "boolean",
+ "markdownDescription": "(*net/url.URL).Query returns a copy, modifying it doesn't change the URL\n\n(*net/url.URL).Query parses the current value of net/url.URL.RawQuery\nand returns it as a map of type net/url.Values. Subsequent changes to\nthis map will not affect the URL unless the map gets encoded and\nassigned to the URL's RawQuery.\n\nAs a consequence, the following code pattern is an expensive no-op:\nu.Query().Add(key, value).\n\nAvailable since\n 2021.1\n",
+ "default": true
+ },
+ "SA4028": {
+ "type": "boolean",
+ "markdownDescription": "x % 1 is always zero\n\nAvailable since\n 2022.1\n",
+ "default": true
+ },
+ "SA4029": {
+ "type": "boolean",
+ "markdownDescription": "Ineffective attempt at sorting slice\n\nsort.Float64Slice, sort.IntSlice, and sort.StringSlice are\ntypes, not functions. Doing x = sort.StringSlice(x) does nothing,\nespecially not sort any values. The correct usage is\nsort.Sort(sort.StringSlice(x)) or sort.StringSlice(x).Sort(),\nbut there are more convenient helpers, namely sort.Float64s,\nsort.Ints, and sort.Strings.\n\nAvailable since\n 2022.1\n",
+ "default": true
+ },
+ "SA4030": {
+ "type": "boolean",
+ "markdownDescription": "Ineffective attempt at generating random number\n\nFunctions in the math/rand package that accept upper limits, such\nas Intn, generate random numbers in the half-open interval [0,n). In\nother words, the generated numbers will be >= 0 and < n – they\ndon't include n. rand.Intn(1) therefore doesn't generate 0\nor 1, it always generates 0.\n\nAvailable since\n 2022.1\n",
+ "default": true
+ },
+ "SA4031": {
+ "type": "boolean",
+ "markdownDescription": "Checking never-nil value against nil\n\nAvailable since\n 2022.1\n",
+ "default": false
+ },
+ "SA4032": {
+ "type": "boolean",
+ "markdownDescription": "Comparing runtime.GOOS or runtime.GOARCH against impossible value\n\nAvailable since\n 2024.1\n",
+ "default": true
+ },
+ "SA5000": {
+ "type": "boolean",
+ "markdownDescription": "Assignment to nil map\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA5001": {
+ "type": "boolean",
+ "markdownDescription": "Deferring Close before checking for a possible error\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA5002": {
+ "type": "boolean",
+ "markdownDescription": "The empty for loop ('for {}') spins and can block the scheduler\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA5003": {
+ "type": "boolean",
+ "markdownDescription": "Defers in infinite loops will never execute\n\nDefers are scoped to the surrounding function, not the surrounding\nblock. In a function that never returns, i.e. one containing an\ninfinite loop, defers will never execute.\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA5004": {
+ "type": "boolean",
+ "markdownDescription": "'for { select { ...' with an empty default branch spins\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA5005": {
+ "type": "boolean",
+ "markdownDescription": "The finalizer references the finalized object, preventing garbage collection\n\nA finalizer is a function associated with an object that runs when the\ngarbage collector is ready to collect said object, that is when the\nobject is no longer referenced by anything.\n\nIf the finalizer references the object, however, it will always remain\nas the final reference to that object, preventing the garbage\ncollector from collecting the object. The finalizer will never run,\nand the object will never be collected, leading to a memory leak. That\nis why the finalizer should instead use its first argument to operate\non the object. That way, the number of references can temporarily go\nto zero before the object is being passed to the finalizer.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA5007": {
+ "type": "boolean",
+ "markdownDescription": "Infinite recursive call\n\nA function that calls itself recursively needs to have an exit\ncondition. Otherwise it will recurse forever, until the system runs\nout of memory.\n\nThis issue can be caused by simple bugs such as forgetting to add an\nexit condition. It can also happen \"on purpose\". Some languages have\ntail call optimization which makes certain infinite recursive calls\nsafe to use. Go, however, does not implement TCO, and as such a loop\nshould be used instead.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA5008": {
+ "type": "boolean",
+ "markdownDescription": "Invalid struct tag\n\nAvailable since\n 2019.2\n",
+ "default": true
+ },
+ "SA5010": {
+ "type": "boolean",
+ "markdownDescription": "Impossible type assertion\n\nSome type assertions can be statically proven to be\nimpossible. This is the case when the method sets of both\narguments of the type assertion conflict with each other, for\nexample by containing the same method with different\nsignatures.\n\nThe Go compiler already applies this check when asserting from an\ninterface value to a concrete type. If the concrete type misses\nmethods from the interface, or if function signatures don't match,\nthen the type assertion can never succeed.\n\nThis check applies the same logic when asserting from one interface to\nanother. If both interface types contain the same method but with\ndifferent signatures, then the type assertion can never succeed,\neither.\n\nAvailable since\n 2020.1\n",
+ "default": false
+ },
+ "SA5011": {
+ "type": "boolean",
+ "markdownDescription": "Possible nil pointer dereference\n\nA pointer is being dereferenced unconditionally, while\nalso being checked against nil in another place. This suggests that\nthe pointer may be nil and dereferencing it may panic. This is\ncommonly a result of improperly ordered code or missing return\nstatements. Consider the following examples:\n\n func fn(x *int) {\n fmt.Println(*x)\n\n // This nil check is equally important for the previous dereference\n if x != nil {\n foo(*x)\n }\n }\n\n func TestFoo(t *testing.T) {\n x := compute()\n if x == nil {\n t.Errorf(\"nil pointer received\")\n }\n\n // t.Errorf does not abort the test, so if x is nil, the next line will panic.\n foo(*x)\n }\n\nStaticcheck tries to deduce which functions abort control flow.\nFor example, it is aware that a function will not continue\nexecution after a call to panic or log.Fatal. However, sometimes\nthis detection fails, in particular in the presence of\nconditionals. Consider the following example:\n\n func Log(msg string, level int) {\n fmt.Println(msg)\n if level == levelFatal {\n os.Exit(1)\n }\n }\n\n func Fatal(msg string) {\n Log(msg, levelFatal)\n }\n\n func fn(x *int) {\n if x == nil {\n Fatal(\"unexpected nil pointer\")\n }\n fmt.Println(*x)\n }\n\nStaticcheck will flag the dereference of x, even though it is perfectly\nsafe. Staticcheck is not able to deduce that a call to\nFatal will exit the program. For the time being, the easiest\nworkaround is to modify the definition of Fatal like so:\n\n func Fatal(msg string) {\n Log(msg, levelFatal)\n panic(\"unreachable\")\n }\n\nWe also hard-code functions from common logging packages such as\nlogrus. Please file an issue if we're missing support for a\npopular package.\n\nAvailable since\n 2020.1\n",
+ "default": false
+ },
+ "SA5012": {
+ "type": "boolean",
+ "markdownDescription": "Passing odd-sized slice to function expecting even size\n\nSome functions that take slices as parameters expect the slices to have an even number of elements. \nOften, these functions treat elements in a slice as pairs. \nFor example, strings.NewReplacer takes pairs of old and new strings, \nand calling it with an odd number of elements would be an error.\n\nAvailable since\n 2020.2\n",
+ "default": false
+ },
+ "SA6000": {
+ "type": "boolean",
+ "markdownDescription": "Using regexp.Match or related in a loop, should use regexp.Compile\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA6001": {
+ "type": "boolean",
+ "markdownDescription": "Missing an optimization opportunity when indexing maps by byte slices\n\nMap keys must be comparable, which precludes the use of byte slices.\nThis usually leads to using string keys and converting byte slices to\nstrings.\n\nNormally, a conversion of a byte slice to a string needs to copy the data and\ncauses allocations. The compiler, however, recognizes m[string(b)] and\nuses the data of b directly, without copying it, because it knows that\nthe data can't change during the map lookup. This leads to the\ncounter-intuitive situation that\n\n k := string(b)\n println(m[k])\n println(m[k])\n\nwill be less efficient than\n\n println(m[string(b)])\n println(m[string(b)])\n\nbecause the first version needs to copy and allocate, while the second\none does not.\n\nFor some history on this optimization, check out commit\nf5f5a8b6209f84961687d993b93ea0d397f5d5bf in the Go repository.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA6002": {
+ "type": "boolean",
+ "markdownDescription": "Storing non-pointer values in sync.Pool allocates memory\n\nA sync.Pool is used to avoid unnecessary allocations and reduce the\namount of work the garbage collector has to do.\n\nWhen passing a value that is not a pointer to a function that accepts\nan interface, the value needs to be placed on the heap, which means an\nadditional allocation. Slices are a common thing to put in sync.Pools,\nand they're structs with 3 fields (length, capacity, and a pointer to\nan array). In order to avoid the extra allocation, one should store a\npointer to the slice instead.\n\nSee the comments on https://go-review.googlesource.com/c/go/+/24371\nthat discuss this problem.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA6003": {
+ "type": "boolean",
+ "markdownDescription": "Converting a string to a slice of runes before ranging over it\n\nYou may want to loop over the runes in a string. Instead of converting\nthe string to a slice of runes and looping over that, you can loop\nover the string itself. That is,\n\n for _, r := range s {}\n\nand\n\n for _, r := range []rune(s) {}\n\nwill yield the same values. The first version, however, will be faster\nand avoid unnecessary memory allocations.\n\nDo note that if you are interested in the indices, ranging over a\nstring and over a slice of runes will yield different indices. The\nfirst one yields byte offsets, while the second one yields indices in\nthe slice of runes.\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA6005": {
+ "type": "boolean",
+ "markdownDescription": "Inefficient string comparison with strings.ToLower or strings.ToUpper\n\nConverting two strings to the same case and comparing them like so\n\n if strings.ToLower(s1) == strings.ToLower(s2) {\n ...\n }\n\nis significantly more expensive than comparing them with\nstrings.EqualFold(s1, s2). This is due to memory usage as well as\ncomputational complexity.\n\nstrings.ToLower will have to allocate memory for the new strings, as\nwell as convert both strings fully, even if they differ on the very\nfirst byte. strings.EqualFold, on the other hand, compares the strings\none character at a time. It doesn't need to create two intermediate\nstrings and can return as soon as the first non-matching character has\nbeen found.\n\nFor a more in-depth explanation of this issue, see\nhttps://blog.digitalocean.com/how-to-efficiently-compare-strings-in-go/\n\nAvailable since\n 2019.2\n",
+ "default": true
+ },
+ "SA6006": {
+ "type": "boolean",
+ "markdownDescription": "Using io.WriteString to write []byte\n\nUsing io.WriteString to write a slice of bytes, as in\n\n io.WriteString(w, string(b))\n\nis both unnecessary and inefficient. Converting from []byte to string\nhas to allocate and copy the data, and we could simply use w.Write(b)\ninstead.\n\nAvailable since\n 2024.1\n",
+ "default": true
+ },
+ "SA9001": {
+ "type": "boolean",
+ "markdownDescription": "Defers in range loops may not run when you expect them to\n\nAvailable since\n 2017.1\n",
+ "default": false
+ },
+ "SA9002": {
+ "type": "boolean",
+ "markdownDescription": "Using a non-octal os.FileMode that looks like it was meant to be in octal.\n\nAvailable since\n 2017.1\n",
+ "default": true
+ },
+ "SA9003": {
+ "type": "boolean",
+ "markdownDescription": "Empty body in an if or else branch\n\nAvailable since\n 2017.1, non-default\n",
+ "default": false
+ },
+ "SA9004": {
+ "type": "boolean",
+ "markdownDescription": "Only the first constant has an explicit type\n\nIn a constant declaration such as the following:\n\n const (\n First byte = 1\n Second = 2\n )\n\nthe constant Second does not have the same type as the constant First.\nThis construct shouldn't be confused with\n\n const (\n First byte = iota\n Second\n )\n\nwhere First and Second do indeed have the same type. The type is only\npassed on when no explicit value is assigned to the constant.\n\nWhen declaring enumerations with explicit values it is therefore\nimportant not to write\n\n const (\n EnumFirst EnumType = 1\n EnumSecond = 2\n EnumThird = 3\n )\n\nThis discrepancy in types can cause various confusing behaviors and\nbugs.\n\n\nWrong type in variable declarations\n\nThe most obvious issue with such incorrect enumerations expresses\nitself as a compile error:\n\n package pkg\n\n const (\n EnumFirst uint8 = 1\n EnumSecond = 2\n )\n\n func fn(useFirst bool) {\n x := EnumSecond\n if useFirst {\n x = EnumFirst\n }\n }\n\nfails to compile with\n\n ./const.go:11:5: cannot use EnumFirst (type uint8) as type int in assignment\n\n\nLosing method sets\n\nA more subtle issue occurs with types that have methods and optional\ninterfaces. Consider the following:\n\n package main\n\n import \"fmt\"\n\n type Enum int\n\n func (e Enum) String() string {\n return \"an enum\"\n }\n\n const (\n EnumFirst Enum = 1\n EnumSecond = 2\n )\n\n func main() {\n fmt.Println(EnumFirst)\n fmt.Println(EnumSecond)\n }\n\nThis code will output\n\n an enum\n 2\n\nas EnumSecond has no explicit type, and thus defaults to int.\n\nAvailable since\n 2019.1\n",
+ "default": true
+ },
+ "SA9005": {
+ "type": "boolean",
+ "markdownDescription": "Trying to marshal a struct with no public fields nor custom marshaling\n\nThe encoding/json and encoding/xml packages only operate on exported\nfields in structs, not unexported ones. It is usually an error to try\nto (un)marshal structs that only consist of unexported fields.\n\nThis check will not flag calls involving types that define custom\nmarshaling behavior, e.g. via MarshalJSON methods. It will also not\nflag empty structs.\n\nAvailable since\n 2019.2\n",
+ "default": false
+ },
+ "SA9006": {
+ "type": "boolean",
+ "markdownDescription": "Dubious bit shifting of a fixed size integer value\n\nBit shifting a value past its size will always clear the value.\n\nFor instance:\n\n v := int8(42)\n v >>= 8\n\nwill always result in 0.\n\nThis check flags bit shifting operations on fixed size integer values only.\nThat is, int, uint and uintptr are never flagged to avoid potential false\npositives in somewhat exotic but valid bit twiddling tricks:\n\n // Clear any value above 32 bits if integers are more than 32 bits.\n func f(i int) int {\n v := i >> 32\n v = v << 32\n return i-v\n }\n\nAvailable since\n 2020.2\n",
+ "default": true
+ },
+ "SA9007": {
+ "type": "boolean",
+ "markdownDescription": "Deleting a directory that shouldn't be deleted\n\nIt is virtually never correct to delete system directories such as\n/tmp or the user's home directory. However, it can be fairly easy to\ndo by mistake, for example by mistakenly using os.TempDir instead\nof ioutil.TempDir, or by forgetting to add a suffix to the result\nof os.UserHomeDir.\n\nWriting\n\n d := os.TempDir()\n defer os.RemoveAll(d)\n\nin your unit tests will have a devastating effect on the stability of your system.\n\nThis check flags attempts at deleting the following directories:\n\n- os.TempDir\n- os.UserCacheDir\n- os.UserConfigDir\n- os.UserHomeDir\n\nAvailable since\n 2022.1\n",
+ "default": false
+ },
+ "SA9008": {
+ "type": "boolean",
+ "markdownDescription": "else branch of a type assertion is probably not reading the right value\n\nWhen declaring variables as part of an if statement (like in 'if\nfoo := ...; foo {'), the same variables will also be in the scope of\nthe else branch. This means that in the following example\n\n if x, ok := x.(int); ok {\n // ...\n } else {\n fmt.Printf(\"unexpected type %T\", x)\n }\n\nx in the else branch will refer to the x from x, ok\n:=; it will not refer to the x that is being type-asserted. The\nresult of a failed type assertion is the zero value of the type that\nis being asserted to, so x in the else branch will always have the\nvalue 0 and the type int.\n\nAvailable since\n 2022.1\n",
+ "default": false
+ },
+ "SA9009": {
+ "type": "boolean",
+ "markdownDescription": "Ineffectual Go compiler directive\n\nA potential Go compiler directive was found, but is ineffectual as it begins\nwith whitespace.\n\nAvailable since\n 2024.1\n",
+ "default": true
+ },
+ "ST1000": {
+ "type": "boolean",
+ "markdownDescription": "Incorrect or missing package comment\n\nPackages must have a package comment that is formatted according to\nthe guidelines laid out in\nhttps://go.dev/wiki/CodeReviewComments#package-comments.\n\nAvailable since\n 2019.1, non-default\n",
+ "default": false
+ },
+ "ST1001": {
+ "type": "boolean",
+ "markdownDescription": "Dot imports are discouraged\n\nDot imports that aren't in external test packages are discouraged.\n\nThe dot_import_whitelist option can be used to whitelist certain\nimports.\n\nQuoting Go Code Review Comments:\n\n> The import . form can be useful in tests that, due to circular\n> dependencies, cannot be made part of the package being tested:\n> \n> package foo_test\n> \n> import (\n> \"bar/testutil\" // also imports \"foo\"\n> . \"foo\"\n> )\n> \n> In this case, the test file cannot be in package foo because it\n> uses bar/testutil, which imports foo. So we use the import .\n> form to let the file pretend to be part of package foo even though\n> it is not. Except for this one case, do not use import . in your\n> programs. It makes the programs much harder to read because it is\n> unclear whether a name like Quux is a top-level identifier in the\n> current package or in an imported package.\n\nAvailable since\n 2019.1\n\nOptions\n dot_import_whitelist\n",
+ "default": false
+ },
+ "ST1003": {
+ "type": "boolean",
+ "markdownDescription": "Poorly chosen identifier\n\nIdentifiers, such as variable and package names, follow certain rules.\n\nSee the following links for details:\n\n- https://go.dev/doc/effective_go#package-names\n- https://go.dev/doc/effective_go#mixed-caps\n- https://go.dev/wiki/CodeReviewComments#initialisms\n- https://go.dev/wiki/CodeReviewComments#variable-names\n\nAvailable since\n 2019.1, non-default\n\nOptions\n initialisms\n",
+ "default": false
+ },
+ "ST1005": {
+ "type": "boolean",
+ "markdownDescription": "Incorrectly formatted error string\n\nError strings follow a set of guidelines to ensure uniformity and good\ncomposability.\n\nQuoting Go Code Review Comments:\n\n> Error strings should not be capitalized (unless beginning with\n> proper nouns or acronyms) or end with punctuation, since they are\n> usually printed following other context. That is, use\n> fmt.Errorf(\"something bad\") not fmt.Errorf(\"Something bad\"), so\n> that log.Printf(\"Reading %s: %v\", filename, err) formats without a\n> spurious capital letter mid-message.\n\nAvailable since\n 2019.1\n",
+ "default": false
+ },
+ "ST1006": {
+ "type": "boolean",
+ "markdownDescription": "Poorly chosen receiver name\n\nQuoting Go Code Review Comments:\n\n> The name of a method's receiver should be a reflection of its\n> identity; often a one or two letter abbreviation of its type\n> suffices (such as \"c\" or \"cl\" for \"Client\"). Don't use generic\n> names such as \"me\", \"this\" or \"self\", identifiers typical of\n> object-oriented languages that place more emphasis on methods as\n> opposed to functions. The name need not be as descriptive as that\n> of a method argument, as its role is obvious and serves no\n> documentary purpose. It can be very short as it will appear on\n> almost every line of every method of the type; familiarity admits\n> brevity. Be consistent, too: if you call the receiver \"c\" in one\n> method, don't call it \"cl\" in another.\n\nAvailable since\n 2019.1\n",
+ "default": false
+ },
+ "ST1008": {
+ "type": "boolean",
+ "markdownDescription": "A function's error value should be its last return value\n\nA function's error value should be its last return value.\n\nAvailable since\n 2019.1\n",
+ "default": false
+ },
+ "ST1011": {
+ "type": "boolean",
+ "markdownDescription": "Poorly chosen name for variable of type time.Duration\n\ntime.Duration values represent an amount of time, which is represented\nas a count of nanoseconds. An expression like 5 * time.Microsecond\nyields the value 5000. It is therefore not appropriate to suffix a\nvariable of type time.Duration with any time unit, such as Msec or\nMilli.\n\nAvailable since\n 2019.1\n",
+ "default": false
+ },
+ "ST1012": {
+ "type": "boolean",
+ "markdownDescription": "Poorly chosen name for error variable\n\nError variables that are part of an API should be called errFoo or\nErrFoo.\n\nAvailable since\n 2019.1\n",
+ "default": false
+ },
+ "ST1013": {
+ "type": "boolean",
+ "markdownDescription": "Should use constants for HTTP error codes, not magic numbers\n\nHTTP has a tremendous number of status codes. While some of those are\nwell known (200, 400, 404, 500), most of them are not. The net/http\npackage provides constants for all status codes that are part of the\nvarious specifications. It is recommended to use these constants\ninstead of hard-coding magic numbers, to vastly improve the\nreadability of your code.\n\nAvailable since\n 2019.1\n\nOptions\n http_status_code_whitelist\n",
+ "default": false
+ },
+ "ST1015": {
+ "type": "boolean",
+ "markdownDescription": "A switch's default case should be the first or last case\n\nAvailable since\n 2019.1\n",
+ "default": false
+ },
+ "ST1016": {
+ "type": "boolean",
+ "markdownDescription": "Use consistent method receiver names\n\nAvailable since\n 2019.1, non-default\n",
+ "default": false
+ },
+ "ST1017": {
+ "type": "boolean",
+ "markdownDescription": "Don't use Yoda conditions\n\nYoda conditions are conditions of the kind 'if 42 == x', where the\nliteral is on the left side of the comparison. These are a common\nidiom in languages in which assignment is an expression, to avoid bugs\nof the kind 'if (x = 42)'. In Go, which doesn't allow for this kind of\nbug, we prefer the more idiomatic 'if x == 42'.\n\nAvailable since\n 2019.2\n",
+ "default": false
+ },
+ "ST1018": {
+ "type": "boolean",
+ "markdownDescription": "Avoid zero-width and control characters in string literals\n\nAvailable since\n 2019.2\n",
+ "default": false
+ },
+ "ST1019": {
+ "type": "boolean",
+ "markdownDescription": "Importing the same package multiple times\n\nGo allows importing the same package multiple times, as long as\ndifferent import aliases are being used. That is, the following\nbit of code is valid:\n\n import (\n \"fmt\"\n fumpt \"fmt\"\n format \"fmt\"\n _ \"fmt\"\n )\n\nHowever, this is very rarely done on purpose. Usually, it is a\nsign of code that got refactored, accidentally adding duplicate\nimport statements. It is also a rarely known feature, which may\ncontribute to confusion.\n\nDo note that sometimes, this feature may be used\nintentionally (see for example\nhttps://github.com/golang/go/commit/3409ce39bfd7584523b7a8c150a310cea92d879d)\n– if you want to allow this pattern in your code base, you're\nadvised to disable this check.\n\nAvailable since\n 2020.1\n",
+ "default": false
+ },
+ "ST1020": {
+ "type": "boolean",
+ "markdownDescription": "The documentation of an exported function should start with the function's name\n\nDoc comments work best as complete sentences, which\nallow a wide variety of automated presentations. The first sentence\nshould be a one-sentence summary that starts with the name being\ndeclared.\n\nIf every doc comment begins with the name of the item it describes,\nyou can use the doc subcommand of the go tool and run the output\nthrough grep.\n\nSee https://go.dev/doc/effective_go#commentary for more\ninformation on how to write good documentation.\n\nAvailable since\n 2020.1, non-default\n",
+ "default": false
+ },
+ "ST1021": {
+ "type": "boolean",
+ "markdownDescription": "The documentation of an exported type should start with type's name\n\nDoc comments work best as complete sentences, which\nallow a wide variety of automated presentations. The first sentence\nshould be a one-sentence summary that starts with the name being\ndeclared.\n\nIf every doc comment begins with the name of the item it describes,\nyou can use the doc subcommand of the go tool and run the output\nthrough grep.\n\nSee https://go.dev/doc/effective_go#commentary for more\ninformation on how to write good documentation.\n\nAvailable since\n 2020.1, non-default\n",
+ "default": false
+ },
+ "ST1022": {
+ "type": "boolean",
+ "markdownDescription": "The documentation of an exported variable or constant should start with variable's name\n\nDoc comments work best as complete sentences, which\nallow a wide variety of automated presentations. The first sentence\nshould be a one-sentence summary that starts with the name being\ndeclared.\n\nIf every doc comment begins with the name of the item it describes,\nyou can use the doc subcommand of the go tool and run the output\nthrough grep.\n\nSee https://go.dev/doc/effective_go#commentary for more\ninformation on how to write good documentation.\n\nAvailable since\n 2020.1, non-default\n",
+ "default": false
+ },
+ "ST1023": {
+ "type": "boolean",
+ "markdownDescription": "Redundant type in variable declaration\n\nAvailable since\n 2021.1, non-default\n",
+ "default": false
+ },
"appends": {
"type": "boolean",
"markdownDescription": "check for missing values after append\n\nThis checker reports calls to append that pass\nno values to be appended to the slice.\n\n\ts := []string{\"a\", \"b\", \"c\"}\n\t_ = append(s)\n\nSuch calls are always no-ops and often indicate an\nunderlying mistake.",
@@ -2199,7 +2985,7 @@
},
"gofix": {
"type": "boolean",
- "markdownDescription": "apply fixes based on go:fix comment directives\n\nThe gofix analyzer inlines functions and constants that are marked for inlining.",
+ "markdownDescription": "apply fixes based on go:fix comment directives\n\nThe gofix analyzer inlines functions and constants that are marked for inlining.\n\n## Functions\n\nGiven a function that is marked for inlining, like this one:\n\n\t//go:fix inline\n\tfunc Square(x int) int { return Pow(x, 2) }\n\nthis analyzer will recommend that calls to the function elsewhere, in the same\nor other packages, should be inlined.\n\nInlining can be used to move off of a deprecated function:\n\n\t// Deprecated: prefer Pow(x, 2).\n\t//go:fix inline\n\tfunc Square(x int) int { return Pow(x, 2) }\n\nIt can also be used to move off of an obsolete package,\nas when the import path has changed or a higher major version is available:\n\n\tpackage pkg\n\n\timport pkg2 \"pkg/v2\"\n\n\t//go:fix inline\n\tfunc F() { pkg2.F(nil) }\n\nReplacing a call pkg.F() by pkg2.F(nil) can have no effect on the program,\nso this mechanism provides a low-risk way to update large numbers of calls.\nWe recommend, where possible, expressing the old API in terms of the new one\nto enable automatic migration.\n\nThe inliner takes care to avoid behavior changes, even subtle ones,\nsuch as changes to the order in which argument expressions are\nevaluated. When it cannot safely eliminate all parameter variables,\nit may introduce a \"binding declaration\" of the form\n\n\tvar params = args\n\nto evaluate argument expressions in the correct order and bind them to\nparameter variables. Since the resulting code transformation may be\nstylistically suboptimal, such inlinings may be disabled by specifying\nthe -gofix.allow_binding_decl=false flag to the analyzer driver.\n\n(In cases where it is not safe to \"reduce\" a call—that is, to replace\na call f(x) by the body of function f, suitably substituted—the\ninliner machinery is capable of replacing f by a function literal,\nfunc(){...}(). However, the gofix analyzer discards all such\n\"literalizations\" unconditionally, again on grounds of style.)\n\n## Constants\n\nGiven a constant that is marked for inlining, like this one:\n\n\t//go:fix inline\n\tconst Ptr = Pointer\n\nthis analyzer will recommend that uses of Ptr should be replaced with Pointer.\n\nAs with functions, inlining can be used to replace deprecated constants and\nconstants in obsolete packages.\n\nA constant definition can be marked for inlining only if it refers to another\nnamed constant.\n\nThe \"//go:fix inline\" comment must appear before a single const declaration on its own,\nas above; before a const declaration that is part of a group, as in this case:\n\n\tconst (\n\t C = 1\n\t //go:fix inline\n\t Ptr = Pointer\n\t)\n\nor before a group, applying to every constant in the group:\n\n\t//go:fix inline\n\tconst (\n\t\tPtr = Pointer\n\t Val = Value\n\t)\n\nThe proposal https://go.dev/issue/32816 introduces the \"//go:fix\" directives.\n\nYou can use this (officially unsupported) command to apply gofix fixes en masse:\n\n\t$ go run golang.org/x/tools/internal/gofix/cmd/gofix@latest -test ./...\n\n(Do not use \"go get -tool\" to add gopls as a dependency of your\nmodule; gopls commands must be built from their release branch.)",
"default": true
},
"hostport": {
@@ -2232,9 +3018,14 @@
"markdownDescription": "check cancel func returned by context.WithCancel is called\n\nThe cancellation function returned by context.WithCancel, WithTimeout,\nWithDeadline and variants such as WithCancelCause must be called,\nor the new context will remain live until its parent context is cancelled.\n(The background context is never cancelled.)",
"default": true
},
+ "maprange": {
+ "type": "boolean",
+ "markdownDescription": "checks for unnecessary calls to maps.Keys and maps.Values in range statements\n\nConsider a loop written like this:\n\n\tfor val := range maps.Values(m) {\n\t\tfmt.Println(val)\n\t}\n\nThis should instead be written without the call to maps.Values:\n\n\tfor _, val := range m {\n\t\tfmt.Println(val)\n\t}\n\ngolang.org/x/exp/maps returns slices for Keys/Values instead of iterators,\nbut unnecessary calls should similarly be removed:\n\n\tfor _, key := range maps.Keys(m) {\n\t\tfmt.Println(key)\n\t}\n\nshould be rewritten as:\n\n\tfor key := range m {\n\t\tfmt.Println(key)\n\t}",
+ "default": true
+ },
"modernize": {
"type": "boolean",
- "markdownDescription": "simplify code by using modern constructs\n\nThis analyzer reports opportunities for simplifying and clarifying\nexisting code by using more modern features of Go, such as:\n\n - replacing an if/else conditional assignment by a call to the\n built-in min or max functions added in go1.21;\n - replacing sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] }\n by a call to slices.Sort(s), added in go1.21;\n - replacing interface{} by the 'any' type added in go1.18;\n - replacing append([]T(nil), s...) by slices.Clone(s) or\n slices.Concat(s), added in go1.21;\n - replacing a loop around an m[k]=v map update by a call\n to one of the Collect, Copy, Clone, or Insert functions\n from the maps package, added in go1.21;\n - replacing []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...),\n added in go1.19;\n - replacing uses of context.WithCancel in tests with t.Context, added in\n go1.24;\n - replacing omitempty by omitzero on structs, added in go1.24;\n - replacing append(s[:i], s[i+1]...) by slices.Delete(s, i, i+1),\n added in go1.21\n - replacing a 3-clause for i := 0; i < n; i++ {} loop by\n for i := range n {}, added in go1.22;\n - replacing Split in \"for range strings.Split(...)\" by go1.24's\n more efficient SplitSeq;\n\nTo apply all modernization fixes en masse, you can use the\nfollowing command:\n\n\t$ go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -test ./...\n\nIf the tool warns of conflicting fixes, you may need to run it more\nthan once until it has applied all fixes cleanly. This command is\nnot an officially supported interface and may change in the future.",
+ "markdownDescription": "simplify code by using modern constructs\n\nThis analyzer reports opportunities for simplifying and clarifying\nexisting code by using more modern features of Go and its standard\nlibrary.\n\nEach diagnostic provides a fix. Our intent is that these fixes may\nbe safely applied en masse without changing the behavior of your\nprogram. In some cases the suggested fixes are imperfect and may\nlead to (for example) unused imports or unused local variables,\ncausing build breakage. However, these problems are generally\ntrivial to fix. We regard any modernizer whose fix changes program\nbehavior to have a serious bug and will endeavor to fix it.\n\nTo apply all modernization fixes en masse, you can use the\nfollowing command:\n\n\t$ go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...\n\n(Do not use \"go get -tool\" to add gopls as a dependency of your\nmodule; gopls commands must be built from their release branch.)\n\nIf the tool warns of conflicting fixes, you may need to run it more\nthan once until it has applied all fixes cleanly. This command is\nnot an officially supported interface and may change in the future.\n\nChanges produced by this tool should be reviewed as usual before\nbeing merged. In some cases, a loop may be replaced by a simple\nfunction call, causing comments within the loop to be discarded.\nHuman judgment may be required to avoid losing comments of value.\n\nEach diagnostic reported by modernize has a specific category. (The\ncategories are listed below.) Diagnostics in some categories, such\nas \"efaceany\" (which replaces \"interface{}\" with \"any\" where it is\nsafe to do so) are particularly numerous. It may ease the burden of\ncode review to apply fixes in two passes, the first change\nconsisting only of fixes of category \"efaceany\", the second\nconsisting of all others. This can be achieved using the -category flag:\n\n\t$ modernize -category=efaceany -fix -test ./...\n\t$ modernize -category=-efaceany -fix -test ./...\n\nCategories of modernize diagnostic:\n\n - forvar: remove x := x variable declarations made unnecessary by the new semantics of loops in go1.22.\n\n - slicescontains: replace 'for i, elem := range s { if elem == needle { ...; break }'\n by a call to slices.Contains, added in go1.21.\n\n - minmax: replace an if/else conditional assignment by a call to\n the built-in min or max functions added in go1.21.\n\n - sortslice: replace sort.Slice(x, func(i, j int) bool) { return s[i] < s[j] }\n by a call to slices.Sort(s), added in go1.21.\n\n - efaceany: replace interface{} by the 'any' type added in go1.18.\n\n - mapsloop: replace a loop around an m[k]=v map update by a call\n to one of the Collect, Copy, Clone, or Insert functions from\n the maps package, added in go1.21.\n\n - fmtappendf: replace []byte(fmt.Sprintf...) by fmt.Appendf(nil, ...),\n added in go1.19.\n\n - testingcontext: replace uses of context.WithCancel in tests\n with t.Context, added in go1.24.\n\n - omitzero: replace omitempty by omitzero on structs, added in go1.24.\n\n - bloop: replace \"for i := range b.N\" or \"for range b.N\" in a\n benchmark with \"for b.Loop()\", and remove any preceding calls\n to b.StopTimer, b.StartTimer, and b.ResetTimer.\n\n B.Loop intentionally defeats compiler optimizations such as\n inlining so that the benchmark is not entirely optimized away.\n Currently, however, it may cause benchmarks to become slower\n in some cases due to increased allocation; see\n https://go.dev/issue/73137.\n\n - rangeint: replace a 3-clause \"for i := 0; i < n; i++\" loop by\n \"for i := range n\", added in go1.22.\n\n - stringsseq: replace Split in \"for range strings.Split(...)\" by go1.24's\n more efficient SplitSeq, or Fields with FieldSeq.\n\n - stringscutprefix: replace some uses of HasPrefix followed by TrimPrefix with CutPrefix,\n added to the strings package in go1.20.\n\n - waitgroup: replace old complex usages of sync.WaitGroup by less complex WaitGroup.Go method in go1.25.",
"default": true
},
"nilfunc": {
@@ -2262,6 +3053,11 @@
"markdownDescription": "check consistency of Printf format strings and arguments\n\nThe check applies to calls of the formatting functions such as\n[fmt.Printf] and [fmt.Sprintf], as well as any detected wrappers of\nthose functions such as [log.Printf]. It reports a variety of\nmistakes such as syntax errors in the format string and mismatches\n(of number and type) between the verbs and their arguments.\n\nSee the documentation of the fmt package for the complete set of\nformat operators and their operand types.",
"default": true
},
+ "recursiveiter": {
+ "type": "boolean",
+ "markdownDescription": "check for inefficient recursive iterators\n\nThis analyzer reports when a function that returns an iterator\n(iter.Seq or iter.Seq2) calls itself as the operand of a range\nstatement, as this is inefficient.\n\nWhen implementing an iterator (e.g. iter.Seq[T]) for a recursive\ndata type such as a tree or linked list, it is tempting to\nrecursively range over the iterator for each child element.\n\nHere's an example of a naive iterator over a binary tree:\n\n\ttype tree struct {\n\t\tvalue int\n\t\tleft, right *tree\n\t}\n\n\tfunc (t *tree) All() iter.Seq[int] {\n\t\treturn func(yield func(int) bool) {\n\t\t\tif t != nil {\n\t\t\t\tfor elem := range t.left.All() { // \"inefficient recursive iterator\"\n\t\t\t\t\tif !yield(elem) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif !yield(t.value) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfor elem := range t.right.All() { // \"inefficient recursive iterator\"\n\t\t\t\t\tif !yield(elem) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\nThough it correctly enumerates the elements of the tree, it hides a\nsignificant performance problem--two, in fact. Consider a balanced\ntree of N nodes. Iterating the root node will cause All to be\ncalled once on every node of the tree. This results in a chain of\nnested active range-over-func statements when yield(t.value) is\ncalled on a leaf node.\n\nThe first performance problem is that each range-over-func\nstatement must typically heap-allocate a variable, so iteration of\nthe tree allocates as many variables as there are elements in the\ntree, for a total of O(N) allocations, all unnecessary.\n\nThe second problem is that each call to yield for a leaf of the\ntree causes each of the enclosing range loops to receive a value,\nwhich they then immediately pass on to their respective yield\nfunction. This results in a chain of log(N) dynamic yield calls per\nelement, a total of O(N*log N) dynamic calls overall, when only\nO(N) are necessary.\n\nA better implementation strategy for recursive iterators is to\nfirst define the \"every\" operator for your recursive data type,\nwhere every(f) reports whether f(x) is true for every element x in\nthe data type. For our tree, the every function would be:\n\n\tfunc (t *tree) every(f func(int) bool) bool {\n\t\treturn t == nil ||\n\t\t\tt.left.every(f) && f(t.value) && t.right.every(f)\n\t}\n\nThen the iterator can be simply expressed as a trivial wrapper\naround this function:\n\n\tfunc (t *tree) All() iter.Seq[int] {\n\t\treturn func(yield func(int) bool) {\n\t\t\t_ = t.every(yield)\n\t\t}\n\t}\n\nIn effect, tree.All computes whether yield returns true for each\nelement, short-circuiting if it every returns false, then discards\nthe final boolean result.\n\nThis has much better performance characteristics: it makes one\ndynamic call per element of the tree, and it doesn't heap-allocate\nanything. It is also clearer.",
+ "default": true
+ },
"shadow": {
"type": "boolean",
"markdownDescription": "check for possible unintended shadowing of variables\n\nThis analyzer check for shadowed variables.\nA shadowed variable is a variable declared in an inner scope\nwith the same name and type as a variable in an outer scope,\nand where the outer variable is mentioned after the inner one\nis declared.\n\n(This definition can be refined; the module generates too many\nfalse positives and is not yet enabled by default.)\n\nFor example:\n\n\tfunc BadRead(f *os.File, buf []byte) error {\n\t\tvar err error\n\t\tfor {\n\t\t\tn, err := f.Read(buf) // shadows the function variable 'err'\n\t\t\tif err != nil {\n\t\t\t\tbreak // causes return of wrong value\n\t\t\t}\n\t\t\tfoo(buf)\n\t\t}\n\t\treturn err\n\t}",
@@ -2395,6 +3191,33 @@
"default": true,
"scope": "resource"
},
+ "ui.diagnostic.annotations": {
+ "type": "object",
+ "markdownDescription": "annotations specifies the various kinds of compiler\noptimization details that should be reported as diagnostics\nwhen enabled for a package by the \"Toggle compiler\noptimization details\" (`gopls.gc_details`) command.\n\n(Some users care only about one kind of annotation in their\nprofiling efforts. More importantly, in large packages, the\nnumber of annotations can sometimes overwhelm the user\ninterface and exceed the per-file diagnostic limit.)\n\nTODO(adonovan): rename this field to CompilerOptDetail.\n",
+ "scope": "resource",
+ "properties": {
+ "bounds": {
+ "type": "boolean",
+ "markdownDescription": "`\"bounds\"` controls bounds checking diagnostics.\n",
+ "default": true
+ },
+ "escape": {
+ "type": "boolean",
+ "markdownDescription": "`\"escape\"` controls diagnostics about escape choices.\n",
+ "default": true
+ },
+ "inline": {
+ "type": "boolean",
+ "markdownDescription": "`\"inline\"` controls diagnostics about inlining choices.\n",
+ "default": true
+ },
+ "nil": {
+ "type": "boolean",
+ "markdownDescription": "`\"nil\"` controls nil checks.\n",
+ "default": true
+ }
+ }
+ },
"ui.diagnostic.diagnosticsDelay": {
"type": "string",
"markdownDescription": "(Advanced) diagnosticsDelay controls the amount of time that gopls waits\nafter the most recent file modification before computing deep diagnostics.\nSimple diagnostics (parsing and type-checking) are always run immediately\non recently modified packages.\n\nThis option must be set to a valid duration string, for example `\"250ms\"`.\n",
@@ -2417,7 +3240,13 @@
},
"ui.diagnostic.staticcheck": {
"type": "boolean",
- "markdownDescription": "(Experimental) staticcheck enables additional analyses from staticcheck.io.\nThese analyses are documented on\n[Staticcheck's website](https://staticcheck.io/docs/checks/).\n",
+ "markdownDescription": "(Experimental) staticcheck configures the default set of analyses staticcheck.io.\nThese analyses are documented on\n[Staticcheck's website](https://staticcheck.io/docs/checks/).\n\nThe \"staticcheck\" option has three values:\n- false: disable all staticcheck analyzers\n- true: enable all staticcheck analyzers\n- unset: enable a subset of staticcheck analyzers\n selected by gopls maintainers for runtime efficiency\n and analytic precision.\n\nRegardless of this setting, individual analyzers can be\nselectively enabled or disabled using the `analyses` setting.\n",
+ "default": false,
+ "scope": "resource"
+ },
+ "ui.diagnostic.staticcheckProvided": {
+ "type": "boolean",
+ "markdownDescription": "(Experimental) ",
"default": false,
"scope": "resource"
},
diff --git a/extension/src/commands/startLanguageServer.ts b/extension/src/commands/startLanguageServer.ts
index b61f89f6bb..608fa8830f 100644
--- a/extension/src/commands/startLanguageServer.ts
+++ b/extension/src/commands/startLanguageServer.ts
@@ -11,7 +11,6 @@ import { GoExtensionContext } from '../context';
import { outputChannel, updateLanguageServerIconGoStatusBar } from '../goStatus';
import {
buildLanguageClient,
- buildLanguageClientOption,
buildLanguageServerConfig,
errorKind,
RestartReason,
@@ -85,7 +84,7 @@ export const startLanguageServer: CommandFactory = (ctx, goCtx) => {
return;
}
- goCtx.languageClient = await buildLanguageClient(goCtx, buildLanguageClientOption(goCtx, cfg));
+ goCtx.languageClient = await buildLanguageClient(goCtx, cfg);
await goCtx.languageClient.start();
goCtx.serverInfo = toServerInfo(goCtx.languageClient.initializeResult);
goCtx.telemetryService = new TelemetryService(
diff --git a/extension/src/config.ts b/extension/src/config.ts
index 5519e3b3fd..32eaddc88e 100644
--- a/extension/src/config.ts
+++ b/extension/src/config.ts
@@ -37,7 +37,7 @@ export class ExtensionInfo {
readonly appName: string;
/** True if the extension runs in preview mode (e.g. Nightly, prerelease) */
readonly isPreview: boolean;
- /** True if the extension runs in well-kwnon cloud IDEs */
+ /** True if the extension runs in well-known cloud IDEs */
readonly isInCloudIDE: boolean;
constructor() {
diff --git a/extension/src/debugAdapter/README.md b/extension/src/debugAdapter/README.md
index c24d4f8a74..438cd9470c 100644
--- a/extension/src/debugAdapter/README.md
+++ b/extension/src/debugAdapter/README.md
@@ -1,3 +1,3 @@
# Debug Adapter
-See the [contribution documentation](../../docs/contributing.md) to learn how to develop the debug adapter.
+See the [contribution documentation](../../../docs/contributing.md) to learn how to develop the debug adapter.
diff --git a/extension/src/export.d.ts b/extension/src/export.d.ts
index 5a4e0a8b94..d63d2eb253 100644
--- a/extension/src/export.d.ts
+++ b/extension/src/export.d.ts
@@ -10,7 +10,20 @@ export interface CommandInvocation {
binPath: string;
}
+/**
+ * The API we expose to other extensions.
+ *
+ * @example
+ * const Go = await vscode.extensions
+ * .getExtension('golang.go')
+ * .then(x => x.activate());
+ *
+ * console.log(`Go extension is a ${Go.isPreview ? 'preview' : 'release'} version`);
+ */
export interface ExtensionAPI {
+ /** True if the extension is running in preview mode (e.g. prerelease) */
+ isPreview: boolean;
+
settings: {
/**
* Returns the execution command corresponding to the specified resource, taking into account
diff --git a/extension/src/extensionAPI.ts b/extension/src/extensionAPI.ts
index accc455dd0..4ae11f8939 100644
--- a/extension/src/extensionAPI.ts
+++ b/extension/src/extensionAPI.ts
@@ -6,8 +6,11 @@
import { Uri } from 'vscode';
import { CommandInvocation, ExtensionAPI } from './export';
import { getBinPathWithExplanation } from './util';
+import { extensionInfo } from './config';
const api: ExtensionAPI = {
+ isPreview: extensionInfo.isPreview,
+
settings: {
getExecutionCommand(toolName: string, resource?: Uri): CommandInvocation | undefined {
const { binPath } = getBinPathWithExplanation(toolName, true, resource);
diff --git a/extension/src/goDebugConfiguration.ts b/extension/src/goDebugConfiguration.ts
index aa57a06317..243a4a29a3 100644
--- a/extension/src/goDebugConfiguration.ts
+++ b/extension/src/goDebugConfiguration.ts
@@ -33,6 +33,7 @@ import { parseEnvFiles } from './utils/envUtils';
import { resolveHomeDir } from './utils/pathUtils';
import { createRegisterCommand } from './commands';
import { GoExtensionContext } from './context';
+import { spawn } from 'child_process';
let dlvDAPVersionChecked = false;
@@ -182,12 +183,23 @@ export class GoDebugConfigurationProvider implements vscode.DebugConfigurationPr
debugConfiguration['debugAdapter'] = dlvConfig['debugAdapter'];
}
}
- // If neither launch.json nor settings.json gave us the debugAdapter value, we go with the default
- // from package.json (dlv-dap) unless this is remote attach with a stable release.
+
+ // If neither launch.json nor settings.json gave us the debugAdapter, we go with the default from pacakge.json (dlv-dap) for all modes except 'remote'.
+ // For remote we will use 'dlv-dap' if we can call 'dlv substitute-path-guess-helper' or 'legacy' otherwise.
if (!debugConfiguration['debugAdapter']) {
+ // set dlv-dap by default
debugConfiguration['debugAdapter'] = defaultConfig.debugAdapter.default;
- if (debugConfiguration['mode'] === 'remote' && !extensionInfo.isPreview) {
- debugConfiguration['debugAdapter'] = 'legacy';
+ if (debugConfiguration['mode'] === 'remote') {
+ const substitutePathGuess = await this.guessSubstitutePath();
+ if (substitutePathGuess === null) {
+ if (!extensionInfo.isPreview) {
+ // can't guess substitute path and isPreview isn't set, fall back to legacy.
+ debugConfiguration['debugAdapter'] = 'legacy';
+ }
+ } else {
+ debugConfiguration['debugAdapter'] = defaultConfig.debugAdapter.default;
+ debugConfiguration['guessSubstitutePath'] = substitutePathGuess;
+ }
}
}
if (debugConfiguration['debugAdapter'] === 'dlv-dap') {
@@ -372,6 +384,43 @@ export class GoDebugConfigurationProvider implements vscode.DebugConfigurationPr
return debugConfiguration;
}
+ /**
+ * Calls `dlv substitute-path-guess-helper` to get a set of parameters used by Delve to guess the substitutePath configuration after also examining the executable.
+ *
+ * Exported for testing.
+ *
+ * See https://github.com/go-delve/delve/blob/d5fb3bee427202f0d4b1683bf743bfd2adb41757/service/debugger/debugger.go#L2466
+ */
+ public async guessSubstitutePath(): Promise