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
/
valSwap_checker.go
64 lines (55 loc) · 1.58 KB
/
valSwap_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
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/astequal"
)
func init() {
var info lintpack.CheckerInfo
info.Name = "valSwap"
info.Tags = []string{"style", "experimental"}
info.Summary = "Detects value swapping code that are not using parallel assignment"
info.Before = `
tmp := *x
*x = *y
*y = tmp`
info.After = `*x, *y = *y, *x`
collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
return astwalk.WalkerForStmtList(&valSwapChecker{ctx: ctx})
})
}
type valSwapChecker struct {
astwalk.WalkHandler
ctx *lintpack.CheckerContext
}
func (c *valSwapChecker) VisitStmtList(list []ast.Stmt) {
for len(list) >= 3 {
tmpAssign := astcast.ToAssignStmt(list[0])
assignX := astcast.ToAssignStmt(list[1])
assignY := astcast.ToAssignStmt(list[2])
cond := c.isSimpleAssign(tmpAssign) &&
c.isSimpleAssign(assignX) &&
c.isSimpleAssign(assignY) &&
assignX.Tok == token.ASSIGN &&
assignY.Tok == token.ASSIGN &&
astequal.Expr(assignX.Lhs[0], tmpAssign.Rhs[0]) &&
astequal.Expr(assignX.Rhs[0], assignY.Lhs[0]) &&
astequal.Expr(assignY.Rhs[0], tmpAssign.Lhs[0])
if cond {
c.warn(tmpAssign, assignX.Lhs[0], assignY.Lhs[0])
list = list[3:]
} else {
list = list[1:]
}
}
}
func (c *valSwapChecker) isSimpleAssign(x *ast.AssignStmt) bool {
return len(x.Lhs) == 1 && len(x.Rhs) == 1
}
func (c *valSwapChecker) warn(cause, x, y ast.Node) {
c.ctx.Warn(cause, "can re-write as `%s, %s = %s, %s`",
x, y, y, x)
}