go-critic

Checks overview

This page describes checks supported by go-critic linter.

Checkers

Total number of checks is 106 :rocket:

Checkers from the “diagnostic” group

Diagnostics try to find programming errors in the code. They also detect code that may be correct, but looks suspicious.

All diagnostics are enabled by default (unless it has “experimental” tag).

Name Short description
:heavy_check_mark:appendAssign Detects suspicious append result assignments
:heavy_check_mark:argOrder Detects suspicious arguments order
:heavy_check_mark:badCall Detects suspicious function calls
:heavy_check_mark:badCond Detects suspicious condition expressions
:white_check_mark:badLock Detects suspicious mutex lock/unlock operations
:white_check_mark:badRegexp Detects suspicious regexp patterns
:white_check_mark:badSorting Detects bad usage of sort package
:white_check_mark:badSyncOnceFunc Detects bad usage of sync.OnceFunc
:white_check_mark:builtinShadowDecl Detects top-level declarations that shadow the predeclared identifiers
:heavy_check_mark:caseOrder Detects erroneous case order inside switch statements
:heavy_check_mark:codegenComment Detects malformed ‘code generated’ file comments
:white_check_mark:commentedOutCode Detects commented-out code inside function bodies
:white_check_mark:deferInLoop Detects loops inside functions that use defer
:heavy_check_mark:deprecatedComment Detects malformed ‘deprecated’ doc-comments
:heavy_check_mark:dupArg Detects suspicious duplicated arguments
:heavy_check_mark:dupBranchBody Detects duplicated branch bodies inside conditional statements
:heavy_check_mark:dupCase Detects duplicated case clauses inside switch or select statements
:heavy_check_mark:dupSubExpr Detects suspicious duplicated sub-expressions
:white_check_mark:dynamicFmtString Detects suspicious formatting strings usage
:white_check_mark:emptyDecl Detects suspicious empty declarations blocks
:white_check_mark:evalOrder Detects unwanted dependencies on the evaluation order
:heavy_check_mark:exitAfterDefer Detects calls to exit/fatal inside functions that use defer
:white_check_mark:externalErrorReassign Detects suspicious reassignment of error from another package
:white_check_mark:filepathJoin Detects problems in filepath.Join() function calls
:heavy_check_mark:flagDeref Detects immediate dereferencing of flag package pointers
:heavy_check_mark:flagName Detects suspicious flag names
:heavy_check_mark:mapKey Detects suspicious map literal keys
:white_check_mark:nilValReturn Detects return statements those results evaluate to nil
:heavy_check_mark:offBy1 Detects various off-by-one kind of errors
:white_check_mark:rangeAppendAll Detects append all its data while range it
:white_check_mark:regexpPattern Detects suspicious regexp patterns
:white_check_mark:returnAfterHttpError Detects suspicious http.Error call without following return
:heavy_check_mark:sloppyLen Detects usage of len when result is obvious or doesn’t make sense
:white_check_mark:sloppyReassign Detects suspicious/confusing re-assignments
:heavy_check_mark:sloppyTypeAssert Detects redundant type assertions
:white_check_mark:sortSlice Detects suspicious sort.Slice calls
:white_check_mark:sprintfQuotedString Detects “%s” formatting directives that can be replaced with %q
:white_check_mark:sqlQuery Detects issue in Query() and Exec() calls
:white_check_mark:syncMapLoadAndDelete Detects sync.Map load+delete operations that can be replaced with LoadAndDelete
:white_check_mark:truncateCmp Detects potential truncation issues when comparing ints of different sizes
:white_check_mark:uncheckedInlineErr Detects unchecked errors in if statements
:white_check_mark:unnecessaryDefer Detects redundantly deferred calls
:white_check_mark:weakCond Detects conditions that are unsafe due to not being exhaustive

Checkers from the “style” group

Style checks suggest replacing some form of expression/statement with another one that is considered more idiomatic or simple.

Only non-opinionated style checks are enabled by default.

Name Short description
:heavy_check_mark:assignOp Detects assignments that can be simplified by using assignment operators
:white_check_mark:boolExprSimplify Detects bool expressions that can be simplified
:white_check_mark:builtinShadow Detects when predeclared identifiers are shadowed in assignments
:heavy_check_mark:captLocal Detects capitalized names for local variables
:heavy_check_mark:commentFormatting Detects comments with non-idiomatic formatting
:white_check_mark:commentedOutImport Detects commented-out imports
:heavy_check_mark:defaultCaseOrder Detects when default case in switch isn’t on 1st or last position
:white_check_mark:deferUnlambda Detects deferred function literals that can be simplified
:white_check_mark:docStub Detects comments that silence go lint complaints about doc-comment
:white_check_mark:dupImport Detects multiple imports of the same package under different aliases
:heavy_check_mark:elseif Detects else with nested if statement that can be replaced with else-if
:white_check_mark:emptyFallthrough Detects fallthrough that can be avoided by using multi case values
:white_check_mark:emptyStringTest Detects empty string checks that can be written more idiomatically
:white_check_mark:exposedSyncMutex Detects exposed methods from sync.Mutex and sync.RWMutex
:white_check_mark:hexLiteral Detects hex literals that have mixed case letter digits
:white_check_mark:httpNoBody Detects nil usages in http.NewRequest calls, suggesting http.NoBody as an alternative
:heavy_check_mark:ifElseChain Detects repeated if-else statements and suggests to replace them with switch statement
:white_check_mark:importShadow Detects when imported package names shadowed in the assignments
:white_check_mark:initClause Detects non-assignment statements inside if/switch init clause
:white_check_mark:methodExprCall Detects method expression call that can be replaced with a method call
:white_check_mark:nestingReduce Finds where nesting level could be reduced
:heavy_check_mark:newDeref Detects immediate dereferencing of new expressions
:white_check_mark:octalLiteral Detects old-style octal literals
:white_check_mark:paramTypeCombine Detects if function parameters could be combined by type and suggest the way to do it
:white_check_mark:preferFilepathJoin Detects concatenation with os.PathSeparator which can be replaced with filepath.Join
:white_check_mark:ptrToRefParam Detects input and output parameters that have a type of pointer to referential type
:white_check_mark:redundantSprint Detects redundant fmt.Sprint calls
:heavy_check_mark:regexpMust Detects regexp.Compile* that can be replaced with regexp.MustCompile*
:white_check_mark:regexpSimplify Detects regexp patterns that can be simplified
:white_check_mark:ruleguard Runs user-defined rules using ruleguard linter
:heavy_check_mark:singleCaseSwitch Detects switch statements that could be better written as if statement
:white_check_mark:stringConcatSimplify Detects string concat operations that can be simplified
:white_check_mark:stringsCompare Detects strings.Compare usage
:heavy_check_mark:switchTrue Detects switch-over-bool statements that use explicit true tag value
:white_check_mark:timeExprSimplify Detects manual conversion to milli- or microseconds
:white_check_mark:todoCommentWithoutDetail Detects TODO comments without detail/assignee
:white_check_mark:tooManyResultsChecker Detects function with too many results
:white_check_mark:typeAssertChain Detects repeated type assertions and suggests to replace them with type switch statement
:white_check_mark:typeDefFirst Detects method declarations preceding the type definition itself
:heavy_check_mark:typeSwitchVar Detects type switches that can benefit from type guard clause with variable
:white_check_mark:typeUnparen Detects unneeded parenthesis inside type expressions and suggests to remove them
:heavy_check_mark:underef Detects dereference expressions that can be omitted
:white_check_mark:unlabelStmt Detects redundant statement labels
:heavy_check_mark:unlambda Detects function literals that can be simplified
:white_check_mark:unnamedResult Detects unnamed results that may benefit from names
:white_check_mark:unnecessaryBlock Detects unnecessary braced statement blocks
:heavy_check_mark:unslice Detects slice expressions that can be simplified to sliced expression itself
:heavy_check_mark:valSwap Detects value swapping code that are not using parallel assignment
:white_check_mark:whyNoLint Ensures that //nolint comments include an explanation
:heavy_check_mark:wrapperFunc Detects function calls that can be replaced with convenience wrappers
:white_check_mark:yodaStyleExpr Detects Yoda style expressions and suggests to replace them

Checkers from the “performance” group

Performance checks tell you about potential issues that can make your code run slower than it could be.

All performance checks are disabled by default.

Name Short description
:white_check_mark:appendCombine Detects append chains to the same slice that can be done in a single append call
:white_check_mark:equalFold Detects unoptimal strings/bytes case-insensitive comparison
:white_check_mark:hugeParam Detects params that incur excessive amount of copying
:white_check_mark:indexAlloc Detects strings.Index calls that may cause unwanted allocs
:white_check_mark:preferDecodeRune Detects expressions like []rune(s)[0] that may cause unwanted rune slice allocation
:white_check_mark:preferFprint Detects fmt.Sprint(f/ln) calls which can be replaced with fmt.Fprint(f/ln)
:white_check_mark:preferStringWriter Detects w.Write or io.WriteString calls which can be replaced with w.WriteString
:white_check_mark:preferWriteByte Detects WriteRune calls with rune literal argument that is single byte and reports to use WriteByte instead
:white_check_mark:rangeExprCopy Detects expensive copies of for loop range expressions
:white_check_mark:rangeValCopy Detects loops that copy big objects during each iteration
:white_check_mark:sliceClear Detects slice clear loops, suggests an idiom that is recognized by the Go compiler
:white_check_mark:stringXbytes Detects redundant conversions between string and []byte

appendAssign

[ diagnostic ]

Detects suspicious append result assignments.

Before:

p.positives = append(p.negatives, x)
p.negatives = append(p.negatives, y)

After:

p.positives = append(p.positives, x)
p.negatives = append(p.negatives, y)

appendCombine

[ performance ]

Detects append chains to the same slice that can be done in a single append call.

Before:

xs = append(xs, 1)
xs = append(xs, 2)

After:

xs = append(xs, 1, 2)

argOrder

[ diagnostic ]

Detects suspicious arguments order.

Before:

strings.HasPrefix("#", userpass)

After:

strings.HasPrefix(userpass, "#")

assignOp

[ style ]

Detects assignments that can be simplified by using assignment operators.

Before:

x = x * 2

After:

x *= 2

badCall

[ diagnostic ]

Detects suspicious function calls.

Before:

strings.Replace(s, from, to, 0)

After:

strings.Replace(s, from, to, -1)

badCond

[ diagnostic ]

Detects suspicious condition expressions.

Before:

for i := 0; i > n; i++ {
	xs[i] = 0
}

After:

for i := 0; i < n; i++ {
	xs[i] = 0
}

badLock

[ diagnostic experimental ]

Detects suspicious mutex lock/unlock operations.

Before:

mu.Lock(); mu.Unlock()

After:

mu.Lock(); defer mu.Unlock()

badRegexp

[ diagnostic experimental ]

Detects suspicious regexp patterns.

Before:

regexp.MustCompile(`(?:^aa|bb|cc)foo[aba]`)

After:

regexp.MustCompile(`^(?:aa|bb|cc)foo[ab]`)

badSorting

[ diagnostic experimental ]

Detects bad usage of sort package.

Before:

xs = sort.StringSlice(xs)

After:

sort.Strings(xs)

badSyncOnceFunc

[ diagnostic experimental ]

Detects bad usage of sync.OnceFunc.

Before:

sync.OnceFunc(foo)()

After:

fooOnce := sync.OnceFunc(foo); ...; fooOnce()

boolExprSimplify

[ style experimental ]

Detects bool expressions that can be simplified.

Before:

a := !(elapsed >= expectElapsedMin)
b := !(x) == !(y)

After:

a := elapsed < expectElapsedMin
b := (x) == (y)

builtinShadow

[ style opinionated ]

Detects when predeclared identifiers are shadowed in assignments.

Before:

len := 10

After:

length := 10

builtinShadowDecl

[ diagnostic experimental ]

Detects top-level declarations that shadow the predeclared identifiers.

Before:

type int struct {}

After:

type myInt struct {}

captLocal

[ style ]

Detects capitalized names for local variables.

Before:

func f(IN int, OUT *int) (ERR error) {}

After:

func f(in int, out *int) (err error) {}

Checker parameters:

caseOrder

[ diagnostic ]

Detects erroneous case order inside switch statements.

Before:

switch x.(type) {
case ast.Expr:
	fmt.Println("expr")
case *ast.BasicLit:
	fmt.Println("basic lit") // Never executed
}

After:

switch x.(type) {
case *ast.BasicLit:
	fmt.Println("basic lit") // Now reachable
case ast.Expr:
	fmt.Println("expr")
}

codegenComment

[ diagnostic ]

Detects malformed ‘code generated’ file comments.

Before:

// This file was automatically generated by foogen

After:

// Code generated by foogen. DO NOT EDIT.

commentFormatting

[ style ]

Detects comments with non-idiomatic formatting.

Before:

//This is a comment

After:

// This is a comment

commentedOutCode

[ diagnostic experimental ]

Detects commented-out code inside function bodies.

Before:

// fmt.Println("Debugging hard")
foo(1, 2)

After:

foo(1, 2)

Checker parameters:

commentedOutImport

[ style experimental ]

Detects commented-out imports.

Before:

import (
	"fmt"
	//"os"
)

After:

import (
	"fmt"
)

defaultCaseOrder

[ style ]

Detects when default case in switch isn’t on 1st or last position.

Before:

switch {
case x > y:
	// ...
default: // <- not the best position
	// ...
case x == 10:
	// ...
}

After:

switch {
case x > y:
	// ...
case x == 10:
	// ...
default: // <- last case (could also be the first one)
	// ...
}

deferInLoop

[ diagnostic experimental ]

Detects loops inside functions that use defer.

Before:

for _, filename := range []string{"foo", "bar"} {
	 f, err := os.Open(filename)
	
	defer f.Close()
}

After:

func process(filename string) {
	 f, err := os.Open(filename)
	
	defer f.Close()
}
/* ... */
for _, filename := range []string{"foo", "bar"} {
	process(filename)
}

deferUnlambda

[ style experimental ]

Detects deferred function literals that can be simplified.

Before:

defer func() { f() }()

After:

defer f()

deprecatedComment

[ diagnostic ]

Detects malformed ‘deprecated’ doc-comments.

Before:

// deprecated, use FuncNew instead
func FuncOld() int

After:

// Deprecated: use FuncNew instead
func FuncOld() int

docStub

[ style experimental ]

Detects comments that silence go lint complaints about doc-comment.

Before:

// Foo ...
func Foo() {
}

After:

// (A) - remove the doc-comment stub
func Foo() {}
// (B) - replace it with meaningful comment
// Foo is a demonstration-only function.
func Foo() {}

dupArg

[ diagnostic ]

Detects suspicious duplicated arguments.

Before:

copy(dst, dst)

After:

copy(dst, src)

dupBranchBody

[ diagnostic ]

Detects duplicated branch bodies inside conditional statements.

Before:

if cond {
	println("cond=true")
} else {
	println("cond=true")
}

After:

if cond {
	println("cond=true")
} else {
	println("cond=false")
}

dupCase

[ diagnostic ]

Detects duplicated case clauses inside switch or select statements.

Before:

switch x {
case ys[0], ys[1], ys[2], ys[0], ys[4]:
}

After:

switch x {
case ys[0], ys[1], ys[2], ys[3], ys[4]:
}

dupImport

[ style experimental ]

Detects multiple imports of the same package under different aliases.

Before:

import (
	"fmt"
	printing "fmt" // Imported the second time
)

After:

import(
	"fmt"
)

dupSubExpr

[ diagnostic ]

Detects suspicious duplicated sub-expressions.

Before:

sort.Slice(xs, func(i, j int) bool {
	return xs[i].v < xs[i].v // Duplicated index
})

After:

sort.Slice(xs, func(i, j int) bool {
	return xs[i].v < xs[j].v
})

dynamicFmtString

[ diagnostic experimental ]

Detects suspicious formatting strings usage.

Before:

fmt.Errorf(msg)

After:

fmt.Errorf("%s", msg)

elseif

[ style ]

Detects else with nested if statement that can be replaced with else-if.

Before:

if cond1 {
} else {
	if x := cond2; x {
	}
}

After:

if cond1 {
} else if x := cond2; x {
}

Checker parameters:

emptyDecl

[ diagnostic experimental ]

Detects suspicious empty declarations blocks.

Before:

var()

After:

/* nothing */

emptyFallthrough

[ style experimental ]

Detects fallthrough that can be avoided by using multi case values.

Before:

switch kind {
case reflect.Int:
	fallthrough
case reflect.Int32:
	return Int
}

After:

switch kind {
case reflect.Int, reflect.Int32:
	return Int
}

emptyStringTest

[ style experimental ]

Detects empty string checks that can be written more idiomatically.

Before:

len(s) == 0

After:

s == ""

equalFold

[ performance experimental ]

Detects unoptimal strings/bytes case-insensitive comparison.

Before:

strings.ToLower(x) == strings.ToLower(y)

After:

strings.EqualFold(x, y)

evalOrder

[ diagnostic experimental ]

Detects unwanted dependencies on the evaluation order.

Before:

return x, f(&x)

After:

err := f(&x)
return x, err

exitAfterDefer

[ diagnostic ]

Detects calls to exit/fatal inside functions that use defer.

Before:

defer os.Remove(filename)
if bad {
	log.Fatalf("something bad happened")
}

After:

defer os.Remove(filename)
if bad {
	log.Printf("something bad happened")
	return
}

exposedSyncMutex

[ style experimental ]

Detects exposed methods from sync.Mutex and sync.RWMutex.

Before:

type Foo struct{ ...; sync.Mutex; ... }

After:

type Foo struct{ ...; mu sync.Mutex; ... }

externalErrorReassign

[ diagnostic experimental ]

Detects suspicious reassignment of error from another package.

Before:

io.EOF = nil

After:

/* don't do it */

filepathJoin

[ diagnostic experimental ]

Detects problems in filepath.Join() function calls.

Before:

filepath.Join("dir/", filename)

After:

filepath.Join("dir", filename)

flagDeref

[ diagnostic ]

Detects immediate dereferencing of flag package pointers.

Before:

b := *flag.Bool("b", false, "b docs")

After:

var b bool; flag.BoolVar(&b, "b", false, "b docs")

flagName

[ diagnostic ]

Detects suspicious flag names.

https://github.com/golang/go/issues/41792

Before:

b := flag.Bool(" foo ", false, "description")

After:

b := flag.Bool("foo", false, "description")

hexLiteral

[ style experimental ]

Detects hex literals that have mixed case letter digits.

Before:

x := 0X12
y := 0xfF

After:

x := 0x12
// (A)
y := 0xff
// (B)
y := 0xFF

httpNoBody

[ style experimental ]

Detects nil usages in http.NewRequest calls, suggesting http.NoBody as an alternative.

Before:

http.NewRequest("GET", url, nil)

After:

http.NewRequest("GET", url, http.NoBody)

hugeParam

[ performance ]

Detects params that incur excessive amount of copying.

Before:

func f(x [1024]int) {}

After:

func f(x *[1024]int) {}

Checker parameters:

ifElseChain

[ style ]

Detects repeated if-else statements and suggests to replace them with switch statement.

Permits single else or else-if; repeated else-if or else + else-if will trigger suggestion to use switch statement. See EffectiveGo#switch.

Before:

if cond1 {
	// Code A.
} else if cond2 {
	// Code B.
} else {
	// Code C.
}

After:

switch {
case cond1:
	// Code A.
case cond2:
	// Code B.
default:
	// Code C.
}

Checker parameters:

importShadow

[ style opinionated ]

Detects when imported package names shadowed in the assignments.

Before:

// "path/filepath" is imported.
filepath := "foo.txt"

After:

filename := "foo.txt"

indexAlloc

[ performance ]

Detects strings.Index calls that may cause unwanted allocs.

See Go issue for details: https://github.com/golang/go/issues/25864

Before:

strings.Index(string(x), y)

After:

bytes.Index(x, []byte(y))

initClause

[ style opinionated experimental ]

Detects non-assignment statements inside if/switch init clause.

Before:

if sideEffect(); cond {
}

After:

sideEffect()
if cond {
}

mapKey

[ diagnostic ]

Detects suspicious map literal keys.

Before:

_ = map[string]int{
	"foo": 1,
	"bar ": 2,
}

After:

_ = map[string]int{
	"foo": 1,
	"bar": 2,
}

methodExprCall

[ style experimental ]

Detects method expression call that can be replaced with a method call.

Before:

f := foo{}
foo.bar(f)

After:

f := foo{}
f.bar()

nestingReduce

[ style opinionated experimental ]

Finds where nesting level could be reduced.

Before:

for _, v := range a {
	if v.Bool {
		body()
	}
}

After:

for _, v := range a {
	if !v.Bool {
		continue
	}
	body()
}

Checker parameters:

newDeref

[ style ]

Detects immediate dereferencing of new expressions.

Before:

x := *new(bool)

After:

x := false

nilValReturn

[ diagnostic experimental ]

Detects return statements those results evaluate to nil.

Before:

if err == nil {
	return err
}

After:

// (A) - return nil explicitly
if err == nil {
	return nil
}
// (B) - typo in "==", change to "!="
if err != nil {
	return err
}

octalLiteral

[ style experimental opinionated ]

Detects old-style octal literals.

Before:

foo(02)

After:

foo(0o2)

offBy1

[ diagnostic ]

Detects various off-by-one kind of errors.

Before:

xs[len(xs)]

After:

xs[len(xs)-1]

paramTypeCombine

[ style opinionated ]

Detects if function parameters could be combined by type and suggest the way to do it.

Before:

func foo(a, b int, c, d int, e, f int, g int) {}

After:

func foo(a, b, c, d, e, f, g int) {}

preferDecodeRune

[ performance experimental ]

Detects expressions like []rune(s)[0] that may cause unwanted rune slice allocation.

See Go issue for details: https://github.com/golang/go/issues/45260

Before:

r := []rune(s)[0]

After:

r, _ := utf8.DecodeRuneInString(s)

preferFilepathJoin

[ style experimental ]

Detects concatenation with os.PathSeparator which can be replaced with filepath.Join.

Before:

x + string(os.PathSeparator) + y

After:

filepath.Join(x, y)

preferFprint

[ performance experimental ]

Detects fmt.Sprint(f/ln) calls which can be replaced with fmt.Fprint(f/ln).

Before:

w.Write([]byte(fmt.Sprintf("%x", 10)))

After:

fmt.Fprintf(w, "%x", 10)

preferStringWriter

[ performance experimental ]

Detects w.Write or io.WriteString calls which can be replaced with w.WriteString.

Before:

w.Write([]byte("foo"))

After:

w.WriteString("foo")

preferWriteByte

[ performance experimental opinionated ]

Detects WriteRune calls with rune literal argument that is single byte and reports to use WriteByte instead.

Before:

w.WriteRune('\n')

After:

w.WriteByte('\n')

ptrToRefParam

[ style opinionated experimental ]

Detects input and output parameters that have a type of pointer to referential type.

Before:

func f(m *map[string]int) (*chan *int)

After:

func f(m map[string]int) (chan *int)

rangeAppendAll

[ diagnostic experimental ]

Detects append all its data while range it.

Before:

for _, n := range ns {
	...
		rs = append(rs, ns...) // append all slice data
	}
}

After:

for _, n := range ns {
	...
		rs = append(rs, n)
	}
}

rangeExprCopy

[ performance ]

Detects expensive copies of for loop range expressions.

Suggests to use pointer to array to avoid the copy using & on range expression.

See Go issue for details: https://github.com/golang/go/issues/15812.

Before:

var xs [2048]byte
for _, x := range xs { // Copies 2048 bytes
	// Loop body.
}

After:

var xs [2048]byte
for _, x := range &xs { // No copy
	// Loop body.
}

Checker parameters:

rangeValCopy

[ performance ]

Detects loops that copy big objects during each iteration.

Suggests to use index access or take address and make use pointer instead.

Before:

xs := make([][1024]byte, length)
for _, x := range xs {
	// Loop body.
}

After:

xs := make([][1024]byte, length)
for i := range xs {
	x := &xs[i]
	// Loop body.
}

Checker parameters:

redundantSprint

[ style experimental ]

Detects redundant fmt.Sprint calls.

Before:

fmt.Sprint(x)

After:

x.String()

regexpMust

[ style ]

Detects regexp.Compile* that can be replaced with regexp.MustCompile*.

Before:

re, _ := regexp.Compile("const pattern")

After:

re := regexp.MustCompile("const pattern")

regexpPattern

[ diagnostic experimental ]

Detects suspicious regexp patterns.

Before:

regexp.MustCompile(`google.com|yandex.ru`)

After:

regexp.MustCompile(`google\.com|yandex\.ru`)

regexpSimplify

[ style experimental opinionated ]

Detects regexp patterns that can be simplified.

Before:

regexp.MustCompile(`(?:a|b|c)   [a-z][a-z]*`)

After:

regexp.MustCompile(`[abc] {3}[a-z]+`)

returnAfterHttpError

[ diagnostic experimental ]

Detects suspicious http.Error call without following return.

Before:

if err != nil { http.Error(...); }

After:

if err != nil { http.Error(...); return; }

ruleguard

[ style experimental ]

Runs user-defined rules using ruleguard linter.

Reads a rules file and turns them into go-critic checkers.

See https://github.com/quasilyte/go-ruleguard.

Before:

N/A

After:

N/A

Checker parameters:

singleCaseSwitch

[ style ]

Detects switch statements that could be better written as if statement.

Before:

switch x := x.(type) {
case int:
	body()
}

After:

if x, ok := x.(int); ok {
	body()
}

sliceClear

[ performance experimental ]

Detects slice clear loops, suggests an idiom that is recognized by the Go compiler.

Before:

for i := 0; i < len(buf); i++ { buf[i] = 0 }

After:

for i := range buf { buf[i] = 0 }

sloppyLen

[ diagnostic ]

Detects usage of len when result is obvious or doesn’t make sense.

Before:

len(arr) <= 0

After:

len(arr) == 0

sloppyReassign

[ diagnostic experimental ]

Detects suspicious/confusing re-assignments.

Before:

if err = f(); err != nil { return err }

After:

if err := f(); err != nil { return err }

sloppyTypeAssert

[ diagnostic ]

Detects redundant type assertions.

Before:

func f(r io.Reader) interface{} {
	return r.(interface{})
}

After:

func f(r io.Reader) interface{} {
	return r
}

sortSlice

[ diagnostic experimental ]

Detects suspicious sort.Slice calls.

Before:

sort.Slice(xs, func(i, j) bool { return keys[i] < keys[j] })

After:

sort.Slice(kv, func(i, j) bool { return kv[i].key < kv[j].key })

sprintfQuotedString

[ diagnostic experimental ]

Detects “%s” formatting directives that can be replaced with %q.

Before:

fmt.Sprintf(`"%s"`, s)

After:

fmt.Sprintf(`%q`, s)

sqlQuery

[ diagnostic experimental ]

Detects issue in Query() and Exec() calls.

Before:

_, err := db.Query("UPDATE ...")

After:

_, err := db.Exec("UPDATE ...")

stringConcatSimplify

[ style experimental ]

Detects string concat operations that can be simplified.

Before:

strings.Join([]string{x, y}, "_")

After:

x + "_" + y

stringXbytes

[ performance ]

Detects redundant conversions between string and []byte.

Before:

copy(b, []byte(s))

After:

copy(b, s)

stringsCompare

[ style experimental ]

Detects strings.Compare usage.

Before:

strings.Compare(x, y)

After:

x < y

switchTrue

[ style ]

Detects switch-over-bool statements that use explicit true tag value.

Before:

switch true {...}

After:

switch {...}

syncMapLoadAndDelete

[ diagnostic experimental ]

Detects sync.Map load+delete operations that can be replaced with LoadAndDelete.

Before:

v, ok := m.Load(k); if ok { m.Delete($k); f(v); }

After:

v, deleted := m.LoadAndDelete(k); if deleted { f(v) }

timeExprSimplify

[ style experimental ]

Detects manual conversion to milli- or microseconds.

Before:

t.Unix() / 1000

After:

t.UnixMilli()

todoCommentWithoutDetail

[ style opinionated experimental ]

Detects TODO comments without detail/assignee.

Before:

// TODO
fiiWithCtx(nil, a, b)

After:

// TODO(admin): pass context.TODO() instead of nil
fiiWithCtx(nil, a, b)

tooManyResultsChecker

[ style opinionated experimental ]

Detects function with too many results.

Before:

func fn() (a, b, c, d float32, _ int, _ bool)

After:

func fn() (resultStruct, bool)

Checker parameters:

truncateCmp

[ diagnostic experimental ]

Detects potential truncation issues when comparing ints of different sizes.

Before:

func f(x int32, y int16) bool {
  return int16(x) < y
}

After:

func f(x int32, int16) bool {
  return x < int32(y)
}

Checker parameters:

typeAssertChain

[ style experimental ]

Detects repeated type assertions and suggests to replace them with type switch statement.

Before:

if x, ok := v.(T1); ok {
	// Code A, uses x.
} else if x, ok := v.(T2); ok {
	// Code B, uses x.
} else if x, ok := v.(T3); ok {
	// Code C, uses x.
}

After:

switch x := v.(T1) {
case cond1:
	// Code A, uses x.
case cond2:
	// Code B, uses x.
default:
	// Code C, uses x.
}

typeDefFirst

[ style experimental ]

Detects method declarations preceding the type definition itself.

Before:

func (r rec) Method() {}
type rec struct{}

After:

type rec struct{}
func (r rec) Method() {}

typeSwitchVar

[ style ]

Detects type switches that can benefit from type guard clause with variable.

Before:

switch v.(type) {
case int:
	return v.(int)
case point:
	return v.(point).x + v.(point).y
default:
	return 0
}

After:

switch v := v.(type) {
case int:
	return v
case point:
	return v.x + v.y
default:
	return 0
}

typeUnparen

[ style opinionated ]

Detects unneeded parenthesis inside type expressions and suggests to remove them.

Before:

type foo [](func([](func())))

After:

type foo []func([]func())

uncheckedInlineErr

[ diagnostic experimental ]

Detects unchecked errors in if statements.

Before:

if err := expr(); err2 != nil { /*...*/ }

After:

if err := expr(); err != nil { /*...*/ }

underef

[ style ]

Detects dereference expressions that can be omitted.

Before:

(*k).field = 5
v := (*a)[5] // only if a is array

After:

k.field = 5
v := a[5]

Checker parameters:

unlabelStmt

[ style experimental ]

Detects redundant statement labels.

Before:

derp:
for x := range xs {
	if x == 0 {
		break derp
	}
}

After:

for x := range xs {
	if x == 0 {
		break
	}
}

unlambda

[ style ]

Detects function literals that can be simplified.

Before:

func(x int) int { return fn(x) }

After:

fn

unnamedResult

[ style opinionated experimental ]

Detects unnamed results that may benefit from names.

Before:

func f() (float64, float64)

After:

func f() (x, y float64)

Checker parameters:

unnecessaryBlock

[ style opinionated experimental ]

Detects unnecessary braced statement blocks.

Before:

x := 1
{
	print(x)
}

After:

x := 1
print(x)

unnecessaryDefer

[ diagnostic experimental ]

Detects redundantly deferred calls.

Before:

func() {
	defer os.Remove(filename)
}

After:

func() {
	os.Remove(filename)
}

unslice

[ style ]

Detects slice expressions that can be simplified to sliced expression itself.

Before:

copy(b[:], values...)

After:

copy(b, values...)

valSwap

[ style ]

Detects value swapping code that are not using parallel assignment.

Before:

*tmp = *x; *x = *y; *y = *tmp

After:

*x, *y = *y, *x

weakCond

[ diagnostic experimental ]

Detects conditions that are unsafe due to not being exhaustive.

Before:

xs != nil && xs[0] != nil

After:

len(xs) != 0 && xs[0] != nil

whyNoLint

[ style experimental ]

Ensures that //nolint comments include an explanation.

Before:

//nolint

After:

//nolint // reason

wrapperFunc

[ style ]

Detects function calls that can be replaced with convenience wrappers.

Before:

wg.Add(-1)

After:

wg.Done()

yodaStyleExpr

[ style experimental ]

Detects Yoda style expressions and suggests to replace them.

Before:

return nil != ptr

After:

return ptr != nil