Skip to content
This repository has been archived by the owner on Jun 2, 2023. It is now read-only.

Sync with main repo #4

Closed
wants to merge 64 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
4ad8331
Only ignore select functions from the fmt package by default.
kisielk May 10, 2018
a174de0
Fix tests
kisielk May 10, 2018
e5700e7
Merge pull request #141 from kisielk/ignore-fmt
kisielk May 17, 2018
af5c046
check reciever type aginst exclude
louissobel Apr 7, 2018
10d5a4d
ignore embedded
louissobel Apr 7, 2018
2ae7c6b
exclude hash.Hash.Write
louissobel Apr 7, 2018
05dbe35
touch up test a bit
louissobel Apr 7, 2018
12b83e1
improvements
louissobel Apr 8, 2018
070cb41
fix merge
louissobel May 19, 2018
cd18fe7
documentation work
louissobel May 19, 2018
55d8f50
Merge pull request #137 from louissobel/add-receiver-checking-against…
kisielk May 22, 2018
8c5d48a
prototyping for skiping generated code
Jun 25, 2018
156d684
add test case for WithouGeneratedCode option
Jun 29, 2018
dbecf20
refactor WithoutGeneratedCode functions
Jun 29, 2018
e96dacd
Merge pull request #145 from bananaumai/skip-generated-code-proto
kisielk Jul 1, 2018
2d6afb3
Support go modules
suzmue Jul 31, 2018
fdf7ba3
Test unchecked errors in a test file
suzmue Jul 31, 2018
e3cdf7f
Update documentation to reflect dependency on go/packages
suzmue Jul 31, 2018
daba332
Update documentation about packages using cgo
suzmue Aug 1, 2018
aa36670
Stop when there are type check errors
suzmue Aug 2, 2018
57a9ef0
update to version of go/packages with fixed race condition
suzmue Aug 2, 2018
8c8888e
Test versions of Go > 1.7
suzmue Aug 2, 2018
ac1b57d
Revert "Test versions of Go > 1.7"
suzmue Aug 2, 2018
2f843a1
run main test on _test files
suzmue Aug 3, 2018
355fb1c
Merge pull request #148 from suzmue/typecheck-with-gopackages
kisielk Aug 7, 2018
1787c4b
Revert "Merge pull request #148 from suzmue/typecheck-with-gopackages"
dominikh Aug 7, 2018
122a336
Add support for excluding fmt.Fprint* to a buffer type
Nov 14, 2018
0f77138
Change the exclude format to explicitly list the arg type or name.
Nov 15, 2018
fa09a99
Change the exclude format to explicitly list the arg type or name.
Nov 15, 2018
90fdeb0
Merge branch 'fprintf' of github.com:yasushi-saito/errcheck into fprintf
Dec 1, 2018
0e51b56
Remove tests that use strings.Builder.
Dec 13, 2018
9e64295
Merge pull request #157 from yasushi-saito/fprintf
kisielk Dec 27, 2018
3d557ba
Add test for build tags
nmiyake Dec 30, 2018
8e9c2a7
Fix test for Go 1.10
nmiyake Dec 30, 2018
3a04621
Merge pull request #160 from nmiyake/addBuildTagsTestMaster
kisielk Dec 30, 2018
85e9ef5
Revert "Revert "Merge pull request #148 from suzmue/typecheck-with-go…
domgreen Oct 31, 2018
4414a0b
revert revert of merge and fix fields
domgreen Oct 31, 2018
86292d1
upgrade and vendor deps
domgreen Oct 31, 2018
edbb333
Remove vendor dir
coopernurse Dec 26, 2018
e406a24
remove errcheck binary
coopernurse Dec 26, 2018
b41a7d8
#155 - Fix compilation errors after rebasing from upstream/master
coopernurse Dec 28, 2018
6bfc115
Add test for build tags
nmiyake Dec 30, 2018
e14f8d5
Merge pull request #159 from coopernurse/155-go-modules
kisielk Jan 3, 2019
4f924b3
errcheck_test.go: Remove dead code
LukeShu Jun 28, 2019
3bf72b1
errcheck_test.go: Better error reporting for debugging
LukeShu Jun 28, 2019
ff068b1
.travis.yml: Grow the build matrix, pin golang.org/x/tools version
LukeShu Jun 28, 2019
f4fbc7c
.travis.yml, tests: Update for GO111MODULE=on [ci-skip]
LukeShu Jun 28, 2019
2050f4e
Fix regression that occurs when GO111MODULE=on
LukeShu Jun 28, 2019
aaeeb43
Use svg for ci build graphics
stephengroat Feb 29, 2020
dd5e04e
Update .travis.yml
kisielk Mar 27, 2020
f02139a
Merge pull request #168 from LukeShu/for-upstream-go112
kisielk Mar 27, 2020
ff9d777
Update .travis.yml
kisielk Mar 27, 2020
1618cdc
Merge pull request #177 from stephengroat/patch-1
kisielk Mar 27, 2020
e327f15
Fix #139: Add example of excluding a call to a vendored dependency
Oct 18, 2019
77437ce
Upgrade golang.org/x/tools to latest
echlebek Jun 19, 2020
175c8b8
Drop support for Go 1.10 and Go 1.9
echlebek Jun 19, 2020
4769c2f
Merge pull request #179 from kisielk/fix-go-114
kisielk Jun 19, 2020
28a963f
Merge pull request #173 from jdkaplan/issue/139
kisielk Jun 19, 2020
b367e75
Limit the amount of memory errcheck uses with smarter goroutine sched…
dragonsinth Jun 19, 2020
f760b69
Merge pull request #178 from dragonsinth/memory
kisielk Jun 19, 2020
d6d3f06
Add some lines to go.sum after running `go build`
echlebek Jun 20, 2020
6b5513d
Ignore comments and empty lines in excludes files
mbyio Jun 30, 2020
082960c
Merge pull request #181 from mbyio/master
kisielk Jul 14, 2020
c491130
Correction: requires Go 1.11.x
echlebek Jul 14, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 29 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,36 @@ sudo: false

matrix:
include:
- go: "1.6"
- go: "1.7"
- go: "1.8"
- go: "1.9"
- go: "1.10"
- go: "1.11.x"
env: {GO111MODULE: "off"}
- go: "1.11.x"
env: {GO111MODULE: "on"}
- go: "1.12.x"
env: {GO111MODULE: "off"}
- go: "1.12.x"
env: {GO111MODULE: "on"}
- go: "1.13.x"
env: {GO111MODULE: "off"}
- go: "1.13.x"
env: {GO111MODULE: "on"}
- go: "1.14.x"
env: {GO111MODULE: "off"}
- go: "1.14.x"
env: {GO111MODULE: "on"}
- go: "tip"
env: {GO111MODULE: "off"}
- go: "tip"
env: {GO111MODULE: "on"}

install: |
if test -z "$(go env GOMOD)"; then
go get -d -t ./... &&
ver=$(sed -n '/^require/s/.*[ -]//p' go.mod) &&
(
cd "$(go env GOPATH)/src/golang.org/x/tools" &&
git checkout "$ver"
)
fi

script:
- go test -race ./...
30 changes: 22 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

errcheck is a program for checking for unchecked errors in go programs.

[![Build Status](https://travis-ci.org/kisielk/errcheck.png?branch=master)](https://travis-ci.org/kisielk/errcheck)
[![Build Status](https://travis-ci.org/kisielk/errcheck.svg?branch=master)](https://travis-ci.org/kisielk/errcheck)

## Install

go get -u github.com/kisielk/errcheck

errcheck requires Go 1.6 or newer and depends on the package go/loader from the golang.org/x/tools repository.
errcheck requires Go 1.11 or newer, and depends on the package go/packages from the golang.org/x/tools repository.

## Use

Expand Down Expand Up @@ -46,16 +46,33 @@ be excluded.

The file should contain one function signature per line. The format for function signatures is
`package.FunctionName` while for methods it's `(package.Receiver).MethodName` for value receivers
and `(*package.Receiver).MethodName` for pointer receivers.
and `(*package.Receiver).MethodName` for pointer receivers. If the function name is followed by string of form `(TYPE)`, then
the the function call is excluded only if the type of the first argument is `TYPE`. It also accepts a special suffix
`(os.Stdout)` and `(os.Stderr)`, which excludes the function only when the first argument is a literal `os.Stdout` or `os.Stderr`.

An example of an exclude file is:

io/ioutil.ReadFile
io.Copy(*bytes.Buffer)
io.Copy(os.Stdout)

// Sometimes we don't care if a HTTP request fails.
(*net/http.Client).Do

The exclude list is combined with an internal list for functions in the Go standard library that
have an error return type but are documented to never return an error.

When using vendored dependencies, specify the full import path. For example:
* Your project's import path is `example.com/yourpkg`
* You've vendored `example.net/fmt2` as `vendor/example.net/fmt2`
* You want to exclude `fmt2.Println` from error checking

In this case, add this line to your exclude file:
```
example.com/yourpkg/vendor/example.net/fmt2.Println
```

Empty lines and lines starting with `//` are ignored.

### The deprecated method

Expand Down Expand Up @@ -94,12 +111,9 @@ no arguments.

## Cgo

Currently errcheck is unable to check packages that `import "C"` due to limitations
in the importer.
Currently errcheck is unable to check packages that import "C" due to limitations in the importer when used with versions earlier than Go 1.11.

However, you can use errcheck on packages that depend on those which use cgo. In
order for this to work you need to `go install` the cgo dependencies before running
errcheck on the dependent packages.
However, you can use errcheck on packages that depend on those which use cgo. In order for this to work you need to go install the cgo dependencies before running errcheck on the dependent packages.

See https://github.com/kisielk/errcheck/issues/16 for more details.

Expand Down
9 changes: 4 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module "github.com/kisielk/errcheck"
module github.com/kisielk/errcheck

require (
"github.com/kisielk/gotool" v1.0.0
"golang.org/x/tools" v0.0.0-20180221164845-07fd8470d635
)
go 1.14

require golang.org/x/tools v0.0.0-20200619180055-7c47624df98f
20 changes: 20 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f h1:tuwaIjfUa6eI6REiNueIxvNm1popyPUnqWga83S7U0o=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
144 changes: 144 additions & 0 deletions internal/errcheck/embedded_walker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package errcheck

import (
"fmt"
"go/types"
)

// walkThroughEmbeddedInterfaces returns a slice of Interfaces that
// we need to walk through in order to reach the actual definition,
// in an Interface, of the method selected by the given selection.
//
// false will be returned in the second return value if:
// - the right side of the selection is not a function
// - the actual definition of the function is not in an Interface
//
// The returned slice will contain all the interface types that need
// to be walked through to reach the actual definition.
//
// For example, say we have:
//
// type Inner interface {Method()}
// type Middle interface {Inner}
// type Outer interface {Middle}
// type T struct {Outer}
// type U struct {T}
// type V struct {U}
//
// And then the selector:
//
// V.Method
//
// We'll return [Outer, Middle, Inner] by first walking through the embedded structs
// until we reach the Outer interface, then descending through the embedded interfaces
// until we find the one that actually explicitly defines Method.
func walkThroughEmbeddedInterfaces(sel *types.Selection) ([]types.Type, bool) {
fn, ok := sel.Obj().(*types.Func)
if !ok {
return nil, false
}

// Start off at the receiver.
currentT := sel.Recv()

// First, we can walk through any Struct fields provided
// by the selection Index() method. We ignore the last
// index because it would give the method itself.
indexes := sel.Index()
for _, fieldIndex := range indexes[:len(indexes)-1] {
currentT = getTypeAtFieldIndex(currentT, fieldIndex)
}

// Now currentT is either a type implementing the actual function,
// an Invalid type (if the receiver is a package), or an interface.
//
// If it's not an Interface, then we're done, as this function
// only cares about Interface-defined functions.
//
// If it is an Interface, we potentially need to continue digging until
// we find the Interface that actually explicitly defines the function.
interfaceT, ok := maybeUnname(currentT).(*types.Interface)
if !ok {
return nil, false
}

// The first interface we pass through is this one we've found. We return the possibly
// wrapping types.Named because it is more useful to work with for callers.
result := []types.Type{currentT}

// If this interface itself explicitly defines the given method
// then we're done digging.
for !explicitlyDefinesMethod(interfaceT, fn) {
// Otherwise, we find which of the embedded interfaces _does_
// define the method, add it to our list, and loop.
namedInterfaceT, ok := getEmbeddedInterfaceDefiningMethod(interfaceT, fn)
if !ok {
// This should be impossible as long as we type-checked: either the
// interface or one of its embedded ones must implement the method...
panic(fmt.Sprintf("either %v or one of its embedded interfaces must implement %v", currentT, fn))
}
result = append(result, namedInterfaceT)
interfaceT = namedInterfaceT.Underlying().(*types.Interface)
}

return result, true
}

func getTypeAtFieldIndex(startingAt types.Type, fieldIndex int) types.Type {
t := maybeUnname(maybeDereference(startingAt))
s, ok := t.(*types.Struct)
if !ok {
panic(fmt.Sprintf("cannot get Field of a type that is not a struct, got a %T", t))
}

return s.Field(fieldIndex).Type()
}

// getEmbeddedInterfaceDefiningMethod searches through any embedded interfaces of the
// passed interface searching for one that defines the given function. If found, the
// types.Named wrapping that interface will be returned along with true in the second value.
//
// If no such embedded interface is found, nil and false are returned.
func getEmbeddedInterfaceDefiningMethod(interfaceT *types.Interface, fn *types.Func) (*types.Named, bool) {
for i := 0; i < interfaceT.NumEmbeddeds(); i++ {
embedded := interfaceT.Embedded(i)
if definesMethod(embedded.Underlying().(*types.Interface), fn) {
return embedded, true
}
}
return nil, false
}

func explicitlyDefinesMethod(interfaceT *types.Interface, fn *types.Func) bool {
for i := 0; i < interfaceT.NumExplicitMethods(); i++ {
if interfaceT.ExplicitMethod(i) == fn {
return true
}
}
return false
}

func definesMethod(interfaceT *types.Interface, fn *types.Func) bool {
for i := 0; i < interfaceT.NumMethods(); i++ {
if interfaceT.Method(i) == fn {
return true
}
}
return false
}

func maybeDereference(t types.Type) types.Type {
p, ok := t.(*types.Pointer)
if ok {
return p.Elem()
}
return t
}

func maybeUnname(t types.Type) types.Type {
n, ok := t.(*types.Named)
if ok {
return n.Underlying()
}
return t
}
93 changes: 93 additions & 0 deletions internal/errcheck/embedded_walker_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package errcheck

import (
"go/ast"
"go/parser"
"go/token"
"go/types"
"testing"
)

const commonSrc = `
package p

type Inner struct {}
func (Inner) Method()

type Outer struct {Inner}
type OuterP struct {*Inner}

type InnerInterface interface {
Method()
}

type OuterInterface interface {InnerInterface}
type MiddleInterfaceStruct struct {OuterInterface}
type OuterInterfaceStruct struct {MiddleInterfaceStruct}

var c = `

type testCase struct {
selector string
expectedOk bool
expected []string
}

func TestWalkThroughEmbeddedInterfaces(t *testing.T) {
cases := []testCase{
testCase{"Inner{}.Method", false, nil},
testCase{"(&Inner{}).Method", false, nil},
testCase{"Outer{}.Method", false, nil},
testCase{"InnerInterface.Method", true, []string{"test.InnerInterface"}},
testCase{"OuterInterface.Method", true, []string{"test.OuterInterface", "test.InnerInterface"}},
testCase{"OuterInterfaceStruct.Method", true, []string{"test.OuterInterface", "test.InnerInterface"}},
}

for _, c := range cases {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "test", commonSrc+c.selector, 0)
if err != nil {
t.Fatal(err)
}

conf := types.Config{}
info := types.Info{
Selections: make(map[*ast.SelectorExpr]*types.Selection),
}
_, err = conf.Check("test", fset, []*ast.File{f}, &info)
if err != nil {
t.Fatal(err)
}
ast.Inspect(f, func(n ast.Node) bool {
s, ok := n.(*ast.SelectorExpr)
if ok {
selection, ok := info.Selections[s]
if !ok {
t.Fatalf("no Selection!")
}
ts, ok := walkThroughEmbeddedInterfaces(selection)
if ok != c.expectedOk {
t.Errorf("expected ok %v got %v", c.expectedOk, ok)
return false
}
if !ok {
return false
}

if len(ts) != len(c.expected) {
t.Fatalf("expected %d types, got %d", len(c.expected), len(ts))
}

for i, e := range c.expected {
if e != ts[i].String() {
t.Errorf("mismatch at index %d: expected %s got %s", i, e, ts[i])
}
}
}

return true
})

}

}
Loading