golangci-lint/vendor/github.com/go-critic/checkers/sloppyReassign_checker.go
David López 37e6995b45 lintpack/gocritic: update lintpack & gocritic versions
update lintpack & gocritic versions to support all the new gocritic checks
2018-12-22 15:34:16 +03:00

81 lines
2.0 KiB
Go

package checkers
import (
"go/ast"
"go/token"
"github.com/go-lintpack/lintpack"
"github.com/go-lintpack/lintpack/astwalk"
"github.com/go-toolsmith/astcast"
"github.com/go-toolsmith/astcopy"
"github.com/go-toolsmith/astequal"
)
func init() {
var info lintpack.CheckerInfo
info.Name = "sloppyReassign"
info.Tags = []string{"diagnostic", "experimental"}
info.Summary = "Detects suspicious/confusing re-assignments"
info.Before = `if err = f(); err != nil { return err }`
info.After = `if err := f(); err != nil { return err }`
collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
return astwalk.WalkerForStmt(&sloppyReassignChecker{ctx: ctx})
})
}
type sloppyReassignChecker struct {
astwalk.WalkHandler
ctx *lintpack.CheckerContext
}
func (c *sloppyReassignChecker) VisitStmt(stmt ast.Stmt) {
// Right now only check assignments in if statements init.
ifStmt := astcast.ToIfStmt(stmt)
assign := astcast.ToAssignStmt(ifStmt.Init)
if assign.Tok != token.ASSIGN {
return
}
// TODO(Quasilyte): is handling of multi-value assignments worthwhile?
if len(assign.Lhs) != 1 || len(assign.Rhs) != 1 {
return
}
// TODO(Quasilyte): handle not only the simplest, return-only case.
body := ifStmt.Body.List
if len(body) != 1 {
return
}
// Variable that is being re-assigned.
reAssigned := astcast.ToIdent(assign.Lhs[0])
if reAssigned.Name == "" {
return
}
// TODO(Quasilyte): handle not only nil comparisons.
eqToNil := &ast.BinaryExpr{
Op: token.NEQ,
X: reAssigned,
Y: &ast.Ident{Name: "nil"},
}
if !astequal.Expr(ifStmt.Cond, eqToNil) {
return
}
results := astcast.ToReturnStmt(body[0]).Results
for _, res := range results {
if astequal.Expr(reAssigned, res) {
c.warnAssignToDefine(assign, reAssigned.Name)
break
}
}
}
func (c *sloppyReassignChecker) warnAssignToDefine(assign *ast.AssignStmt, name string) {
suggest := astcopy.AssignStmt(assign)
suggest.Tok = token.DEFINE
c.ctx.Warn(assign, "re-assignment to `%s` can be replaced with `%s`", name, suggest)
}