---
title: Staticcheck 2019.2 release notes
linkTitle: 2019.2
weight: -3
---


## Performance improvements {#performance}

Staticcheck 2019.2 brings major performance improvements and a
reduction in memory usage.

Staticcheck has been redesigned to only keep those packages in memory that are actively being processed.
This allows for much larger workspaces to be checked in one go.
While previously it may have been necessary to split a list of packages into many invocations of `staticcheck`,
this is now handled intelligently and efficiently by Staticcheck itself.

In particular, memory usage is now closely tied to parallelism:
having more CPU cores available allows for more packages to be processed in parallel,
which increases the number of packages held in memory at any one time.
Not only does this make good use of available resources –
systems with more CPU cores also tend to have more memory available –
it also exposes a single, easy to use knob for trading execution time for memory use.
By setting `GOMAXPROCS` to a value lower than the number of available cores,
memory usage of Staticcheck will be reduced, at the cost of taking longer to complete.

We've observed reductions in memory usage of 2x to 8x when checking large code bases.

<table class="table">
  <thead>
    <tr>
      <th>Package</th>
      <th>2019.1.1</th>
      <th>2019.2¹</th>
      <th>Change</th>
    </tr>
  </thead>

  <tr>
    <td>net/http</td>
    <td>3.543 s / 677 MB</td>
    <td>3.747 s / 254 MB</td>
    <td>+5.76% / -62.48%</td>
  </tr>

  <tr>
    <td>strconv</td>
    <td>1.628 s / 294 MB</td>
    <td>1.678 s / 118 MB</td>
    <td>+3.07% / -59.86%</td>
  </tr>

  <tr>
    <td>image/color</td>
    <td>1.304 s / 225 MB</td>
    <td>1.702 s / 138 MB</td>
    <td>+30.52% / -38.67%</td>
  </tr>

  <tr>
    <td>std</td>
    <td>26.234 s / 3987 MB</td>
    <td>19.444 s / 1054 MB</td>
    <td>-25.88% / -73.56%</td>
  </tr>

  <tr>
    <td>github.com/cockroachdb/cockroach/pkg/...</td>
    <td>88.644 s / 15959 MB</td>
    <td>93.798 s / 4156 MB</td>
    <td>+5.81% / -73.96%</td>
  </tr>

  <tfoot>
    <tr>
      <td colspan="4">
        ¹: The fact cache was empty for all benchmarks.
      </td>
    </tr>
  </tfoot>
</table>

In addition, Staticcheck now employs caching to speed up repeated checking of packages.
In the past, when checking a package, all of its dependencies had to be loaded from source and analyzed.
Now, we can make use of Go's build cache, as well as cache our own analysis facts.
This makes Staticcheck behave a lot more like `go build`, where repeated builds are much faster.

| Package                                  | Uncached           | Cached             | Change                 |
|------------------------------------------|--------------------|--------------------|------------------------|
| net/http                                 | 3.747 s / 254 MB   | 1.545 s / 195 MB   | -58.77% / -23.23%      |
| strconv                                  | 1.678 s / 118 MB   | 0.495 s / 57 MB    | -70.5% / -51.69%       |
| image/color                              | 1.702 s / 138 MB   | 0.329 s / 31 MB    | -80.67% / -77.54%      |
| std                                      | 19.444 s / 1054 MB | 15.099 s / 887 MB  | -22.35% / -15.84%      |
| github.com/cockroachdb/cockroach/pkg/... | 93.798 s / 4156 MB | 47.205 s / 2516 MB | -49.67% / -39.46%      |

This combination of improvements not only compensates for the
increased memory usage that 2019.1 introduced, it also brings the
memory usage and execution times way below the levels of those seen in the
2017.2 release, which had previously been our most efficient
release.

It should be noted that all of these improvements are part of the `staticcheck` command itself, not the individual checks.
Tools such as golangci-lint will have to replicate our efforts to benefit from these improvements.

## The go/analysis framework {#go-analysis}

Part of the redesign of Staticcheck involved porting our code to the [go/analysis](https://godoc.org/golang.org/x/tools/go/analysis) framework.

The go/analysis framework is a framework for writing static analysis tools such as Staticcheck and go vet.
It provides an API that enables interoperability between different analyses and analysis drivers – drivers being the code that actually executes analyses.
The intention is that any driver can trivially use any analysis that is implemented using go/analysis.

With the exception of {{< check "U1000" >}}, all of our checks are now go/analysis analyses. Furthermore, the `staticcheck` command is now a go/analysis driver.

With our move to this framework, we enable other drivers to reuse our checks without having to patch them.
This should be of particular interest to golangci-lint, which previously took to patching Staticcheck, sometimes in subtly incorrect ways.
Another high-profile go/analysis driver is gopls, the Go language server. It will now be much easier for gopls to use Staticcheck to analyze code, should it so desire.

Theoretically it would also allow us to use third-party analyses as part of Staticcheck.
Due to quality control reasons, however, we will likely refrain from doing so.
Nonetheless it would be trivial for users to maintain internal forks of `cmd/staticcheck` that use third-party analyses.

## Improvements to the CLI {#cli}

We've made several minor improvements to the command-line interface of `staticcheck` that improve usability and debuggability.

### SIGINFO handler {#cli-siginfo}

Upon receiving the SIGINFO signal – or SIGUSR1 on platforms that lack
SIGINFO – Staticcheck will dump statistics, such as the current phase
and how many packages are left to analyze.

```text
Packages: 37/619 initial, 38/1011 total; Workers: 8/8; Problems: 73
```

### Explaining checks {#cli-explain}

Using the new `-explain` flag, a check's documentation can be displayed right in the terminal,
eliminating the need to visit the website.

```text
$ staticcheck -explain S1007
Simplify regular expression by using raw string literal

Raw string literals use ` instead of " 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
```

### -debug.version {#cli-debug-version}

The `-debug.version` flag causes `staticcheck` to print
detailed version information, such as the Go version used to compile
it, as well as the versions of all dependencies if built using Go
modules. This feature is intended for debugging issues, and we will
ask for its output from users who file issues.

```text
$ staticcheck -debug.version
staticcheck (devel, v0.0.0-20190602125119-5a4a2f4a438d)

Compiled with Go version: go1.12.5
Main module:
	honnef.co/go/tools@v0.0.0-20190602125119-5a4a2f4a438d (sum: h1:U5vSGN1Bjr0Yd/4pRcp8iRUCs3S5TIPzoAeTEFV2aiU=)
Dependencies:
	github.com/BurntSushi/toml@v0.3.1 (sum: h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=)
	golang.org/x/tools@v0.0.0-20190530171427-2b03ca6e44eb (sum: h1:mnQlcVx8Qq8L70HV0DxUGuiuAtiEHTwF1gYJE/EL9nU=)
```

### Enabling unused's whole program mode {#cli-unused}

When we merged `unused` into `staticcheck`, we lost the ability to specify the `-exported` flag to report unused exported identifiers.
Staticcheck 2019.2 restores this ability with the new `-unused.whole-program` flag.

### Range information in diagnostics {#cli-ranges}

Many of our checks now emit `[start, end]` ranges for findings instead of just positions.
These ranges can be accessed via the `json` output formatter, as well as by using `go/analysis.Diagnostic` directly, such as in gopls.

Note that not all checks are able to emit range information.

## Installing Staticcheck as a module {#module}

As part of the 2019.2 release, we've turned Staticcheck into a Go module.
From now on, if using Go modules, you can install specific versions of Staticcheck with `go get honnef.co/go/tools/cmd/staticcheck@<version>`,
though do note that older releases do not have a `go.mod` file.
You can still download them as modules, but Go will record indirect dependencies in the main module's `go.mod` file, and no minimum versions are specified.

Staticcheck will not use Semantic Versioning for its releases.
It is our belief that Semver is a poor fit for applications and is more suited towards libraries.
For example, almost every release of Staticcheck has backwards incompatible changes to some APIs that aren't meant for public consumption,
but which we expose nevertheless so that tinkerers can use them.

However, we use so-called _pre-release versions_ of the form `v0.0.0-2019.2`.
These allow us to embed our versioning scheme in that of Semver, with correct sorting and updating of versions.
Furthermore, these versions ensure that `go get ...`,
if not specifying an explicit version (that is, if using the query `latest`),
will install the latest released version of Staticcheck and not the master branch.

While you can use these pre-release version numbers directly, you can also use the canonical versions of the form `2019.2` instead.
The Go tool will automatically translate these versions to the appropriate pre-releases.

To install the master branch, use `go get honnef.co/go/tools/cmd/staticcheck@master`

## Removal of deprecated functionality {#deprecated}

Staticcheck 2019.1 deprecated the `unused`, `gosimple`, and `megacheck`
utilities, as they have been merged into `staticcheck`. Furthermore, it deprecated the `-ignore` flag,
which has been replaced by [linter directives]({{< relref "/docs/#ignoring-problems" >}}).

This release no longer includes these deprecated utilities, nor does
it provide the deprecated flag.

## Checks {#checks}

### New checks {#checks-new}

Numerous new checks have been added in this release:

- {{< check "S1033"  >}} flags unnecessary guards around calls to `delete`.
- {{< check "S1034"  >}} simplifies type switches involving redundant type assertions.
- {{< check "SA1026" >}} flags attempts at marshaling invalid types.
- {{< check "SA1027" >}} flags incorrectly aligned atomic accesses.
- {{< check "SA4020" >}} flags unreachable case clauses in type switches.
- {{< check "SA4021" >}} flags calls to append with a single argument, as `x = append(y)` is equivalent to `x = y`.
- {{< check "SA5008" >}} flags certain kinds of invalid struct tags.
- {{< check "SA5009" >}} verifies the correctness of Printf calls.
- {{< check "SA6005" >}} flags inefficient string comparisons involving `strings.ToLower`
  or `strings.ToUpper` when they can be replaced with `strings.EqualFold`.
- {{< check "SA9005" >}} flags attempts at marshaling structs with no public fields nor custom marshaling.
- {{< check "ST1017" >}} flags so-called [yoda conditions](https://en.wikipedia.org/wiki/Yoda_conditions),
  which take the form of `if 42 == x`.
- {{< check "ST1018" >}} flags string literals containing zero-width characters.


### Changed checks {#checks-changed}

Several checks have been improved:

- {{< check "SA1019" >}} now flags imports of deprecated packages.
- {{< check "SA4000" >}} no longer flags comparisons between custom float types. Additionally, it avoids a false positive caused by cgo.
- {{< check "SA4006" >}} no longer flags unused values in code generated by goyacc. This avoids noise caused by the nature of the generated state machine.
- {{< check "ST1005" >}} no longer flags error messages that start with capitalized type names.
- {{< check "ST1006" >}} no longer flags receiver names in generated code.
- {{< check "SA5002" >}} no longer suggests replacing `for false {` with `for {`.
- Added "SIP" and "RTP" as default initialisms to {{< check "ST1003" >}}.
- {{< check "SA1006" >}}, {{< check "SA4003" >}}, {{< check "S1017" >}}, and {{< check "S1020" >}} match more code patterns.
- {{< check "S1021"  >}} is less eager to merge declarations and assignments when multiple assignments are involved.
- {{< check "U1000"  >}} has been rewritten, eliminating a variety of false positives.

## Sustainable open source and a personal plea {#sustainable-open-source}

Staticcheck is an open source project developed primarily by me, Dominik Honnef, in my free time.
While this model of software development has gotten increasingly common, it is not very sustainable.
Time has to be split between open source work and paid work to sustain one's life.
This is made especially unfortunate by the fact that hundreds of companies rely on open source each day,
but few consider giving back to it, even though it would directly benefit their businesses,
ensuring that the software they rely on keeps being developed.

I have long been soliciting donations for Staticcheck [on Patreon](https://www.patreon.com/dominikh) to make its development more sustainable.
A fair number of individuals have generously pledged their support and I am very grateful to them.
Unfortunately, only few companies support Staticcheck's development, and I'd like for that to change.

To people who are familiar with Patreon, it might've always seemed like an odd choice for a software project.
Patreon focuses on art and creative work, and on individuals supporting said work, not companies.
I am therefore excited to announce my participation in [GitHub Sponsors](https://github.com/sponsors),
a new way of supporting developers, directly on GitHub.

GitHub Sponsors allows you to easily support developers by sponsoring them on a monthly basis, [via a few simple clicks.](https://github.com/users/dominikh/sponsorship)
It is fully integrated with the platform and can use your existing billing information, making it an effortless process.
**To encourage more company sponsorships I offer to display your company's logo prominently on
[Staticcheck's website](https://staticcheck.dev/)**
for
[$250 USD a month](https://github.com/users/dominikh/sponsorship?utf8=%E2%9C%93&tier_id=MDIyOk1hcmtldHBsYWNlTGlzdGluZ1BsYW4yNTAy&editing=false),
to show my appreciation for your contribution and to show to the world how much you care about code quality.

Please don't hesitate [contacting me directly](mailto:dominik@honnef.co) if neither GitHub Sponsors nor Patreon seem suitable to you but you'd like to support me nevertheless.
I am sure we can work something out.

## Staticcheck 2019.2.1 release notes {#2019.2.1}

The 2019.2 release has an unfortunate bug that prevents Staticcheck from running on 32-bit architectures, causing it to crash unconditionally.
This release fixes that crash.

## Staticcheck 2019.2.2 release notes {#2019.2.2}

Staticcheck 2019.2.2 contains the following user-visible fixes:

- {{< check "S1008" >}} now skips if/else statements where both branches return the same value.
- {{< check "SA4006" >}} now considers a value read when a switch statement reads it, even if the switch statement has no branches.
- 2019.2 introduced a bug that made it impossible to enable non-default checks via configuration files. This is now possible again.
- 2019.2 introduced a bug that made the `-tags` command line argument ineffective, making it impossible to pass in build tags. This is now possible again.
- From this release onward, we will use pseudo versions of the form
  `v0.0.1-<year>.<minor>` instead of `v0.0.0-<year>.<minor>`.
  This fixes an issue where `go get` would prefer an older commit over a newer released version due to the way versions sort.

## Staticcheck 2019.2.3 release notes {#2019.2.3}

Staticcheck 2019.2.3 is a re-release of 2019.2.2.
Its pre-built binaries, which can be found on GitHub,
have been built with Go 1.13, to enable checking of code that uses language features introduced in Go 1.13.
