81 lines
2.0 KiB
Go
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)
|
|
}
|