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
/
assignOp_checker.go
81 lines (72 loc) · 2.07 KB
/
assignOp_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
73
74
75
76
77
78
79
80
81
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/astequal"
"github.com/go-toolsmith/typep"
)
func init() {
var info lintpack.CheckerInfo
info.Name = "assignOp"
info.Tags = []string{"style"}
info.Summary = "Detects assignments that can be simplified by using assignment operators"
info.Before = `x = x * 2`
info.After = `x *= 2`
collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
return astwalk.WalkerForStmt(&assignOpChecker{ctx: ctx})
})
}
type assignOpChecker struct {
astwalk.WalkHandler
ctx *lintpack.CheckerContext
}
func (c *assignOpChecker) VisitStmt(stmt ast.Stmt) {
assign, ok := stmt.(*ast.AssignStmt)
cond := ok &&
assign.Tok == token.ASSIGN &&
len(assign.Lhs) == 1 &&
len(assign.Rhs) == 1 &&
typep.SideEffectFree(c.ctx.TypesInfo, assign.Lhs[0])
if !cond {
return
}
// TODO(quasilyte): can take commutativity into account.
expr, ok := assign.Rhs[0].(*ast.BinaryExpr)
if !ok || !astequal.Expr(assign.Lhs[0], expr.X) {
return
}
// TODO(quasilyte): perform unparen?
switch expr.Op {
case token.MUL:
c.warn(assign, token.MUL_ASSIGN, expr.Y)
case token.QUO:
c.warn(assign, token.QUO_ASSIGN, expr.Y)
case token.REM:
c.warn(assign, token.REM_ASSIGN, expr.Y)
case token.ADD:
c.warn(assign, token.ADD_ASSIGN, expr.Y)
case token.SUB:
c.warn(assign, token.SUB_ASSIGN, expr.Y)
case token.AND:
c.warn(assign, token.AND_ASSIGN, expr.Y)
case token.OR:
c.warn(assign, token.OR_ASSIGN, expr.Y)
case token.XOR:
c.warn(assign, token.XOR_ASSIGN, expr.Y)
case token.SHL:
c.warn(assign, token.SHL_ASSIGN, expr.Y)
case token.SHR:
c.warn(assign, token.SHR_ASSIGN, expr.Y)
case token.AND_NOT:
c.warn(assign, token.AND_NOT_ASSIGN, expr.Y)
}
}
func (c *assignOpChecker) warn(cause *ast.AssignStmt, op token.Token, rhs ast.Expr) {
suggestion := astcopy.AssignStmt(cause)
suggestion.Tok = op
suggestion.Rhs[0] = rhs
c.ctx.Warn(cause, "replace `%s` with `%s`", cause, suggestion)
}