From 4def8bfe06266ef6256aa29eccdb027da8467671 Mon Sep 17 00:00:00 2001 From: Charith Ellawala Date: Mon, 18 Feb 2019 22:15:10 +0000 Subject: [PATCH] Casting variables or function results --- durationcheck.go | 28 ++++++++++++++-------------- testdata/src/a/a.go | 13 +++++++++++++ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/durationcheck.go b/durationcheck.go index 895a14c..da1db5f 100644 --- a/durationcheck.go +++ b/durationcheck.go @@ -64,39 +64,39 @@ func check(pass *analysis.Pass) func(ast.Node) { return } - if isDuration(x) && isDuration(y) { + if isDuration(x.Type) && isDuration(y.Type) { // check that both sides are acceptable expressions - if isUnacceptableExpr(expr.X) && isUnacceptableExpr(expr.Y) { + if isUnacceptableExpr(pass, expr.X) && isUnacceptableExpr(pass, expr.Y) { pass.Reportf(expr.Pos(), "Multiplication of durations: `%s`", formatNode(expr)) } } } } -func isDuration(x types.TypeAndValue) bool { - return x.Type.String() == "time.Duration" +func isDuration(x types.Type) bool { + return x.String() == "time.Duration" } // isUnacceptableExpr returns true if the argument is not an acceptable time.Duration expression -func isUnacceptableExpr(expr ast.Expr) bool { +func isUnacceptableExpr(pass *analysis.Pass, expr ast.Expr) bool { switch e := expr.(type) { case *ast.BasicLit: // constants are acceptable return false case *ast.CallExpr: // explicit casting of constants such as `time.Duration(10)` is acceptable - return !isConstExprCastToDuration(e) + return !isAcceptableCast(pass, e) } return true } -// isConstExprCastToDuration returns true if the argument is a constant expression cast to time.Duration -func isConstExprCastToDuration(e *ast.CallExpr) bool { +// isAcceptableCast returns true if the argument is a constant expression cast to time.Duration +func isAcceptableCast(pass *analysis.Pass, e *ast.CallExpr) bool { // check that there's a single argument if len(e.Args) != 1 { return false } - // check that the argument is a constant expression - if !allConstArgs(e.Args[0]) { + // check that the argument is acceptable + if !isAcceptableCastArg(pass, e.Args[0]) { return false } @@ -118,15 +118,15 @@ func isConstExprCastToDuration(e *ast.CallExpr) bool { return selector.Sel.Name == "Duration" } -// allConstArgs checks that the argument is a constant expression -func allConstArgs(n ast.Node) bool { +func isAcceptableCastArg(pass *analysis.Pass, n ast.Expr) bool { switch e := n.(type) { case *ast.BasicLit: return true case *ast.BinaryExpr: - return allConstArgs(e.X) && allConstArgs(e.Y) + return isAcceptableCastArg(pass, e.X) && isAcceptableCastArg(pass, e.Y) default: - return false + argType := pass.TypesInfo.TypeOf(n) + return !isDuration(argType) } } diff --git a/testdata/src/a/a.go b/testdata/src/a/a.go index 904ad3c..be7a537 100644 --- a/testdata/src/a/a.go +++ b/testdata/src/a/a.go @@ -8,6 +8,7 @@ const timeout = 10 * time.Second func multiplyTwoDurations() { x := 30 * time.Second + y := 10 _ = time.Second * 30 @@ -19,6 +20,14 @@ func multiplyTwoDurations() { _ = time.Second * time.Duration(10+20*5) + _ = time.Duration(y) * time.Second + + _ = time.Second * time.Duration(y) + + _ = time.Duration(someDurationMillis()) * time.Millisecond + + _ = time.Millisecond * time.Duration(someDurationMillis()) + _ = timeout / time.Millisecond _ = timeout * time.Millisecond // want `Multiplication of durations` @@ -43,3 +52,7 @@ func multiplyTwoDurations() { func someDuration() time.Duration { return 10 * time.Second } + +func someDurationMillis() int { + return 10 +}