This repository has been archived by the owner on Dec 30, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
sloppyLen_checker.go
72 lines (62 loc) · 1.62 KB
/
sloppyLen_checker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package checkers
import (
"go/ast"
"go/token"
"github.com/go-lintpack/lintpack"
"github.com/go-lintpack/lintpack/astwalk"
"github.com/go-toolsmith/astcopy"
"github.com/go-toolsmith/astfmt"
)
func init() {
var info lintpack.CheckerInfo
info.Name = "sloppyLen"
info.Tags = []string{"style"}
info.Summary = "Detects usage of `len` when result is obvious or doesn't make sense"
info.Before = `
len(arr) >= 0 // Sloppy
len(arr) <= 0 // Sloppy
len(arr) < 0 // Doesn't make sense at all`
info.After = `
len(arr) > 0
len(arr) == 0`
collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
return astwalk.WalkerForExpr(&sloppyLenChecker{ctx: ctx})
})
}
type sloppyLenChecker struct {
astwalk.WalkHandler
ctx *lintpack.CheckerContext
}
func (c *sloppyLenChecker) VisitExpr(x ast.Expr) {
expr, ok := x.(*ast.BinaryExpr)
if !ok {
return
}
if expr.Op == token.LSS || expr.Op == token.GEQ || expr.Op == token.LEQ {
if c.isLenCall(expr.X) && c.isZero(expr.Y) {
c.warn(expr)
}
}
}
func (c *sloppyLenChecker) isLenCall(x ast.Expr) bool {
call, ok := x.(*ast.CallExpr)
return ok && qualifiedName(call.Fun) == "len" && len(call.Args) == 1
}
func (c *sloppyLenChecker) isZero(x ast.Expr) bool {
value, ok := x.(*ast.BasicLit)
return ok && value.Value == "0"
}
func (c *sloppyLenChecker) warn(cause *ast.BinaryExpr) {
info := ""
switch cause.Op {
case token.LSS:
info = "is always false"
case token.GEQ:
info = "is always true"
case token.LEQ:
expr := astcopy.BinaryExpr(cause)
expr.Op = token.EQL
info = astfmt.Sprintf("can be %s", expr)
}
c.ctx.Warn(cause, "%s %s", cause, info)
}