Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions simple/s1012/s1012.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package s1012

import (
"go/ast"

"honnef.co/go/tools/analysis/code"
"honnef.co/go/tools/analysis/edit"
"honnef.co/go/tools/analysis/facts/generated"
Expand Down Expand Up @@ -36,11 +38,23 @@ var (
)

func run(pass *analysis.Pass) (any, error) {
for node, m := range code.Matches(pass, checkTimeSinceQ) {
edits := code.EditMatch(pass, node, m, checkTimeSinceR)
for node := range code.Matches(pass, checkTimeSinceQ) {
call := node.(*ast.CallExpr)
sub := call.Fun.(*ast.SelectorExpr)
now := sub.X.(*ast.CallExpr)
selector, ok := ast.Unparen(now.Fun).(*ast.SelectorExpr)
if !ok {
report.Report(pass, node, "should use time.Since instead of time.Now().Sub", report.FilterGenerated())
continue
}
time := selector.X
replacement := &ast.CallExpr{
Fun: &ast.SelectorExpr{X: time, Sel: ast.NewIdent("Since")},
Args: call.Args,
}
report.Report(pass, node, "should use time.Since instead of time.Now().Sub",
report.FilterGenerated(),
report.Fixes(edit.Fix("Replace with call to time.Since", edits...)))
report.Fixes(edit.Fix("Replace with call to time.Since", edit.ReplaceWithNode(pass.Fset, node, replacement))))
}
return nil, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package pkg

import timelib "time"

func fn() {
t1 := timelib.Now()
_ = timelib.Now().Sub(t1) //@ diag(`time.Since`)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package pkg

import timelib "time"

func fn() {
t1 := timelib.Now()
_ = timelib.Since(t1) //@ diag(`time.Since`)
}
7 changes: 7 additions & 0 deletions simple/s1012/testdata/go1.0/CheckTimeSinceDotImport/dot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package pkg

import . "time"

func fn(t Time) {
_ = Now().Sub(t) //@ diag(`time.Since`)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package pkg

import . "time"

func fn(t Time) {
_ = Now().Sub(t) //@ diag(`time.Since`)
}
29 changes: 23 additions & 6 deletions simple/s1024/s1024.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,39 @@ var Analyzer = SCAnalyzer.Analyzer

var (
checkTimeUntilQ = pattern.MustParse(`(CallExpr (Symbol "(time.Time).Sub") [(CallExpr (Symbol "time.Now") [])])`)
checkTimeUntilR = pattern.MustParse(`(CallExpr (SelectorExpr (Ident "time") (Ident "Until")) [arg])`)
)

func run(pass *analysis.Pass) (any, error) {
for node := range code.Matches(pass, checkTimeUntilQ) {
if sel, ok := node.(*ast.CallExpr).Fun.(*ast.SelectorExpr); ok {
r := pattern.NodeToAST(checkTimeUntilR.Root, map[string]any{"arg": sel.X}).(ast.Node)
call, ok := node.(*ast.CallExpr)
if !ok {
report.Report(pass, node, "should use time.Until instead of t.Sub(time.Now())",
report.FilterGenerated(),
report.MinimumStdlibVersion("go1.8"),
report.Fixes(edit.Fix("Replace with call to time.Until", edit.ReplaceWithNode(pass.Fset, node, r))))
} else {
report.FilterGenerated())
continue
}
selector, ok := call.Fun.(*ast.SelectorExpr)
if !ok {
report.Report(pass, node, "should use time.Until instead of t.Sub(time.Now())",
report.MinimumStdlibVersion("go1.8"),
report.FilterGenerated())
continue
}
timeNow := call.Args[0].(*ast.CallExpr)
nowSelector, ok := ast.Unparen(timeNow.Fun).(*ast.SelectorExpr)
if !ok {
report.Report(pass, node, "should use time.Until instead of t.Sub(time.Now())", report.MinimumStdlibVersion("go1.8"), report.FilterGenerated())
continue
}
timePkg := nowSelector.X
replacement := &ast.CallExpr{
Fun: &ast.SelectorExpr{X: timePkg, Sel: ast.NewIdent("Until")},
Args: []ast.Expr{selector.X},
}
report.Report(pass, node, "should use time.Until instead of t.Sub(time.Now())",
report.FilterGenerated(),
report.MinimumStdlibVersion("go1.8"),
report.Fixes(edit.Fix("Replace with call to time.Until", edit.ReplaceWithNode(pass.Fset, node, replacement))))
}
return nil, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package pkg

import timelib "time"

func fn(t timelib.Time) {
t.Sub(timelib.Now()) //@ diag(`time.Until`)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package pkg

import timelib "time"

func fn(t timelib.Time) {
timelib.Until(t) //@ diag(`time.Until`)
}
7 changes: 7 additions & 0 deletions simple/s1024/testdata/go1.8/CheckTimeUntilDotImport/dot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package pkg

import . "time"

func fn(t Time) {
_ = t.Sub(Now()) //@ diag(`time.Until`)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package pkg

import . "time"

func fn(t Time) {
_ = t.Sub(Now()) //@ diag(`time.Until`)
}
14 changes: 12 additions & 2 deletions simple/s1037/s1037.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,27 @@ can much simpler be expressed with a simple call to time.Sleep.`,
var Analyzer = SCAnalyzer.Analyzer

var (
checkElaborateSleepQ = pattern.MustParse(`(SelectStmt (CommClause (UnaryExpr "<-" (CallExpr (Symbol "time.After") [arg])) body))`)
checkElaborateSleepQ = pattern.MustParse(`(SelectStmt (CommClause (UnaryExpr "<-" afterCall@(CallExpr (Symbol "time.After") [arg])) body))`)
checkElaborateSleepR = pattern.MustParse(`(CallExpr (SelectorExpr (Ident "time") (Ident "Sleep")) [arg])`)
)

func run(pass *analysis.Pass) (any, error) {
for node, m := range code.Matches(pass, checkElaborateSleepQ) {
if body, ok := m.State["body"].([]ast.Stmt); ok && len(body) == 0 {
selector, ok := ast.Unparen(m.State["afterCall"].(*ast.CallExpr).Fun).(*ast.SelectorExpr)
if !ok {
report.Report(pass, node, "should use time.Sleep instead of elaborate way of sleeping", report.ShortRange(), report.FilterGenerated())
continue
}
time := selector.X
replacement := &ast.CallExpr{
Fun: &ast.SelectorExpr{X: time, Sel: ast.NewIdent("Sleep")},
Args: []ast.Expr{m.State["arg"].(ast.Expr)},
}
report.Report(pass, node, "should use time.Sleep instead of elaborate way of sleeping",
report.ShortRange(),
report.FilterGenerated(),
report.Fixes(edit.Fix("Use time.Sleep", edit.ReplaceWithPattern(pass.Fset, node, checkElaborateSleepR, m.State))))
report.Fixes(edit.Fix("Use time.Sleep", edit.ReplaceWithNode(pass.Fset, node, replacement))))
} else {
// TODO(dh): we could make a suggested fix if the body
// doesn't declare or shadow any identifiers
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package pkg

import timelib "time"

func fn() {
select { //@ diag(`should use time.Sleep`)
case <-timelib.After(0):
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package pkg

import timelib "time"

func fn() {
timelib.Sleep(0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package pkg

import . "time"

func fn() {
select { //@ diag(`should use time.Sleep`)
case <-After(0):
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package pkg

import . "time"

func fn() {
select { //@ diag(`should use time.Sleep`)
case <-After(0):
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package pkg

import t "time"

func fn(x struct{ After func() t.Duration }) {
select { //@ diag(`should use time.Sleep`)
case <-t.After(x.After()):
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package pkg

import t "time"

func fn(x struct{ After func() t.Duration }) {
t.Sleep(x.After())
}