diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2025-01-17 10:28:37 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2025-01-17 10:02:07 +0000 |
| commit | bb91bdd45a9407e6594eb36266e74db1e50210a0 (patch) | |
| tree | f6b2a69ef250d37acdcf3006dfa349d9697a1d23 /tools/syz-linter | |
| parent | 5d04aae8969f6c72318ce0a4cde4f027766b1a55 (diff) | |
tools/syz-linter: suggest use of min/max functions
They are shorter, more readable, and don't require temp vars.
Diffstat (limited to 'tools/syz-linter')
| -rw-r--r-- | tools/syz-linter/linter.go | 42 | ||||
| -rw-r--r-- | tools/syz-linter/testdata/src/lintertest/lintertest.go | 13 |
2 files changed, 55 insertions, 0 deletions
diff --git a/tools/syz-linter/linter.go b/tools/syz-linter/linter.go index 5e0415324..fec7490fc 100644 --- a/tools/syz-linter/linter.go +++ b/tools/syz-linter/linter.go @@ -15,8 +15,10 @@ package main import ( + "bytes" "fmt" "go/ast" + "go/printer" "go/token" "go/types" "regexp" @@ -71,6 +73,8 @@ func run(p *analysis.Pass) (interface{}, error) { pass.checkLogErrorFormat(n) case *ast.GenDecl: pass.checkVarDecl(n) + case *ast.IfStmt: + pass.checkIfStmt(n) } return true }) @@ -340,3 +344,41 @@ func (pass *Pass) checkVarDecl(n *ast.GenDecl) { "Use either \"var x type\" or \"x := val\" or \"x := type(val)\"") } } + +func (pass *Pass) checkIfStmt(n *ast.IfStmt) { + cond, ok := n.Cond.(*ast.BinaryExpr) + if !ok || len(n.Body.List) != 1 { + return + } + assign, ok := n.Body.List[0].(*ast.AssignStmt) + if !ok || assign.Tok != token.ASSIGN || len(assign.Lhs) != 1 { + return + } + isMin := true + switch cond.Op { + case token.GTR, token.GEQ: + case token.LSS, token.LEQ: + isMin = false + default: + return + } + x := pass.nodeString(cond.X) + y := pass.nodeString(cond.Y) + lhs := pass.nodeString(assign.Lhs[0]) + rhs := pass.nodeString(assign.Rhs[0]) + switch { + case x == lhs && y == rhs: + case x == rhs && y == lhs: + isMin = !isMin + default: + return + } + fn := map[bool]string{true: "min", false: "max"}[isMin] + pass.report(n, "Use %v function instead", fn) +} + +func (pass *Pass) nodeString(n ast.Node) string { + w := new(bytes.Buffer) + printer.Fprint(w, pass.Fset, n) + return w.String() +} diff --git a/tools/syz-linter/testdata/src/lintertest/lintertest.go b/tools/syz-linter/testdata/src/lintertest/lintertest.go index 650893be3..d52b087ea 100644 --- a/tools/syz-linter/testdata/src/lintertest/lintertest.go +++ b/tools/syz-linter/testdata/src/lintertest/lintertest.go @@ -123,3 +123,16 @@ func varDecls() { var d int = 0 // want "Don't use both var, type and value in variable declarations" _, _, _, _ = a, b, c, d } + +func minmax() { + x, y := 0, 0 + if x < y + 1 { // want "Use max function instead" + x = y + 1 + } + if x >= y { // want "Use max function instead" + y = x + } + if x > 10 { // want "Use min function instead" + x = 10 + } +} |
