From 577de294c539e9ae7310d186654872ec196c8890 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 31 May 2024 05:39:01 +0100 Subject: [PATCH] SA4006: Fix for compound operators, increment/decrement In the case of compound operators such as +=, -=, etc we need to use the left-hand side to get the value. For IncDec we need a different codepath from AssignStmt altogether. Fixes #1329 --- staticcheck/sa4006/sa4006.go | 26 +++++++++++- .../CheckUnreadVariableValues.go | 40 +++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/staticcheck/sa4006/sa4006.go b/staticcheck/sa4006/sa4006.go index 238309d25..c700583d2 100644 --- a/staticcheck/sa4006/sa4006.go +++ b/staticcheck/sa4006/sa4006.go @@ -3,6 +3,7 @@ package sa4006 import ( "fmt" "go/ast" + "go/token" "honnef.co/go/tools/analysis/code" "honnef.co/go/tools/analysis/facts/generated" @@ -31,7 +32,7 @@ var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ var Analyzer = SCAnalyzer.Analyzer -func run(pass *analysis.Pass) (interface{}, error) { +func run(pass *analysis.Pass) (any, error) { for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { if irutil.IsExample(fn) { continue @@ -99,6 +100,22 @@ func run(pass *analysis.Pass) (interface{}, error) { } ast.Inspect(node, func(node ast.Node) bool { + inc, ok := node.(*ast.IncDecStmt) + if ok { + val, _ := fn.ValueForExpr(inc.X) + if val == nil { + return true + } + if _, ok := val.(*ir.Const); ok { + // a zero-valued constant, for example in 'foo := []string(nil)' + return true + } + if !hasUse(val, nil) { + report.Report(pass, inc, fmt.Sprintf("this value of %s is never used", inc.X)) + } + return true + } + assign, ok := node.(*ast.AssignStmt) if !ok { return true @@ -137,7 +154,12 @@ func run(pass *analysis.Pass) (interface{}, error) { } val, _ := fn.ValueForExpr(rhs) if val == nil { - continue + if assign.Tok != token.ASSIGN { // +=, *=, etc. + val, _ = fn.ValueForExpr(lhs) + } + if val == nil { + continue + } } if _, ok := val.(*ir.Const); ok { diff --git a/staticcheck/sa4006/testdata/go1.0/CheckUnreadVariableValues/CheckUnreadVariableValues.go b/staticcheck/sa4006/testdata/go1.0/CheckUnreadVariableValues/CheckUnreadVariableValues.go index db21d31b5..666dc8cc6 100644 --- a/staticcheck/sa4006/testdata/go1.0/CheckUnreadVariableValues/CheckUnreadVariableValues.go +++ b/staticcheck/sa4006/testdata/go1.0/CheckUnreadVariableValues/CheckUnreadVariableValues.go @@ -142,3 +142,43 @@ func fn10() { } fmt.Println(slice) } + +func issue1329() { + { + n := 1 + n += 1 //@ diag(`this value of n is never used`) + } + { + n := 1 + n ^= 1 //@ diag(`this value of n is never used`) + } + { + n := "" + n += "" //@ diag(`this value of n is never used`) + } + { + n := 1 + n++ //@ diag(`this value of n is never used`) + } + + { + n := 1 + n += 1 + fmt.Println(n) + } + { + n := 1 + n ^= 1 + fmt.Println(n) + } + { + n := "" + n += "" + fmt.Println(n) + } + { + n := 1 + n++ + fmt.Println(n) + } +}