Staticcheck - The advanced Go linter

Overview

Staticcheck logo
The advanced Go linter

Staticcheck is a state of the art linter for the Go programming language. Using static analysis, it finds bugs and performance issues, offers simplifications, and enforces style rules.

Financial support by private and corporate sponsors guarantees the tool's continued development. Please become a sponsor if you or your company rely on Staticcheck.

Documentation

You can find extensive documentation on Staticcheck on its website.

Installation

Releases

It is recommended that you run released versions of the tools. These releases can be found as git tags (e.g. 2019.1) as well as prebuilt binaries in the releases tab.

The easiest way of using the releases from source is to use a Go package manager such as Godep or Go modules. Alternatively you can use a combination of git clone -b and go get to check out the appropriate tag and download its dependencies.

Master

You can also run the master branch instead of a release. Note that while the master branch is usually stable, it may still contain new checks or backwards incompatible changes that break your build. By using the master branch you agree to become a beta tester.

Tools

All of the following tools can be found in the cmd/ directory. Each tool is accompanied by its own README, describing it in more detail.

Tool Description
keyify Transforms an unkeyed struct literal into a keyed one.
rdeps Find all reverse dependencies of a set of packages
staticcheck Go static analysis, detecting bugs, performance issues, and much more.
structlayout Displays the layout (field sizes and padding) of structs.
structlayout-optimize Reorders struct fields to minimize the amount of padding.
structlayout-pretty Formats the output of structlayout with ASCII art.

Libraries

In addition to the aforementioned tools, this repository contains the libraries necessary to implement these tools.

Unless otherwise noted, none of these libraries have stable APIs. Their main purpose is to aid the implementation of the tools. If you decide to use these libraries, please vendor them and expect regular backwards-incompatible changes.

System requirements

We support the last two versions of Go.

Comments
  • Wrong certificate on honnef.co

    Wrong certificate on honnef.co

    I have an issue with dependency scanning of my repo which implicitly using your extension. The extension itself is working but scanning doesn't pass:

    honnef.co/go/[email protected]: unrecognized import path "honnef.co/go/tools" (https fetch: Get https://honnef.co/go/tools?go-get=1: x509: certificate is valid for *.netlify.com, netlify.com, not honnef.co)
    

    Can it be that something is wrong with certificate of your website?

    Thanks for your attention.

    infrastructure 
    opened by legosx 30
  • Package loading time in Go 1.10.x

    Package loading time in Go 1.10.x

    I seem to have an interesting issue where running the checked is extremely slow and CPU is pegged at 100% on one core.

    [email protected]:~/gopath/src/user/package$ staticcheck --debug.print-stats github.com/user/package/...
    Package loading: 1h38m31.454171864s
    SSA build: 21.67682346s
    Other init work: 6.817053264s
    Checker inits:
            gosimple: 5.939782ms
            staticcheck: 6.580565926s
            stylecheck: 3.011µs
            unused: 308ns
    
    Jobs:
            SA1023: 605.955µs
            ST1008: 2.835215ms
            SA5007: 12.190218ms
            SA4019: 740.066374ms
            SA5000: 788.664339ms
            SA4016: 1.341984904s
            ST1001: 1.548734657s
            SA2002: 1.751419466s
            SA4012: 1.980239895s
            SA6001: 3.151521396s
            SA4013: 3.616790341s
            SA4002: 3.741031528s
            S1020: 4.209893928s
            SA1013: 4.7203341s
            SA3001: 4.757165187s
            SA5004: 4.79783047s
            S1023: 4.847563802s
            SA1010: 4.898477989s
            SA4001: 4.92993824s
            S1010: 5.170548174s
            SA5002: 5.191772116s
            ST1015: 5.227913934s
            SA4011: 5.260503075s
            S1000: 5.506765333s
            SA4010: 5.602958172s
            SA4015: 5.635165478s
            SA6003: 5.826837105s
            S1006: 6.026174231s
            S1029: 6.288058228s
            S1017: 6.521211728s
            S1005: 6.657113216s
            SA1003: 7.166001256s
            SA4008: 8.185722499s
            SA1020: 8.47647566s
            SA6002: 9.123205597s
            SA1017: 10.400495305s
            SA6000: 11.090975882s
            SA1025: 11.55688655s
            SA5005: 12.273645941s
            SA2000: 12.657624433s
            SA1007: 12.86456794s
            SA4006: 14.983973684s
            SA1021: 15.570106172s
            ST1006: 19.799175166s
            SA1018: 19.7997434s
            SA3000: 19.806420248s
            SA2003: 20.006151449s
            S1021: 20.17263736s
            SA1024: 20.319294594s
            SA1011: 20.714653373s
            SA5003: 22.834504023s
            SA1002: 23.611794013s
            S1018: 23.82204222s
            SA1014: 24.237042124s
            SA1000: 25.042900226s
            SA6005: 29.890880858s
            S1008: 30.267773032s
            S1004: 30.617342398s
            ST1016: 31.025323399s
            S1009: 31.761876835s
            ST1012: 32.49133553s
            S1011: 33.264634843s
            SA9004: 34.480512655s
            S1001: 35.164602355s
            S1019: 36.734606891s
            SA1008: 37.6376481s
            SA9001: 37.677980421s
            SA4004: 38.47965889s
            S1030: 39.069030457s
            S1012: 39.084799926s
            S1016: 39.434007962s
            SA5001: 39.451987822s
            S1031: 39.666953149s
            S1002: 40.197963098s
            ST1011: 40.207626479s
            SA2001: 40.388245786s
            SA1012: 40.413728705s
            SA1016: 40.58124205s
            S1003: 40.626086764s
            SA4003: 40.691722167s
            S1028: 40.739847559s
            S1025: 40.829009563s
            ST1003: 40.984717091s
            ST1013: 40.990694135s
            SA1019: 41.040898529s
            S1024: 41.081448598s
            SA4018: 41.093339685s
            SA9002: 41.156389751s
            SA4000: 41.299867621s
            SA4014: 41.333049609s
            SA1001: 41.433742272s
            SA1015: 41.439050706s
            SA1006: 41.534056007s
            SA1005: 41.571696853s
            SA1004: 41.742200385s
            S1032: 41.787982319s
            S1007: 41.80344573s
            SA9003: 41.851629245s
            ST1005: 42.379658152s
            ST1000: 42.523186901s
            SA4009: 42.574494452s
            SA4017: 43.139778791s
            U1000: 45.419632247s
            Total: 39m54.325734682s
    
    [email protected]:~/gopath/src/honnef.co/go/tools$ git cat-file commit HEAD
    tree 822824557d88c8751120de337fdc352f5d58d041
    parent 17562b81b08373b3b11be787d2cf278102bce55d
    
    [email protected]:~/gopath/src/honnef.co/go/tools$ go version
    go version go1.10.4 linux/amd64
    [email protected]:~/gopath/src/honnef.co/go/tools$ go env
    GOARCH="amd64"
    GOBIN=""
    GOCACHE="/home/klaus/.cache/go-build"
    GOEXE=""
    GOHOSTARCH="amd64"
    GOHOSTOS="linux"
    GOOS="linux"
    GOPATH="/home/klaus/gopath"
    GORACE=""
    GOROOT="/usr/local/go"
    GOTMPDIR=""
    GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
    GCCGO="gccgo"
    CC="gcc"
    CXX="g++"
    CGO_ENABLED="1"
    CGO_CFLAGS="-g -O2"
    CGO_CPPFLAGS=""
    CGO_CXXFLAGS="-g -O2"
    CGO_FFLAGS="-g -O2"
    CGO_LDFLAGS="-g -O2"
    PKG_CONFIG="pkg-config"
    GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build804420424=/tmp/go-build -gno-record-gcc-switches"
    

    It seems the times in Jobs doesn't add up to the total, and obviously the 1½ hour loading time seems a bit much. It is a big package with lots of dependencies, but this does seem a bit excessive.

    I restarted with --debug.cpuprofile="profile.cpu" to get a profile, but obviously it will take a while before the results are available.

    performance 
    opened by klauspost 27
  • honnef.co is down

    honnef.co is down

    $ curl -sSL https://honnef.co/go/tools/cmd/staticcheck?go-get=1
    <html>
    <head><title>502 Bad Gateway</title></head>
    <body bgcolor="white">
    <center><h1>502 Bad Gateway</h1></center>
    <hr><center>nginx/1.12.1</center>
    </body>
    </html>
    
    infrastructure 
    opened by bufdev 27
  • go-langserver: implement a Language Server for Go

    go-langserver: implement a Language Server for Go

    Implement a Language Server for Go that supports all the common features as well as hooks into our linters. Will use the new loader package to provide incremental rebuilds, which will be much faster than calling standalone tools repeatedly.

    Where possible we should implement our own logic. More complex matters may be delegated to vendored and patched versions of guru.

    Desired features

    • [x] Report diagnostics for build errors

    • [ ] Report diagnostics for linters (may want to vendor golint and errcheck)

      • [ ] megacheck
      • [ ] go vet
      • [ ] golint
      • [ ] errcheck
    • [x] Support the hover request, displaying documentation

      • [ ] display struct field alignment(?)
      • [ ] display type size(?)
      • [ ] display VRP-based information
    • [x] Support signature request, displaying function signatures

    • [ ] Support references request. Will likely depend on guru.

    • [x] Support documentHighlight request, highlighting instances of an identifier in the same file

      • [ ] Use the read and write highlight kinds instead of text
      • [x] Support highlighting more things than just identifiers. Struct fields, imports and so on.
    • [x] Support documentSymbol request, listing all symbols in the file

      • [ ] Support the same for workspace queries

        • Due to Go's use of GOPATH, and the stdlib, would it make sense to offer combinable configurable modes of workspace-wide symbol queries?
        1. Only search in the VS Code workspace, i.e. the opened folder
        2. Search in the entire GOPATH
        3. Search in GOROOT

        If we do support such large scopes, we will definitely need good caching and also not rely on having all packages in memory at once.

    • [ ] Support formatting request, using go/format to gofmt Go documents

    • [x] Support definition request, a la godef, but with our own implementation

    • [ ] Support code actions. Most of gosimple's warnings can be turned into automatic fixes, maybe some of staticcheck, too.

    • [ ] Support rename request, by deferring to gorename.

    Maybe features

    • [ ] Code completion by delegating to gocode (or writing our own)
    • [ ] Support document links. Maybe linkify imports, if that fits into the vscode ecosystem. Maybe mentions to RFCs in comments, a la godoc.org. Anything else?

    Experimental extensions

    There are a number of Go-specific features that don't map to standard LSP commands. LSP 3, however, supports experimental extensions, which act as vendor-specific extensions. We may be able to offer some extra functionality that is currently handled by editors and external tools.

    • [ ] Return a list of importable packages, for example for vscode-go's Go: Add Import feature.
      • Caching combined with fsnotify could make it extremely fast to get the list of packages
    • [ ] https://code.visualstudio.com/docs/editor/editingevolved mentions Go To Type Definition and Go To Implementation. Can we add support for that? Similarly, can we support Open symbol by name? Update: Apparently there might be methods for that functionality in LSP 4.0, c.f. https://github.com/Microsoft/language-server-protocol/issues/173

    Required architectural changes

    • [ ] The current implementation of loader only accepts packages that type-check fully, because we can only create SSA programs out of well-formed code, which is required by the linters. As a language server, however, we will get a lot of invalid code as the user is typing. While we can't lint or do any complex analysis on that code, we still want to support signature information, Go To definition and other features that can work on partially type-checked packages.

      This change will require loader to not build SSA form for broken packages or any of their reverse dependencies. This will likely be achieved by setting some flag and not building SSA form for those packages, as well as not pass them to the linters.

    • [ ] The current loader prototype needs to retain all compiled packages in memory. That may be okay when only compiling packages we work on + their forward dependencies. It is, however, not acceptable once we compile all reverse dependencies, for queries such as References.

      We should design a serialisation format, akin to object files, that allows us to store the AST, type information and SSA form on disk, and load these on demand. We have to use our own format, as opposed to gc object files, because the latter doesn't store all the information we need.

    Code rebuilding

    The long-term goal for (re)compiling packages, caching and memory usage looks something like this:

    1. When the user opens a file, compile the surrounding package

    2. When the user modifies code, mark the changed package, and all reverse dependencies, as out of date.

    3. After an idle timeout, or when we require type information (e.g. when hovering), we rebuild the package that we require. This will not automatically rebuild reverse dependencies unless required (such as by rename and references)

    4. If the package can't be type-checked fully, we'll do as much work as possible and mark the package and its reverse dependencies as incomplete. For incomplete packages we will offer a reduced set of features (no renaming, for example.)

    If a package failed to compile, and neither its own code, nor that of any of its dependencies changed we shouldn't try to recompile it.

    As far as memory usage and caching go, there are several incremental approaches of increasing complexity. The one we will implement first is as such:

    • All packages that we require for a computation will be loaded into memory
    • Additionally, the packages that the user is currently actively editing will be pinned in memory
    • Additionally, we won't immediately unload unused packages. Instead, we will use a LRU cache with a configurable maximum memory usage. When we need to load new packages and exceed our memory limit, cached packages will be evicted.
    • When loading a package, we will use information cached on disk, unless the sources changed, in which case we build the package from scratch

    A more advanced approach, requiring modifications to the go/types package, would allow us to load and unload packages in a more fine-grained fashion. Instead of loading all packages for a query into memory, we could stream packages in and out as the algorithms are inspecting the packages.

    An even more complex approach could forego the internal go/types representation and instead use a disk-backed database, likely a graph database. Some queries, such as references could be solved entirely with graph queries if the graph is up to date.

    Preview

    Some previews of features using just our language server:

    Screenshots

    As-you-type type checking

    checking

    Identifier highlighting

    highlight

    Hover

    hover

    /cc @ramya-rao-a in case she has any ideas/requests.

    wontfix idea 
    opened by dominikh 22
  • staticcheck: reimplement errcheck using our framework

    staticcheck: reimplement errcheck using our framework

    It should be rather straightforward to implement errcheck using our framework. Do it for fun, and also to experiment with some SSA aided features. For example, we could rather easily ignore unchecked errors on (*os.File) if the file is known to be opened read-only.

    We may either try to upstream our ideas, assuming adding SSA there is feasible, or maintain our own errcheck check in staticcheck.

    wontfix 
    opened by dominikh 22
  • staticcheck: detect pointer access after non-terminating nil checks

    staticcheck: detect pointer access after non-terminating nil checks

    I've had code like this:

    var foo = foos.Get(fooID)
    if foo == nil {
    	log.Printf("skipping foo with id %d: not found", fooID)
    	// Whoops! Forgot a return.
    }
    
    // …
    
    // Boom! foo was nil this time.
    var bar = foo.Bars[barID]
    

    I think that when a pointer value is checked against nil, no terminating action like panic, continue, or return is performed, and then the pointer is dereferenced, that probably means that either the developer has forgotten to terminate execution or the nil check here is useless (e.g. was moved up-stack or the pointer is now guaranteed to not be nil).

    new-check 
    opened by ainar-g 20
  • Build errors when Go modules are enabled

    Build errors when Go modules are enabled

    In https://github.com/grpc/grpc-go/pull/2281, I converted grpc-go to support the new modules in Go. However, without a workaround, staticcheck gave the following error:

    $ staticcheck -ignore '
    > internal/transport/transport_test.go:SA2002
    > benchmark/benchmain/main.go:SA1019
    > stats/stats_test.go:SA1019
    > test/end2end_test.go:SA1019
    > balancer_test.go:SA1019
    > balancer.go:SA1019
    > clientconn_test.go:SA1019
    > internal/transport/handler_server_test.go:SA1019
    > internal/transport/handler_server.go:SA1019
    > ' ./...
    .../go/pkg/mod/github.com/golang/[email protected]/gomock/controller.go:60:2: could not import golang.org/x/net/context (cannot find package "golang.org/x/net/context" in any of:
    	.../go111/go/src/golang.org/x/net/context (from $GOROOT)
    	.../go/src/golang.org/x/net/context (from $GOPATH))
    couldn't load packages due to errors: google.golang.org/genproto/googleapis/rpc/status, github.com/golang/protobuf/ptypes/any, ./channelz/service and 21 more
    

    The workaround: make a symlink in $GOPATH/src for every package needed from $GOPATH/pkg/mod (see vet.sh immediately before running staticcheck).

    I found this related issue: https://github.com/golang/go/issues/26504. However, it was resolved before the 1.11 release and was marked as a release blocker, so my best guess is it was incorporated in the release. The advice in that issue is to switch to golang.org/x/tools/go/packages from go/build. Maybe that will fix all related issues?

    opened by dfawley 17
  • SA5011 false positive after (*testing.T).Fatalf

    SA5011 false positive after (*testing.T).Fatalf

    These occur after updating to v0.1.1. Two instances:

    https://github.com/google/gvisor/blob/fcc2468db573fec37c91236f805f7fa0e46e4492/pkg/sentry/fs/fdpipe/pipe_opener_test.go#L349-L366

    https://github.com/google/gvisor/blob/fcc2468db573fec37c91236f805f7fa0e46e4492/pkg/tcpip/tests/integration/link_resolution_test.go#L400-L429

    Raw results:

    • https://storage.googleapis.com/gvisor-buildkite/7bc1c9fc-1448-41d1-9c08-64d76ea8d46e/e31744a4-2c50-4a77-a692-21323350aee6/home/agent/.cache/bazel/_bazel_agent/843778434294ab14ec56b0cf0ea4c952/execroot/main/bazel-out/k8-fastbuild/testlogs/pkg/sentry/fs/fdpipe/fdpipe_test_nogo/test.log
    • https://storage.googleapis.com/gvisor-buildkite/7bc1c9fc-1448-41d1-9c08-64d76ea8d46e/e31744a4-2c50-4a77-a692-21323350aee6/home/agent/.cache/bazel/_bazel_agent/843778434294ab14ec56b0cf0ea4c952/execroot/main/bazel-out/k8-fastbuild/testlogs/pkg/tcpip/tests/integration/integration_test_nogo/test.log

    cc @ghanan94

    bug upstream 
    opened by tamird 16
  • Improve semantic versioning

    Improve semantic versioning

    Go modules, for all intents and purposes, require projects to use Semantic Versioning. Because of the way many people install staticcheck – by including it in their go.mod as a dependency – we are not exempt from this requirement.

    Staticcheck does not provide a stable API (but doesn't hide all packages in /internal/ – users are free to use our APIs, without any guarantees), nor does it provide a stable CLI – Staticcheck releases can make backwards incompatible changes. If we were to use a major version >= 1, then most releases would require bumping the major version, which in turn would require changing our import paths. This creates unnecessary churn – both for us and our users. This means we can only use major version 0, as it carries no backwards compatibility guarantee.

    Staticcheck adopted its official versioning scheme long before the introduction of Go modules. We chose the format <year>.<seq>.<patch>. <year> would correspond to the current year, <seq> would increment with each feature release and reset at the beginning of the year, and <patch> would denote bugfix releases of a given feature release. This versioning scheme was chosen to add some meaning to versions – based on the <year> component, users can tell how old their version of Staticcheck is, in terms of time. This contrasts with Semantic Versioning, which carries no such information. It was and is my belief that Semantic Versioning is primarily of use to libraries, not end-user software. Staticcheck is end-user software.

    However, under Go modules, we cannot simply use our versioning scheme. v2020.1.0 would be major version 2020, and we've established that only major version 0 is viable for us. This leaves us with two options:

    1. Abandon our versioning scheme, use plain Semantic Versioning, incrementing the minor version with each feature release.

    2. Somehow encode our versioning scheme in Semantic Versioning.

    Currently, we use a form of option 2 (let's call it option 2a): versions are tagged as v0.0.1-<year>.<seq>.<patch> – that is, we store our own version in the pre-release portion of Semantic Versioning. The actual version is fixed at v0.0.1 and doesn't change. This scheme has worked somewhat well, but suffers from two (related) problems.

    1. We can't make actual pre-releases. Say we wanted to release version 2020.2-beta.1 – there is no way for us to do so. If we used v0.0.1-2020.2-beta.1, then this version would sort higher than v0.0.1-2020.1, despite being a beta release, defaulting people to using the beta.

    2. Because we use release branches, and tags are on commits that are unique to these release branches, our current versioning scheme makes it difficult to use the master branch, as can be seen in https://github.com/golang/go/issues/38985. In short, the pseudo-versions that Go generates for commits on master will sort lower than the latest actual release, even if these commits are chronologically newer. To fix that, while still using release branches, would require pre-release tags on the master branch. And that runs into the first problem.

    The other way (option 2b) of implementing option 2 is to store the <year>.<seq> portion in the minor component, resulting in v0.202001.0 and v0.202002.0-beta.1. These versions would constitute "proper" Semantic Versions, sort as expected and allow us to make bugfix releases as well as pre-releases. Their downside is that they're exceptionally ugly and difficult to read for at least all of 2020, and probably in general.

    Option 1 can be split into two sub-options:

    a. completely abandon our versioning scheme b. use basic semantic versions for Go, but use our existing versioning scheme officially

    Option a is not very satisfying. We would switch from our established versioning scheme to an inferior one. We would also be stuck on major version 0, which would make Staticcheck look less stable than it is. It would also create a break in our versions, going from 2019.1 to 2019.2 to 2020.1 to… 0.2.0.

    Option b requires maintaining a mapping, and will ienvitably confuse users. We could tag our releases with both versions, so that v0.2.0 and 2020.2 point to the same commit. This would allow go get [email protected] to work, transparently resolving to v0.2.0. However, users will now see v0.2.0 in their go.mod files and have no idea what version that corresponds to.

    In summary: Option 1a is unsatisfying, option 1b is confusing, Option 2a is insufficient and option 2b is ugly.

    Is there another option I have missed? If not, which of these mediocre options is the least bad?

    /cc @dmitshur @bcmills @myitcv @mvdan

    help wanted infrastructure 
    opened by dominikh 15
  • panic in nilness check

    panic in nilness check

    Running staticcheck at commit 740f570319eacbf8098b259fd4770779905be852:

    $ staticcheck -debug.version
    staticcheck (no version)
    
    Compiled with Go version: go1.17
    Main module:
    	honnef.co/go/tools
    Dependencies:
    	github.com/BurntSushi/[email protected] (sum: h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=)
    	golang.org/x/[email protected] (sum: h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=)
    	golang.org/x/[email protected] (sum: h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=)
    	golang.org/x/[email protected] (sum: h1:oRWktbvlCLroCQeAn0bO+yyQy8vmj7Fu+J41xJTt1YM=)
    	golang.org/x/[email protected] (sum: h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=)
    

    I'm using go 1.17 to compile, but I could also reproduce on Go 1.18 tip.

    I am running

    GOFLAGS="-mod=vendor -race" GO111MODULE=on staticcheck ./...
    

    I see the following panic:

    panic: runtime error: index out of range [1] with length 1
    
    goroutine 549 [running]:
    honnef.co/go/tools/analysis/facts/nilness.impl.func1({0x15688e8, 0xc0011f6900})
    	/Users/kevin/src/honnef.co/go/tools/analysis/facts/nilness/nilness.go:153 +0xddb
    honnef.co/go/tools/analysis/facts/nilness.impl.func1({0x1568fd0, 0xc00035d7a0})
    	/Users/kevin/src/honnef.co/go/tools/analysis/facts/nilness/nilness.go:140 +0xe7f
    honnef.co/go/tools/analysis/facts/nilness.impl(0xc000fd2000, 0xc0016067e0, 0xc001350e48)
    	/Users/kevin/src/honnef.co/go/tools/analysis/facts/nilness/nilness.go:232 +0x397
    honnef.co/go/tools/analysis/facts/nilness.run(0xc000fd2000)
    	/Users/kevin/src/honnef.co/go/tools/analysis/facts/nilness/nilness.go:66 +0x126
    honnef.co/go/tools/lintcmd/runner.(*analyzerRunner).do(0xc0026f4150, {0x1563278, 0xc0013e1860})
    	/Users/kevin/src/honnef.co/go/tools/lintcmd/runner/runner.go:937 +0x614
    honnef.co/go/tools/lintcmd/runner.genericHandle({0x1563278, 0xc0013e1860}, {0x1563278, 0xc0013e15e0}, 0x8080104, 0x0, 0xc0013511b8)
    	/Users/kevin/src/honnef.co/go/tools/lintcmd/runner/runner.go:762 +0x102
    honnef.co/go/tools/lintcmd/runner.(*subrunner).runAnalyzers(0xc00007fc70, 0xc000429d40, 0xc000d92be0)
    	/Users/kevin/src/honnef.co/go/tools/lintcmd/runner/runner.go:1007 +0x786
    honnef.co/go/tools/lintcmd/runner.(*subrunner).doUncached(0x0, 0xc000429d40)
    	/Users/kevin/src/honnef.co/go/tools/lintcmd/runner/runner.go:666 +0x1a9
    honnef.co/go/tools/lintcmd/runner.(*subrunner).do(0xc00007fc70, {0x15632c0, 0xc000429d40})
    	/Users/kevin/src/honnef.co/go/tools/lintcmd/runner/runner.go:529 +0x6e8
    honnef.co/go/tools/lintcmd/runner.(*Runner).Run.func2({0x15632c0, 0xc000429d40})
    	/Users/kevin/src/honnef.co/go/tools/lintcmd/runner/runner.go:1183 +0x30
    honnef.co/go/tools/lintcmd/runner.genericHandle({0x15632c0, 0xc000429d40}, {0x15632c0, 0xc00020f0e0}, 0x0, 0xc0002c00b8, 0xc001fed110)
    	/Users/kevin/src/honnef.co/go/tools/lintcmd/runner/runner.go:762 +0x102
    created by honnef.co/go/tools/lintcmd/runner.(*Runner).Run
    	/Users/kevin/src/honnef.co/go/tools/lintcmd/runner/runner.go:1182 +0x4d4
    Command exited with non-zero status 2
    6.50user 1.66system 0:02.77elapsed 294%CPU (0avgtext+0avgdata 187676maxresident)k
    0inputs+0outputs (6major+93629minor)pagefaults 0swaps
    make: *** [Makefile:91: lint] Error 2
    

    It's a large closed source project, I suppose I could try to bisect the package list to find out exactly where the error is occurring.

    bug upstream 
    opened by kevinburke1 13
  • simple or quickfix: replace strings.Replace with strings.ReplaceAll where applicable

    simple or quickfix: replace strings.Replace with strings.ReplaceAll where applicable

    Greetings to the maintainers and thanks for the excellent linter(s).

    I propose that the simple linter should warn on the following code:

    fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1)) // Prints "moo moo moo"
    

    And recommend converting it to:

    fmt.Println(strings.ReplaceAll("oink oink oink", "oink", "moo")) // Prints "moo moo moo"
    

    Hopefully you agree. = )

    new-check 
    opened by Zamiell 13
  • go/ir: can't convert slice to array

    go/ir: can't convert slice to array

    $ staticcheck -version
    staticcheck (devel, v0.4.0-0.dev.0.20221004230109-4229c3d955f8)
    $ go version
    go version devel go1.20-205f636e0a Fri Nov 18 08:04:52 2022 +0000 linux/amd64
    $ staticcheck net/netip
    panic: in net/netip.AddrFromSlice: cannot convert Load <[]byte> t0 ([]byte) to [4]byte
    
    goroutine 232 [running]:
    honnef.co/go/tools/go/ir.emitConv(0xc0016a4000, {0xa00e80, 0xc001591b20}, {0x9fc030?, 0xc000ba4258}, {0x9fb860, 0xc000957800})
    	/home/mvdan/go/pkg/mod/honnef.co/go/[email protected]/go/ir/emit.go:293 +0xc05
    honnef.co/go/tools/go/ir.(*builder).expr0(0xc000b63b50, 0xc0016a4000, {0x9fd448?, 0xc000957800?}, {0x7, {0x9fc030, 0xc000ba4258}, {0x0, 0x0}})
    	/home/mvdan/go/pkg/mod/honnef.co/go/[email protected]/go/ir/builder.go:610 +0x5d7
    honnef.co/go/tools/go/ir.(*builder).expr(0xc00077fbd8?, 0xc0016a4000, {0x9fd448, 0xc000957800})
    	/home/mvdan/go/pkg/mod/honnef.co/go/[email protected]/go/ir/builder.go:566 +0x1e7
    [...]
    
    bug 
    opened by mvdan 1
  • simple: enforce early return in loops

    simple: enforce early return in loops

    Early returns help to reduce nesting levels. I wonder how much effort is it to implement with staticcheck.io. Examples are:

    unwanted:

    for _, v := range x {
        if condition {
            // do stuff
        }
    }
    

    wanted:

    for _, v := range x {
        if negatedCondition {
            continue
        }
        // do stuff
    }
    
    new-check 
    opened by nfx 3
  • U1000: The

    U1000: The "unused" linting rule has misleading behaviour when interacting with generated code

    staticcheck has, in my judgement, some misleading behaviour when it interacts with generated code.

    Under some conditions, it produces an error message that doesn't suffice to resolve the underlying problem. (This was first reported here, which led me to here.)

    Reproduction

    The following example was produced with staticcheck 2022.1.3 (v0.3.3).

    The "details" block at the bottom of this section describes the following directory structure (which I've also attached as a tarball here):

    .
    ├── bar.go
    ├── Dockerfile
    ├── foo.go
    ├── go.mod
    └── rc.sh
    

    First, recreate this directory structure and set rc.sh to be executable.

    1. If you run ./rc.sh, then staticcheck will report that the function foo is unused.

    2. If you remove the first line from bar.go (that says that the file is generated) and run ./rc.sh, then staticcheck will report that both foo and bar are unused.

    3. If you replace bar with Bar, then, irrespective of the presence of the "first line" in bar.go, no errors are reported.

    ~~In my view, the messages in 1 and 2 are misleading. In both cases, the issue is that bar isn't public (and therefore isn't used); foo is only unused as a consequence of bar not being used. This is especially a problem in 1, because there's no way to resolve the problem from the error message alone.~~

    (Ed.: I've changed my mind about 2, so I've struck this through and rewritten it. See the comments below.)

    In my view, the message in option 1 is misleading; there's no way to resolve the problem from the error message alone.

    // bar.go
    // Code generated by hand. DO NOT EDIT.
    package foo
    
    func bar() {
    	foo()
    }
    
    # Dockerfile
    FROM golang:1.19-bullseye
    RUN go install honnef.co/go/tools/cmd/[email protected]
    RUN mkdir /reprex
    WORKDIR /reprex
    
    // foo.go
    package foo
    
    func foo() {}
    
    // go.mod
    module staticcheck-reprex
    
    go 1.19
    
    # rc.sh
    #! /usr/bin/env sh
    
    docker build --tag staticcheck-reprex .
    
    docker container run \
      --mount type=bind,source=$(pwd),destination=/reprex \
      -it \
      staticcheck-reprex \
      staticcheck ./...
    
    false-negative 
    opened by adamroyjones 3
  • SA1019: doesn't check nested field

    SA1019: doesn't check nested field

    • The output of 'staticcheck -version'

      staticcheck (devel, v0.4.0-0.dev.0.20221004230109-4229c3d955f8)

    • The output of 'staticcheck -debug.version' (it is fine if this command fails)

      staticcheck (devel, v0.4.0-0.dev.0.20221004230109-4229c3d955f8)
      
      Compiled with Go version: go1.19.2
      Main module:
              honnef.co/go/[email protected] (sum: h1:EHR9ADt0Go0ZXBZh1y5pKCxsr2U4V9F/rdt0lsz6Kbw=)
      Dependencies:
              github.com/BurntSushi/[email protected] (sum: h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=)
              golang.org/x/exp/[email protected] (sum: h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM=)
              golang.org/x/[email protected] (sum: h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=)
              golang.org/x/[email protected] (sum: h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=)
              golang.org/x/[email protected] (sum: h1:x7xHTSn+2j8rhcnpIsId1TO+U0RKUc8g7kHgqb2Awrg=)
      
    • The output of 'go version'

      go version go1.19.2 linux/amd64

    • The output of 'go env'

      GO111MODULE=""
      GOARCH="amd64"
      GOBIN=""
      GOCACHE="/home/zhsj/.cache/go-build"
      GOENV="/home/zhsj/.config/go/env"
      GOEXE=""
      GOEXPERIMENT=""
      GOFLAGS=""
      GOHOSTARCH="amd64"
      GOHOSTOS="linux"
      GOINSECURE=""
      GOMODCACHE="/home/zhsj/go/pkg/mod"
      GONOPROXY=""
      GONOSUMDB=""
      GOOS="linux"
      GOPATH="/home/zhsj/go"
      GOPRIVATE=""
      GOPROXY="https://goproxy.cn"
      GOROOT="/usr/lib/go-1.19"
      GOSUMDB="sum.golang.google.cn"
      GOTMPDIR=""
      GOTOOLDIR="/usr/lib/go-1.19/pkg/tool/linux_amd64"
      GOVCS=""
      GOVERSION="go1.19.2"
      GCCGO="gccgo"
      GOAMD64="v1"
      AR="ar"
      CC="gcc"
      CXX="g++"
      CGO_ENABLED="1"
      GOMOD="/tmp/t/g/go.mod"
      GOWORK=""
      CGO_CFLAGS="-g -O2"
      CGO_CPPFLAGS=""
      CGO_CXXFLAGS="-g -O2"
      CGO_FFLAGS="-g -O2"
      CGO_LDFLAGS="-g -O2"
      PKG_CONFIG="pkg-config"
      GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build771852048=/tmp/go-build -gno-record-gcc-switches"
      
    • Exactly which command you ran

      staticcheck ./...

    • Output of the command and what's wrong with the output

      main.go:11:14: a.F1 is deprecated: don't use  (SA1019)
      

      It doesn't report a.F2.F3 is also deprecated.

    • Where we can read the code you're running Staticcheck on

      ==> go.mod <==
      module zhsj.me/hello
      
      go 1.19
      
      ==> main.go <==
      package main
      
      import (
              "log"
      
              "zhsj.me/hello/pkg1"
      )
      
      func main() {
              a := pkg1.A{}
              log.Println(a.F1)
              log.Println(a.F2.F3)
      }
      
      ==> pkg1/pkg1.go <==
      package pkg1
      
      type A struct {
              // Deprecated: don't use
              F1 string
      
              F2 struct {
                      // Deprecated: don't use
                      F3 string
              }
      }
      
    false-negative 
    opened by zhsj 1
  • staticcheck: SA4006 with structs

    staticcheck: SA4006 with structs

    (Possible dup of #191, #231, or one of the others related to SA4006.)

    package main
    
    type t1 struct{ n int }
    
    func (v *t1) clone() *t1 { return &t1{n: v.n} }
    
    func defaultVal() *t1 { return &t1{n: 123} }
    
    func main() {
    	def := defaultVal()
    
    	// (Lots of unrelated code.)
    
    	v := def
    	if v != nil {
    		v = v.clone()
    		v.n = 42
    
    		// Note: v is not used after this point.
    	}
    
    	// Error!  Meant to use v, which has not been used at all.
    	println(def)
    }
    

    staticcheck --checks='*' ./main.go doesn't report anything wrong.

    Version info
    staticcheck 2022.1.3 (v0.3.3)
    
    Compiled with Go version: go1.19.2
    Main module:
            honnef.co/go/[email protected] (sum: h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=)
    Dependencies:
            github.com/BurntSushi/[email protected] (sum: h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=)
            golang.org/x/exp/[email protected] (sum: h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM=)
            golang.org/x/[email protected] (sum: h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=)
            golang.org/x/[email protected] (sum: h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=)
            golang.org/x/[email protected] (sum: h1:OKYpQQVE3DKSc3r3zHVzq46vq5YH7x8xpR3/k9ixmUg=)
    
    GO111MODULE=""                                                                                                                            
    GOARCH="amd64"                                                                                                                            
    GOBIN=""                                                                                                                                  
    GOCACHE="/home/ainar/.cache/go-build"                                                                                                     
    GOENV="/home/ainar/.config/go/env"                                                                                                        
    GOEXE=""                                                                                                                                  
    GOEXPERIMENT=""                                                                                                                           
    GOFLAGS=""
    GOHOSTARCH="amd64"
    GOHOSTOS="linux"
    GOINSECURE=""
    GOMODCACHE="/home/ainar/go/pkg/mod"
    GONOPROXY="REMOVED"
    GONOSUMDB="REMOVED"
    GOOS="linux"
    GOPATH="/home/ainar/go"
    GOPRIVATE="REMOVED"
    GOPROXY="https://proxy.golang.org,direct"
    GOROOT="/home/ainar/go/go1.19"
    GOSUMDB="sum.golang.org"
    GOTMPDIR=""
    GOTOOLDIR="/home/ainar/go/go1.19/pkg/tool/linux_amd64"
    GOVCS=""
    GOVERSION="go1.19.2"
    GCCGO="gccgo"
    GOAMD64="v1"
    AR="ar"
    CC="clang"
    CXX="clang++"
    CGO_ENABLED="1"
    GOMOD="/dev/null"
    GOWORK=""
    CGO_CFLAGS="-g -O2"
    CGO_CPPFLAGS=""
    CGO_CXXFLAGS="-g -O2"
    CGO_FFLAGS="-g -O2"
    CGO_LDFLAGS="-g -O2"
    PKG_CONFIG="pkg-config"
    GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build2034514620=/tmp/go-build -gno-record-gcc-switches"
    
    enhancement 
    opened by ainar-g 1
  • SA4006: detect unused writes with +=

    SA4006: detect unused writes with +=

    $ staticcheck -debug.version
    staticcheck 2022.1.3 (v0.3.3)
    
    Compiled with Go version: go1.18.4
    Main module:
            honnef.co/go/[email protected] (sum: h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=)
    Dependencies:
            github.com/BurntSushi/[email protected] (sum: h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=)
            golang.org/x/exp/[email protected] (sum: h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM=)
            golang.org/x/[email protected] (sum: h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=)
            golang.org/x/[email protected] (sum: h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=)
            golang.org/x/[email protected] (sum: h1:OKYpQQVE3DKSc3r3zHVzq46vq5YH7x8xpR3/k9ixmUg=)
    

    Go version is 1.19.2 linux/amd64.

    Example program:

    package main
    
    func main() {
    	dir := "a"
    	dir += "/b"
    }
    

    Staticcheck doesn't complain about that. But if I tweak it to

    package main
    
    func main() {
    	dir := "a"
    	dir = dir + "/b"
    }
    

    Then I get

    x/x.go:5:2: this value of dir is never used (SA4006)
    

    Could SA4006 better detect this case with +=?

    false-negative 
    opened by cespare 0
Releases(v0.3.3)
Owner
Dominik Honnef
Long-time Go user, contributor, and author of many Go related tools, including Staticcheck.
Dominik Honnef
[mirror] This is a linter for Go source code.

Golint is a linter for Go source code. Installation Golint requires a supported release of Go. go get -u golang.org/x/lint/golint To find out where g

Go 4k Nov 25, 2022
A Go linter to check that errors from external packages are wrapped

Wrapcheck A simple Go linter to check that errors from external packages are wrapped during return to help identify the error source during debugging.

Tom Arrell 198 Nov 24, 2022
A linter that handles struct tags.

Tagliatelle A linter that handles struct tags. Supported string casing: camel pascal kebab snake goCamel Respects Go's common initialisms (e.g. HttpRe

Ludovic Fernandez 19 Nov 23, 2022
a simple golang SSA viewer tool use for code analysis or make a linter

ssaviewer A simple golang SSA viewer tool use for code analysis or make a linter ssa.html generate code modify from src/cmd/compile/internal/ssa/html.

null 7 May 17, 2022
The Golang linter that checks that there is no simultaneous return of `nil` error and an invalid value.

nilnil Checks that there is no simultaneous return of nil error and an invalid value. Installation & usage $ go install github.com/Antonboom/[email protected]

Anton Telyshev 12 Aug 30, 2022
Go linter which checks for dangerous unicode character sequences

bidichk - checks for dangerous unicode character sequences bidichk finds dangerous unicode character sequences in Go source files. Considered dangerou

Lucas Bremgartner 27 Oct 5, 2022
Go linter that checks types that are json encoded - reports unsupported types and unnecessary error checks

Checks types passed to the json encoding functions. Reports unsupported types and reports occations, where the check for the returned error can be omited.

Lucas Bremgartner 28 Oct 7, 2022
Linter for PostgreSQL

Использование Проверить миграции: oh-my-pg-linter check ./migrations/*.sql Добавить директории с дополнительными проверками (переопределение - кто пос

Denis Kayumov 0 Nov 25, 2021
containedctx detects is a linter that detects struct contained context.Context field

containedctx containedctx detects is a linter that detects struct contained context.Context field Instruction go install github.com/sivchari/contained

sivchari 12 Oct 22, 2022
World's spookiest linter

nosleep The world's spookiest linter nosleep is a golang-ci compatible linter which checks for and fails if it detects usages of time.Sleep. Why did y

Elliot Williams 1 Oct 15, 2022
Go linter to analyze expression groups: require 'import' declaration groups

grouper — a Go linter to analyze expression groups Installation

null 0 Jun 19, 2022
funcresult — a Go linter to analyze function result parameters

Go linter to analyze function result parameters: require named / unnamed function result parameters

null 0 Jan 27, 2022
nostdglobals is a simple Go linter that checks for usages of global variables defined in the go standard library

nostdglobals is a simple Go linter that checks for usages of global variables defined in the go standard library

Nassos Kat 1 Feb 17, 2022
Goalinter-v1: Goa framework (version1) linter

goavl: Goa framework (ver1) linter goavlは、goa version1(フォーク版)のlinterです。開発目的は、goa

CHIKAMATSU Naohiro 1 Jul 28, 2022
Linter for Go's fmt.Errorf message

wrapmsg wrapmsg is Go code linter. this enforces fmt.Errorf's message when you wrap error. Example // OK ???? if err := pkg.Cause(); err != nil { re

Shinnosuke Sawada 10 Nov 19, 2022
misspelled word linter for Go comments, string literals and embedded files

gospel The gospel program lints Go source files for misspellings in comments, strings and embedded files. It uses hunspell to identify misspellings an

Dan Kortschak 30 Aug 6, 2022
GAAD (Go Advanced Audio Decoder)

GAAD (Go Advanced Audio Decoder) Package currently provides AAC parsing capabilities. This package performs a full parse of AAC-LC and HE-AACv1 bitstr

null 107 Oct 24, 2022
pg_timetable: Advanced scheduling for PostgreSQL

pg_timetable: Advanced scheduling for PostgreSQL pg_timetable is an advanced job scheduler for PostgreSQL, offering many advantages over traditional s

CYBERTEC PostgreSQL International GmbH 808 Nov 25, 2022
Fortio load testing library, command line tool, advanced echo server and web UI in go (golang). Allows to specify a set query-per-second load and record latency histograms and other useful stats.

Fortio Fortio (Φορτίο) started as, and is, Istio's load testing tool and now graduated to be its own project. Fortio is also used by, among others, Me

Fortio (Φορτίο) 2.8k Nov 28, 2022
An Advanced HTTP Reverse Proxy with Dynamic Sharding Strategies

Weaver - A modern HTTP Proxy with Advanced features Description Features Installation Architecture Configuration Contributing License Description Weav

Gojek 563 Nov 21, 2022