1 Star 0 Fork 0

lonely/gometalinter

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
errcheck.go 3.71 KB
一键复制 编辑 原始数据 按行查看 历史
Bradley Falzon 提交于 2017-11-14 04:02 . Update honnef.co tools (#386)
package errcheck
import (
"go/types"
"honnef.co/go/tools/functions"
"honnef.co/go/tools/lint"
"honnef.co/go/tools/ssa"
)
type Checker struct {
funcDescs *functions.Descriptions
}
func NewChecker() *Checker {
return &Checker{}
}
func (*Checker) Name() string { return "errcheck" }
func (*Checker) Prefix() string { return "ERR" }
func (c *Checker) Funcs() map[string]lint.Func {
return map[string]lint.Func{
"ERR1000": c.CheckErrcheck,
}
}
func (c *Checker) Init(prog *lint.Program) {
c.funcDescs = functions.NewDescriptions(prog.SSA)
}
func (c *Checker) CheckErrcheck(j *lint.Job) {
for _, ssafn := range j.Program.InitialFunctions {
for _, b := range ssafn.Blocks {
for _, ins := range b.Instrs {
ssacall, ok := ins.(ssa.CallInstruction)
if !ok {
continue
}
switch lint.CallName(ssacall.Common()) {
case "fmt.Print", "fmt.Println", "fmt.Printf":
continue
}
isRecover := false
if builtin, ok := ssacall.Common().Value.(*ssa.Builtin); ok {
isRecover = ok && builtin.Name() == "recover"
}
switch ins := ins.(type) {
case ssa.Value:
refs := ins.Referrers()
if refs == nil || len(lint.FilterDebug(*refs)) != 0 {
continue
}
case ssa.Instruction:
// will be a 'go' or 'defer', neither of which has usable return values
default:
// shouldn't happen
continue
}
if ssacall.Common().IsInvoke() {
if sc, ok := ssacall.Common().Value.(*ssa.Call); ok {
// TODO(dh): support multiple levels of
// interfaces, not just one
ssafn := sc.Common().StaticCallee()
if ssafn != nil {
ct := c.funcDescs.Get(ssafn).ConcreteReturnTypes
// TODO(dh): support >1 concrete types
if ct != nil && len(ct) == 1 {
// TODO(dh): do we have access to a
// cached method set somewhere?
ms := types.NewMethodSet(ct[0].At(ct[0].Len() - 1).Type())
// TODO(dh): where can we get the pkg
// for Lookup? Passing nil works fine
// for exported methods, but will fail
// on unexported ones
// TODO(dh): holy nesting and poor
// variable names, clean this up
fn, _ := ms.Lookup(nil, ssacall.Common().Method.Name()).Obj().(*types.Func)
if fn != nil {
ssafn := j.Program.SSA.FuncValue(fn)
if ssafn != nil {
if c.funcDescs.Get(ssafn).NilError {
continue
}
}
}
}
}
}
} else {
ssafn := ssacall.Common().StaticCallee()
if ssafn != nil {
if c.funcDescs.Get(ssafn).NilError {
// Don't complain when the error is known to be nil
continue
}
}
}
switch lint.CallName(ssacall.Common()) {
case "(*os.File).Close":
recv := ssacall.Common().Args[0]
if isReadOnlyFile(recv, nil) {
continue
}
}
res := ssacall.Common().Signature().Results()
if res.Len() == 0 {
continue
}
if !isRecover {
last := res.At(res.Len() - 1)
if types.TypeString(last.Type(), nil) != "error" {
continue
}
}
j.Errorf(ins, "unchecked error")
}
}
}
}
func isReadOnlyFile(val ssa.Value, seen map[ssa.Value]bool) bool {
if seen == nil {
seen = map[ssa.Value]bool{}
}
if seen[val] {
return true
}
seen[val] = true
switch val := val.(type) {
case *ssa.Phi:
for _, edge := range val.Edges {
if !isReadOnlyFile(edge, seen) {
return false
}
}
return true
case *ssa.Extract:
call, ok := val.Tuple.(*ssa.Call)
if !ok {
return false
}
switch lint.CallName(call.Common()) {
case "os.Open":
return true
case "os.OpenFile":
flags, ok := call.Common().Args[1].(*ssa.Const)
return ok && flags.Uint64() == 0
}
return false
}
return false
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/lonely0422/gometalinter.git
git@gitee.com:lonely0422/gometalinter.git
lonely0422
gometalinter
gometalinter
v2.0.4

搜索帮助

0d507c66 1850385 C8b1a773 1850385