Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 63cdf81
Showing
5 changed files
with
198 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
Copyright (c) 2013 Kamil Kisiel | ||
|
||
Permission is hereby granted, free of charge, to any person | ||
obtaining a copy of this software and associated documentation | ||
files (the "Software"), to deal in the Software without | ||
restriction, including without limitation the rights to use, | ||
copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the | ||
Software is furnished to do so, subject to the following | ||
conditions: | ||
|
||
The above copyright notice and this permission notice shall be | ||
included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
errcheck | ||
========= | ||
|
||
errcheck is a program for checking for unchecked errors in go programs. | ||
|
||
Install | ||
------- | ||
|
||
go get github.com/kisielk/errcheck | ||
|
||
Note that errcheck depends on the go/types package which is currently only available in go tip. | ||
|
||
Use | ||
--- | ||
|
||
For basic usage, just give the package path of interest as the first | ||
argument: | ||
|
||
errcheck github.com/kisielk/errcheck/example | ||
|
||
The output format is incomplete. |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package main | ||
|
||
import "fmt" | ||
|
||
func a() error { | ||
fmt.Println("this function returns an error") | ||
return nil | ||
} | ||
|
||
func b() (int, error) { | ||
fmt.Println("this function returns an int and an error") | ||
return 0, nil | ||
} | ||
|
||
func main() { | ||
_ = a() | ||
a() | ||
_, _ = b() | ||
b() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"go/ast" | ||
"go/build" | ||
"go/parser" | ||
"go/token" | ||
"go/types" | ||
"os" | ||
"path/filepath" | ||
) | ||
|
||
func main() { | ||
flag.Parse() | ||
pkgName := flag.Arg(0) | ||
if pkgName == "" { | ||
fmt.Fprintln(os.Stderr, "you must specify a package") | ||
flag.Usage() | ||
os.Exit(1) | ||
} | ||
|
||
pkg, err := build.Import(pkgName, ".", 0) | ||
if err != nil { | ||
fmt.Fprintln(os.Stderr, "could not import %s: %s", pkgName, err) | ||
} | ||
|
||
for _, fileName := range pkg.GoFiles { | ||
filePath := filepath.Join(pkg.Dir, fileName) | ||
if err := checkFile(filePath); err != nil { | ||
fmt.Fprintln(os.Stderr, "could not check %s: %s", filePath, err) | ||
} | ||
} | ||
} | ||
|
||
func checkFile(fileName string) error { | ||
fset := token.NewFileSet() | ||
|
||
astFile, err := parser.ParseFile(fset, fileName, nil, parser.ParseComments) | ||
if err != nil { | ||
return fmt.Errorf("could not parse: %s", err) | ||
} | ||
|
||
callTypes := make(map[*ast.CallExpr]types.Type) | ||
|
||
exprFn := func(x ast.Expr, typ types.Type, val interface{}) { | ||
call, ok := x.(*ast.CallExpr) | ||
if !ok { | ||
return | ||
} | ||
callTypes[call] = typ | ||
} | ||
context := types.Context{ | ||
Expr: exprFn, | ||
} | ||
_, err = context.Check(fset, []*ast.File{astFile}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
visitor := func(node ast.Node) { | ||
n, ok := node.(*ast.ExprStmt) | ||
if !ok { | ||
return | ||
} | ||
|
||
// Check for a call expression | ||
call, ok := n.X.(*ast.CallExpr) | ||
if !ok { | ||
return | ||
} | ||
|
||
var fun *ast.Ident | ||
switch exp := call.Fun.(type) { | ||
case (*ast.Ident): | ||
fun = exp | ||
case (*ast.SelectorExpr): | ||
fun = exp.Sel | ||
default: | ||
fmt.Fprintf(os.Stderr, "unknown call: %T %+v\n", exp, exp) | ||
return | ||
} | ||
|
||
// Get the types | ||
callType := callTypes[call] | ||
|
||
unchecked := false | ||
|
||
switch t := callType.(type) { | ||
case *types.NamedType: | ||
// Single return | ||
if isErrorType(t.Obj) { | ||
unchecked = true | ||
} | ||
case *types.Result: | ||
// Multiple returns | ||
for _, v := range t.Values { | ||
nt, ok := v.Type.(*types.NamedType) | ||
if !ok { | ||
continue | ||
} | ||
if isErrorType(nt.Obj) { | ||
unchecked = true | ||
break | ||
} | ||
} | ||
} | ||
|
||
if unchecked { | ||
fmt.Fprintf(os.Stderr, "%s\n", fset.Position(fun.NamePos)) | ||
} | ||
} | ||
|
||
ast.Walk(visitorFunc(visitor), astFile) | ||
ast.Fprint(os.Stderr, fset, astFile, nil) | ||
|
||
return nil | ||
} | ||
|
||
type obj interface { | ||
GetPkg() *types.Package | ||
GetName() string | ||
} | ||
|
||
func isErrorType(v obj) bool { | ||
return v.GetPkg() == nil && v.GetName() == "error" | ||
} | ||
|
||
type visitorFunc func(node ast.Node) | ||
|
||
func (v visitorFunc) Visit(node ast.Node) ast.Visitor { | ||
v(node) | ||
return v | ||
} |