aboutsummaryrefslogtreecommitdiffstats
path: root/tools/syz-linter
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2025-01-17 10:28:37 +0100
committerDmitry Vyukov <dvyukov@google.com>2025-01-17 10:02:07 +0000
commitbb91bdd45a9407e6594eb36266e74db1e50210a0 (patch)
treef6b2a69ef250d37acdcf3006dfa349d9697a1d23 /tools/syz-linter
parent5d04aae8969f6c72318ce0a4cde4f027766b1a55 (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.go42
-rw-r--r--tools/syz-linter/testdata/src/lintertest/lintertest.go13
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
+ }
+}