Staticcheck 2020.1 Release Notes

Introduction to Staticcheck 2020.1

Staticcheck 2020.1 introduces UI improvements, speed enhancements, and a number of new as well as improved checks. Additionally, it is the first release to support the upcoming Go 1.14.

UI improvements

We've improved the output of the staticcheck command as well as Staticcheck's integration with gopls to make it easier to understand the problems that are being reported.

Related information describes the source of a problem, or why Staticcheck believes that there is a problem. Take the following piece of code for example:

func fn(x *int) {
	if x == nil {
		log.Println("x is nil, returning")
	}
	// lots of code here
	log.Println(*x)
}

Staticcheck 2020.1 will produce the following output:

foo.go:6:14: possible nil pointer dereference (SA5011)
	foo.go:2:5: this check suggests that the pointer can be nil

The actual problem that is being reported is the "possible nil pointer dereference". Staticcheck also explains why it believes that x might be nil, namely the comparison on line 2.

When using the text or stylish formatters, related information will appear as indented lines. The json formatter adds a new field related to problems, containing position information as well as the message. Editors that use gopls will also display the related information.

Related information should make it easier to understand why Staticcheck is flagging code, and how to fix problems.

Integration with gopls has seen some other improvements as well¹. We now emit better position information that more accurately reflects the true source of a problem. The most obvious example is that a missing package comment will no longer underline the entire file. Similarly, invalid function arguments will be highlighted individually, instead of highlighting the call as a whole. Finally, some problems can now be automatically fixed by using quick fixes.

¹: due to the nature of Staticcheck's integration with gopls, gopls will need to update their dependency on Staticcheck before benefiting from these changes.

Better caching

The 2019.2 release introduced caching to Staticcheck, greatly speeding up repeated runs. However, the caching only applied to dependencies; the packages under analysis still had to be analyzed anew on every invocation to compute the list of problems. Staticcheck 2020.1 introduces caching of problems found, so that repeat runs for unchanged packages are virtually instantaneous.

Checks

New checks

Numerous new checks have been added in this release:

  • S1035 flags redundant calls to net/http.CanonicalHeaderKey.
  • S1036 flags unnecessary guards around map accesses.
  • S1037 flags unnecessarily elaborate ways of sleeping.
  • S1038 flags unnecessary uses of fmt.Sprintf, such as fmt.Println(fmt.Sprintf(...)).
  • S1039 flags uses of fmt.Sprint with single string literals.
  • SA1028 flags uses of sort.Slice on non-slices.
  • SA1029 flags inappropriate keys in calls to context.WithValue.
  • SA4022 flags comparisons of the kind if &x == nil.
  • SA5010 flags impossible type assertions.
  • SA5011 flags potential nil pointer dereferences.
  • ST1019 flags duplicate imports.
  • ST1020 checks the documentation of exported functions.
  • ST1021 checks the documentation of exported types.
  • ST1022 checks the documentation of exported variables and constants.

ST1020, ST1021 and ST1022 are not enabled by default.

Changed checks

Several checks have been improved:

  • S1036 detects more kinds of unnecessary guards around map accesses.
  • S1008 reports more easily understood diagnostics.
  • S1025 no longer suggests using v.String() instead of fmt.Sprintf("%s", v) when v is a reflect.Value. fmt gives special treatment to reflect.Value and the two results differ.
  • SA1015 no longer flags uses of time.Tick in packages that implement Cobra commands.
  • SA1019 no longer misses references to deprecated packages when said packages have been vendored.
  • SA4000 no longer flags comparisons of the kind x == x and x != x when `x` has a compound type involving floats.
  • SA4003 no longer flags comparisons of the kind x <= 0 when x is an unsigned integer. While it is true that x <= 0 can be written more specifically as x == 0, this is not a helpful suggestion in reality. A lot of people use x <= 0 as a defensive measure, in case x ever becomes signed. Also, unlike all the other warnings made in the check, x <= 0 is neither a tautology nor a contradiction, it is merely less precise than it could be.
  • SA4016 now detects silly bitwise ops of the form x & k where k is defined as const k = iota.
  • SA4018 no longer flags self-assignments involving side effects; for example, it won't flag x[fn()] = x[fn()] if fn isn't pure.
  • SA5008 now permits duplicate instances of various struct tags used by github.com/jessevdk/go-flags.
  • SA5009 now correctly recognizes that unsafe.Pointer is a pointer type that can be used with verbs such as %p. Furthermore, it validates calls to golang.org/x/xerrors.Errorf.
  • SA5009 now understands fmt.Printf verbs that were changed and added in Go 1.13. Specifically, it now recognizes the new %O verb, and allows the use of %x and %X on floats and complex numbers.
  • ST1003 has learned about several new initialisms.
  • ST1011 no longer misses variable declarations with inferred types.
  • ST1016 now ignores the names of method receivers of methods declared in generated files.
  • ST1020, ST1021, and ST1022 no longer enforce comment style in generated code.

General bug fixes

The following bugs were fixed:

  • A race condition in the U1000 check could occasionally lead to sporadic false positives.
  • Some files generated by goyacc weren't recognized as being generated.
  • staticcheck no longer fails to check packages that consist exclusively of tests.

Staticcheck 2020.1.1 release notes

The 2020.1 release neglected to update the version string stored in the binary, causing staticcheck -version to incorrectly emit (no version).

Staticcheck 2020.1.2 release notes

The 2020.1.1 release incorrectly identified itself as version 2020.1.

Staticcheck 2020.1.3 release notes

This release fixes two bugs involving //lint:ignore directives:

  • When ignoring U1000 and checking a package that contains tests, Staticcheck would incorrectly complain that the linter directive didn't match any problems, even when it did.
  • On repeated runs, the position information for a this linter directive didn't match anything report would either be missing, or be wildly incorrect.

Staticcheck 2020.1.4 release notes

This release adds special handling for imports of the deprecated github.com/golang/protobuf/proto package.

github.com/golang/protobuf has deprecated the proto package, but their protoc-gen-go still imports the package and uses one of its constants, to enforce a weak dependency on a sufficiently new version of the legacy package.

Staticcheck would flag the import of this deprecated package in all code generated by protoc-gen-go. Instead of forcing the project to change their project structure, we choose to ignore such imports in code generated by protoc-gen-go. The import still gets flagged in code not generated by protoc-gen-go.

You can find more information about this in the upstream issue.