1
0
mirror of https://github.com/mgechev/revive.git synced 2024-11-28 08:49:11 +02:00
revive/rule/time_naming.go

97 lines
2.1 KiB
Go
Raw Normal View History

2018-01-25 21:34:38 +02:00
package rule
import (
"fmt"
"go/ast"
"go/types"
"strings"
"github.com/mgechev/revive/lint"
)
2018-05-27 06:28:31 +02:00
// TimeNamingRule lints given else constructs.
type TimeNamingRule struct{}
2018-01-25 21:34:38 +02:00
// Apply applies the rule to given file.
2022-04-10 11:55:13 +02:00
func (*TimeNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
2018-01-25 21:34:38 +02:00
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
w := &lintTimeNames{file, onFailure}
file.Pkg.TypeCheck()
2018-01-25 21:34:38 +02:00
ast.Walk(w, file.AST)
return failures
}
// Name returns the rule name.
2022-04-10 11:55:13 +02:00
func (*TimeNamingRule) Name() string {
2018-05-27 06:28:31 +02:00
return "time-naming"
2018-01-25 21:34:38 +02:00
}
type lintTimeNames struct {
file *lint.File
onFailure func(lint.Failure)
}
func (w *lintTimeNames) Visit(node ast.Node) ast.Visitor {
v, ok := node.(*ast.ValueSpec)
if !ok {
return w
}
for _, name := range v.Names {
origTyp := w.file.Pkg.TypeOf(name)
// Look for time.Duration or *time.Duration;
// the latter is common when using flag.Duration.
typ := origTyp
if pt, ok := typ.(*types.Pointer); ok {
typ = pt.Elem()
}
if !isNamedType(typ, "time", "Duration") {
2018-01-25 21:34:38 +02:00
continue
}
suffix := ""
for _, suf := range timeSuffixes {
if strings.HasSuffix(name.Name, suf) {
suffix = suf
break
}
}
if suffix == "" {
continue
}
w.onFailure(lint.Failure{
Category: "time",
Confidence: 0.9,
Node: v,
Failure: fmt.Sprintf("var %s is of type %v; don't use unit-specific suffix %q", name.Name, origTyp, suffix),
})
}
return w
}
// timeSuffixes is a list of name suffixes that imply a time unit.
// This is not an exhaustive list.
var timeSuffixes = []string{
"Hour", "Hours",
"Min", "Mins", "Minutes", "Minute",
"Sec", "Secs", "Seconds", "Second",
2018-01-25 21:34:38 +02:00
"Msec", "Msecs",
"Milli", "Millis", "Milliseconds", "Millisecond",
"Usec", "Usecs", "Microseconds", "Microsecond",
2018-01-25 21:34:38 +02:00
"MS", "Ms",
}
func isNamedType(typ types.Type, importPath, name string) bool {
2018-01-25 21:34:38 +02:00
n, ok := typ.(*types.Named)
if !ok {
return false
}
2024-10-01 12:14:02 +02:00
typeName := n.Obj()
return typeName != nil && typeName.Pkg() != nil && typeName.Pkg().Path() == importPath && typeName.Name() == name
2018-01-25 21:34:38 +02:00
}