Golangci-lint v2 part one (#492)
This commit is contained in:
@@ -0,0 +1,81 @@
|
|||||||
|
[service]
|
||||||
|
golangci-lint-version = "1.39.0"
|
||||||
|
|
||||||
|
[linters-settings.wsl]
|
||||||
|
allow-assign-and-anything = true
|
||||||
|
|
||||||
|
[linters]
|
||||||
|
disable-all = true
|
||||||
|
enable = [
|
||||||
|
"asciicheck",
|
||||||
|
"bodyclose",
|
||||||
|
"cyclop",
|
||||||
|
"deadcode",
|
||||||
|
"depguard",
|
||||||
|
"dogsled",
|
||||||
|
"dupl",
|
||||||
|
"durationcheck",
|
||||||
|
"errcheck",
|
||||||
|
"errorlint",
|
||||||
|
"exhaustive",
|
||||||
|
"exhaustivestruct",
|
||||||
|
"exportloopref",
|
||||||
|
"forbidigo",
|
||||||
|
"forcetypeassert",
|
||||||
|
"funlen",
|
||||||
|
"gci",
|
||||||
|
"gochecknoglobals",
|
||||||
|
"gochecknoinits",
|
||||||
|
"gocognit",
|
||||||
|
"goconst",
|
||||||
|
"gocritic",
|
||||||
|
"gocyclo",
|
||||||
|
"godot",
|
||||||
|
"godox",
|
||||||
|
"goerr113",
|
||||||
|
"gofmt",
|
||||||
|
"gofumpt",
|
||||||
|
"goheader",
|
||||||
|
"goimports",
|
||||||
|
"golint",
|
||||||
|
"gomnd",
|
||||||
|
# "gomoddirectives",
|
||||||
|
"gomodguard",
|
||||||
|
"goprintffuncname",
|
||||||
|
"gosec",
|
||||||
|
"gosimple",
|
||||||
|
"govet",
|
||||||
|
"ifshort",
|
||||||
|
"importas",
|
||||||
|
"ineffassign",
|
||||||
|
"lll",
|
||||||
|
"makezero",
|
||||||
|
"misspell",
|
||||||
|
"nakedret",
|
||||||
|
"nestif",
|
||||||
|
"nilerr",
|
||||||
|
"nlreturn",
|
||||||
|
"noctx",
|
||||||
|
"nolintlint",
|
||||||
|
"paralleltest",
|
||||||
|
"prealloc",
|
||||||
|
"predeclared",
|
||||||
|
"revive",
|
||||||
|
"rowserrcheck",
|
||||||
|
"sqlclosecheck",
|
||||||
|
"staticcheck",
|
||||||
|
"structcheck",
|
||||||
|
"stylecheck",
|
||||||
|
# "testpackage",
|
||||||
|
"thelper",
|
||||||
|
"tparallel",
|
||||||
|
"typecheck",
|
||||||
|
"unconvert",
|
||||||
|
"unparam",
|
||||||
|
"unused",
|
||||||
|
"varcheck",
|
||||||
|
"wastedassign",
|
||||||
|
"whitespace",
|
||||||
|
"wrapcheck",
|
||||||
|
"wsl"
|
||||||
|
]
|
||||||
@@ -22,6 +22,7 @@ func parseInteger(b []byte) (int64, error) {
|
|||||||
return 0, newDecodeError(b[1:2], "invalid base: '%c'", b[1])
|
return 0, newDecodeError(b[1:2], "invalid base: '%c'", b[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parseIntDec(b)
|
return parseIntDec(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,8 +31,7 @@ func parseLocalDate(b []byte) (LocalDate, error) {
|
|||||||
// date-fullyear = 4DIGIT
|
// date-fullyear = 4DIGIT
|
||||||
// date-month = 2DIGIT ; 01-12
|
// date-month = 2DIGIT ; 01-12
|
||||||
// date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year
|
// date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year
|
||||||
|
var date LocalDate
|
||||||
date := LocalDate{}
|
|
||||||
|
|
||||||
if len(b) != 10 || b[4] != '-' || b[7] != '-' {
|
if len(b) != 10 || b[4] != '-' || b[7] != '-' {
|
||||||
return date, newDecodeError(b, "dates are expected to have the format YYYY-MM-DD")
|
return date, newDecodeError(b, "dates are expected to have the format YYYY-MM-DD")
|
||||||
@@ -48,31 +48,41 @@ func parseLocalDate(b []byte) (LocalDate, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return date, err
|
return date, err
|
||||||
}
|
}
|
||||||
|
|
||||||
date.Month = time.Month(v)
|
date.Month = time.Month(v)
|
||||||
|
|
||||||
date.Day, err = parseDecimalDigits(b[8:10])
|
date.Day, err = parseDecimalDigits(b[8:10])
|
||||||
|
if err != nil {
|
||||||
|
return date, err
|
||||||
|
}
|
||||||
|
|
||||||
return date, nil
|
return date, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errNotDigit = errors.New("not a digit")
|
||||||
|
|
||||||
func parseDecimalDigits(b []byte) (int, error) {
|
func parseDecimalDigits(b []byte) (int, error) {
|
||||||
v := 0
|
v := 0
|
||||||
|
|
||||||
for _, c := range b {
|
for _, c := range b {
|
||||||
if !isDigit(c) {
|
if !isDigit(c) {
|
||||||
return 0, fmt.Errorf("expected digit")
|
return 0, fmt.Errorf("%s: %w", b, errNotDigit)
|
||||||
}
|
}
|
||||||
|
|
||||||
v *= 10
|
v *= 10
|
||||||
v += int(c - '0')
|
v += int(c - '0')
|
||||||
}
|
}
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errParseDateTimeMissingInfo = errors.New("date-time missing timezone information")
|
||||||
|
|
||||||
func parseDateTime(b []byte) (time.Time, error) {
|
func parseDateTime(b []byte) (time.Time, error) {
|
||||||
// offset-date-time = full-date time-delim full-time
|
// offset-date-time = full-date time-delim full-time
|
||||||
// full-time = partial-time time-offset
|
// full-time = partial-time time-offset
|
||||||
// time-offset = "Z" / time-numoffset
|
// time-offset = "Z" / time-numoffset
|
||||||
// time-numoffset = ( "+" / "-" ) time-hour ":" time-minute
|
// time-numoffset = ( "+" / "-" ) time-hour ":" time-minute
|
||||||
|
|
||||||
dt, b, err := parseLocalDateTime(b)
|
dt, b, err := parseLocalDateTime(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return time.Time{}, err
|
return time.Time{}, err
|
||||||
@@ -81,14 +91,15 @@ func parseDateTime(b []byte) (time.Time, error) {
|
|||||||
var zone *time.Location
|
var zone *time.Location
|
||||||
|
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
return time.Time{}, fmt.Errorf("date-time missing timezone information")
|
return time.Time{}, errParseDateTimeMissingInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
if b[0] == 'Z' {
|
if b[0] == 'Z' {
|
||||||
b = b[1:]
|
b = b[1:]
|
||||||
zone = time.UTC
|
zone = time.UTC
|
||||||
} else {
|
} else {
|
||||||
if len(b) != 6 {
|
const dateTimeByteLen = 6
|
||||||
|
if len(b) != dateTimeByteLen {
|
||||||
return time.Time{}, newDecodeError(b, "invalid date-time timezone")
|
return time.Time{}, newDecodeError(b, "invalid date-time timezone")
|
||||||
}
|
}
|
||||||
direction := 1
|
direction := 1
|
||||||
@@ -123,11 +134,19 @@ func parseDateTime(b []byte) (time.Time, error) {
|
|||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
|
var (
|
||||||
dt := LocalDateTime{}
|
errParseLocalDateTimeWrongLength = errors.New(
|
||||||
|
"local datetimes are expected to have the format YYYY-MM-DDTHH:MM:SS[.NNNNNN]",
|
||||||
|
)
|
||||||
|
errParseLocalDateTimeWrongSeparator = errors.New("datetime separator is expected to be T or a space")
|
||||||
|
)
|
||||||
|
|
||||||
if len(b) < 11 {
|
func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
|
||||||
return dt, nil, fmt.Errorf("local datetimes are expected to have the format YYYY-MM-DDTHH:MM:SS[.NNNNNN]")
|
var dt LocalDateTime
|
||||||
|
|
||||||
|
const localDateTimeByteLen = 11
|
||||||
|
if len(b) < localDateTimeByteLen {
|
||||||
|
return dt, nil, errParseLocalDateTimeWrongLength
|
||||||
}
|
}
|
||||||
|
|
||||||
date, err := parseLocalDate(b[:10])
|
date, err := parseLocalDate(b[:10])
|
||||||
@@ -138,7 +157,7 @@ func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
|
|||||||
|
|
||||||
sep := b[10]
|
sep := b[10]
|
||||||
if sep != 'T' && sep != ' ' {
|
if sep != 'T' && sep != ' ' {
|
||||||
return dt, nil, fmt.Errorf("datetime separator is expected to be T or a space")
|
return dt, nil, errParseLocalDateTimeWrongSeparator
|
||||||
}
|
}
|
||||||
|
|
||||||
t, rest, err := parseLocalTime(b[11:])
|
t, rest, err := parseLocalTime(b[11:])
|
||||||
@@ -150,31 +169,39 @@ func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
|
|||||||
return dt, rest, nil
|
return dt, rest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errParseLocalTimeWrongLength = errors.New("times are expected to have the format HH:MM:SS[.NNNNNN]")
|
||||||
|
|
||||||
// parseLocalTime is a bit different because it also returns the remaining
|
// parseLocalTime is a bit different because it also returns the remaining
|
||||||
// []byte that is didn't need. This is to allow parseDateTime to parse those
|
// []byte that is didn't need. This is to allow parseDateTime to parse those
|
||||||
// remaining bytes as a timezone.
|
// remaining bytes as a timezone.
|
||||||
func parseLocalTime(b []byte) (LocalTime, []byte, error) {
|
func parseLocalTime(b []byte) (LocalTime, []byte, error) {
|
||||||
t := LocalTime{}
|
var t LocalTime
|
||||||
|
|
||||||
if len(b) < 8 {
|
const localTimeByteLen = 8
|
||||||
return t, nil, fmt.Errorf("times are expected to have the format HH:MM:SS[.NNNNNN]")
|
if len(b) < localTimeByteLen {
|
||||||
|
return t, nil, errParseLocalTimeWrongLength
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
t.Hour, err = parseDecimalDigits(b[0:2])
|
t.Hour, err = parseDecimalDigits(b[0:2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return t, nil, err
|
return t, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if b[2] != ':' {
|
if b[2] != ':' {
|
||||||
return t, nil, newDecodeError(b[2:3], "expecting colon between hours and minutes")
|
return t, nil, newDecodeError(b[2:3], "expecting colon between hours and minutes")
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Minute, err = parseDecimalDigits(b[3:5])
|
t.Minute, err = parseDecimalDigits(b[3:5])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return t, nil, err
|
return t, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if b[5] != ':' {
|
if b[5] != ':' {
|
||||||
return t, nil, newDecodeError(b[5:6], "expecting colon between minutes and seconds")
|
return t, nil, newDecodeError(b[5:6], "expecting colon between minutes and seconds")
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Second, err = parseDecimalDigits(b[6:8])
|
t.Second, err = parseDecimalDigits(b[6:8])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return t, nil, err
|
return t, nil, err
|
||||||
@@ -182,79 +209,127 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) {
|
|||||||
|
|
||||||
if len(b) >= 15 && b[8] == '.' {
|
if len(b) >= 15 && b[8] == '.' {
|
||||||
t.Nanosecond, err = parseDecimalDigits(b[9:15])
|
t.Nanosecond, err = parseDecimalDigits(b[9:15])
|
||||||
|
if err != nil {
|
||||||
|
return t, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return t, b[15:], nil
|
return t, b[15:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return t, b[8:], nil
|
return t, b[8:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errParseFloatStartDot = errors.New("float cannot start with a dot")
|
||||||
|
errParseFloatEndDot = errors.New("float cannot end with a dot")
|
||||||
|
)
|
||||||
|
|
||||||
|
//nolint:cyclop
|
||||||
func parseFloat(b []byte) (float64, error) {
|
func parseFloat(b []byte) (float64, error) {
|
||||||
|
//nolint:godox
|
||||||
// TODO: inefficient
|
// TODO: inefficient
|
||||||
if len(b) == 4 && (b[0] == '+' || b[0] == '-') && b[1] == 'n' && b[2] == 'a' && b[3] == 'n' {
|
if len(b) == 4 && (b[0] == '+' || b[0] == '-') && b[1] == 'n' && b[2] == 'a' && b[3] == 'n' {
|
||||||
return math.NaN(), nil
|
return math.NaN(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tok := string(b)
|
tok := string(b)
|
||||||
|
|
||||||
err := numberContainsInvalidUnderscore(tok)
|
err := numberContainsInvalidUnderscore(tok)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanedVal := cleanupNumberToken(tok)
|
cleanedVal := cleanupNumberToken(tok)
|
||||||
if cleanedVal[0] == '.' {
|
if cleanedVal[0] == '.' {
|
||||||
return 0, fmt.Errorf("float cannot start with a dot")
|
return 0, errParseFloatStartDot
|
||||||
}
|
}
|
||||||
|
|
||||||
if cleanedVal[len(cleanedVal)-1] == '.' {
|
if cleanedVal[len(cleanedVal)-1] == '.' {
|
||||||
return 0, fmt.Errorf("float cannot end with a dot")
|
return 0, errParseFloatEndDot
|
||||||
}
|
}
|
||||||
return strconv.ParseFloat(cleanedVal, 64)
|
|
||||||
|
f, err := strconv.ParseFloat(cleanedVal, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("coudn't ParseFloat %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseIntHex(b []byte) (int64, error) {
|
func parseIntHex(b []byte) (int64, error) {
|
||||||
tok := string(b)
|
tok := string(b)
|
||||||
cleanedVal := cleanupNumberToken(tok)
|
cleanedVal := cleanupNumberToken(tok)
|
||||||
|
|
||||||
err := hexNumberContainsInvalidUnderscore(cleanedVal)
|
err := hexNumberContainsInvalidUnderscore(cleanedVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil
|
return 0, err
|
||||||
}
|
}
|
||||||
return strconv.ParseInt(cleanedVal[2:], 16, 64)
|
|
||||||
|
i, err := strconv.ParseInt(cleanedVal[2:], 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("coudn't ParseIntHex %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseIntOct(b []byte) (int64, error) {
|
func parseIntOct(b []byte) (int64, error) {
|
||||||
tok := string(b)
|
tok := string(b)
|
||||||
cleanedVal := cleanupNumberToken(tok)
|
cleanedVal := cleanupNumberToken(tok)
|
||||||
|
|
||||||
err := numberContainsInvalidUnderscore(cleanedVal)
|
err := numberContainsInvalidUnderscore(cleanedVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return strconv.ParseInt(cleanedVal[2:], 8, 64)
|
|
||||||
|
i, err := strconv.ParseInt(cleanedVal[2:], 8, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("coudn't ParseIntOct %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseIntBin(b []byte) (int64, error) {
|
func parseIntBin(b []byte) (int64, error) {
|
||||||
tok := string(b)
|
tok := string(b)
|
||||||
cleanedVal := cleanupNumberToken(tok)
|
cleanedVal := cleanupNumberToken(tok)
|
||||||
|
|
||||||
err := numberContainsInvalidUnderscore(cleanedVal)
|
err := numberContainsInvalidUnderscore(cleanedVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return strconv.ParseInt(cleanedVal[2:], 2, 64)
|
|
||||||
|
i, err := strconv.ParseInt(cleanedVal[2:], 2, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("coudn't ParseIntBin %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseIntDec(b []byte) (int64, error) {
|
func parseIntDec(b []byte) (int64, error) {
|
||||||
tok := string(b)
|
tok := string(b)
|
||||||
cleanedVal := cleanupNumberToken(tok)
|
cleanedVal := cleanupNumberToken(tok)
|
||||||
|
|
||||||
err := numberContainsInvalidUnderscore(cleanedVal)
|
err := numberContainsInvalidUnderscore(cleanedVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return strconv.ParseInt(cleanedVal, 10, 64)
|
|
||||||
|
i, err := strconv.ParseInt(cleanedVal, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("coudn't parseIntDec %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func numberContainsInvalidUnderscore(value string) error {
|
func numberContainsInvalidUnderscore(value string) error {
|
||||||
// For large numbers, you may use underscores between digits to enhance
|
// For large numbers, you may use underscores between digits to enhance
|
||||||
// readability. Each underscore must be surrounded by at least one digit on
|
// readability. Each underscore must be surrounded by at least one digit on
|
||||||
// each side.
|
// each side.
|
||||||
|
|
||||||
hasBefore := false
|
hasBefore := false
|
||||||
|
|
||||||
for idx, r := range value {
|
for idx, r := range value {
|
||||||
if r == '_' {
|
if r == '_' {
|
||||||
if !hasBefore || idx+1 >= len(value) {
|
if !hasBefore || idx+1 >= len(value) {
|
||||||
@@ -264,11 +339,13 @@ func numberContainsInvalidUnderscore(value string) error {
|
|||||||
}
|
}
|
||||||
hasBefore = isDigitRune(r)
|
hasBefore = isDigitRune(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func hexNumberContainsInvalidUnderscore(value string) error {
|
func hexNumberContainsInvalidUnderscore(value string) error {
|
||||||
hasBefore := false
|
hasBefore := false
|
||||||
|
|
||||||
for idx, r := range value {
|
for idx, r := range value {
|
||||||
if r == '_' {
|
if r == '_' {
|
||||||
if !hasBefore || idx+1 >= len(value) {
|
if !hasBefore || idx+1 >= len(value) {
|
||||||
@@ -278,11 +355,13 @@ func hexNumberContainsInvalidUnderscore(value string) error {
|
|||||||
}
|
}
|
||||||
hasBefore = isHexDigit(r)
|
hasBefore = isHexDigit(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanupNumberToken(value string) string {
|
func cleanupNumberToken(value string) string {
|
||||||
cleanedVal := strings.Replace(value, "_", "", -1)
|
cleanedVal := strings.ReplaceAll(value, "_", "")
|
||||||
|
|
||||||
return cleanedVal
|
return cleanedVal
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,5 +375,7 @@ func isDigitRune(r rune) bool {
|
|||||||
return r >= '0' && r <= '9'
|
return r >= '0' && r <= '9'
|
||||||
}
|
}
|
||||||
|
|
||||||
var errInvalidUnderscore = errors.New("invalid use of _ in number")
|
var (
|
||||||
var errInvalidUnderscoreHex = errors.New("invalid use of _ in hex number")
|
errInvalidUnderscore = errors.New("invalid use of _ in number")
|
||||||
|
errInvalidUnderscoreHex = errors.New("invalid use of _ in hex number")
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user