go-critic.github.io

Checks overview

This page describes checks supported by go-critic linter.

Checkers:

Name Short description
appendCombine Detects `append` chains to the same slice that can be done in a single `append` call
builtinShadow Detects when predeclared identifiers shadowed in assignments
flagDeref Detects immediate dereferencing of `flag` package pointers.
ifElseChain Detects repeated if-else statements and suggests to replace them with switch statement
paramTypeCombine :nerd_face: Detects if function parameters could be combined by type and suggest the way to do it
rangeExprCopy Detects expensive copies of `for` loop range expressions
rangeValCopy Detects loops that copy big objects during each iteration
regexpMust Detects `regexp.Compile*` that can be replaced with `regexp.MustCompile*`
singleCaseSwitch Detects switch statements that could be better written as if statements
switchTrue Detects switch-over-bool statements that use explicit `true` tag value
typeSwitchVar Detects type switches that can benefit from type guard clause with variable
typeUnparen Detects unneded parenthesis inside type expressions and suggests to remove them
underef Detects dereference expressions that can be omitted
unslice Detects slice expressions that can be simplified to sliced expression itself

Experimental:

Name Short description
appendAssign Detects suspicious append result assignments
assignOp Detects assignments that can be simplified by using assignment operators
blankParam :nerd_face: Detects unused params and suggests to name them as `_` (blank)
boolExprSimplify Detects bool expressions that can be simplified
boolFuncPrefix :nerd_face: Detects function returning only bool and suggests to add Is/Has/Contains prefix to it's name
busySelect Detects default statement inside a select without a sleep that might waste a CPU time
captLocal Detects capitalized names for local variables
caseOrder Detects erroneous case order inside switch statements
commentedOutCode Detects commented-out code inside function bodies
deadCodeAfterLogFatal Detects dead code that follow panic/fatal logging
defaultCaseOrder Detects when default case in switch isn't on 1st or last position
deferInLoop Detects defer in loop and warns that it will not be executed till the end of function's scope
deprecatedComment Detects malformed "deprecated" doc-comments
docStub Detects comments that silence go lint complaints about doc-comment
dupArg Detects suspicious duplicated arguments
dupBranchBody Detects duplicated branch bodies inside conditional statements
dupCase Detects duplicated case clauses inside switch statements
dupSubExpr Detects suspicious duplicated sub-expressions
elseif :nerd_face: Detects else with nested if statement that can be replaced with else-if
emptyFallthrough Detects fallthrough that can be avoided by using multi case values
emptyFmt Detects usages of formatting functions without formatting arguments
evalOrder Detects potentially unsafe dependencies on evaluation order
floatCompare Detects fragile float variables comparisons
hugeParam Detects params that incur excessive amount of copying
importPackageName Detects when imported package names are unnecessary renamed
importShadow Detects when imported package names shadowed in assignments
indexAlloc Detects strings.Index calls that may cause unwanted allocs
indexOnlyLoop Detects for loops that can benefit from rewrite to range loop
initClause Detects non-assignment statements inside if/switch init clause
longChain :nerd_face: Detects repeated expression chains and suggest to refactor them
methodExprCall :nerd_face: Detects method expression call that can be replaced with a method call
namedConst Detects literals that can be replaced with defined named const
nestingReduce Finds where nesting level could be reduced
nilValReturn Detects return statements those results evaluate to nil
ptrToRefParam Detects input and output parameters that have a type of pointer to referential type
sloppyLen Detects usage of `len` when result is obvious or doesn't make sense
sqlRowsClose Detects uses of *sql.Rows without call Close method
stdExpr Detects constant expressions that can be replaced by a stdlib const
unexportedCall :nerd_face: Detects calls of unexported method from unexported type outside that type
unlabelStmt Detects redundant statement labels
unlambda Detects function literals that can be simplified
unnamedResult Detects unnamed results that may benefit from names
unnecessaryBlock Detects unnecessary braced statement blocks
yodaStyleExpr :nerd_face: Detects Yoda style expressions that suggest to replace them

appendAssign

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

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)

assignOp

Detects assignments that can be simplified by using assignment operators.

Before:

x = x * 2

After:

x *= 2

blankParam

Detects unused params and suggests to name them as _ (blank).

Before:

func f(a int, b float64) // b isn't used inside function body

After:

func f(a int, _ float64) // everything is cool

blankParam is very opinionated.

boolExprSimplify

Detects bool expressions that can be simplified.

Before:

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

After:

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

boolFuncPrefix

Detects function returning only bool and suggests to add Is/Has/Contains prefix to it’s name.

Before:

func Enabled() bool

After:

func IsEnabled() bool

boolFuncPrefix is very opinionated.

builtinShadow

Detects when predeclared identifiers shadowed in assignments.

Before:

len := 10
println(len)

After:

length := 10 // Changed variable name
println(length)

builtinShadow is syntax-only checker (fast).

busySelect

Detects default statement inside a select without a sleep that might waste a CPU time.

Before:

for {
	select {
	case <-ch:
		// ...
	default:
		// will waste CPU time
	}
}

After:

for {
	select {
	case <-ch:
		// ...
	default:
		time.Sleep(100 * time.Millisecond)
	}
}

captLocal

Detects capitalized names for local variables.

Before:

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

After:

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

captLocal is syntax-only checker (fast).

caseOrder

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")
}

commentedOutCode

Detects commented-out code inside function bodies.

Before:

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

After:

foo(1, 2)

deadCodeAfterLogFatal

Detects dead code that follow panic/fatal logging.

Before:

log.Fatal("exits function")
return

After:

log.Fatal("exits function")

defaultCaseOrder

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)
	// ...
}

defaultCaseOrder is syntax-only checker (fast).

deferInLoop

Detects defer in loop and warns that it will not be executed till the end of function’s scope.

Before:

for i := range [10]int{} {
	defer f(i) // will be executed only at the end of func
}

After:

for i := range [10]int{} {
	func(i int) {
		defer f(i)
	}(i)
}

deprecatedComment

Detects malformed “deprecated” doc-comments.

Before:

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

After:

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

deprecatedComment is syntax-only checker (fast).

docStub

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

Before:

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

After:

func Foo() {
}

You can either remove a comment to let go lint find it or change stub to useful comment. This checker makes it easier to detect stubs, the action is up to you. docStub is syntax-only checker (fast).

dupArg

Detects suspicious duplicated arguments.

Before:

copy(dst, dst)

After:

copy(dst, src)

dupBranchBody

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

Detects duplicated case clauses inside switch 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]:
}

dupSubExpr

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
})

elseif

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 {
}

elseif is very opinionated.

emptyFallthrough

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
}

emptyFmt

Detects usages of formatting functions without formatting arguments.

Before:

fmt.Sprintf("whatever")
fmt.Errorf("wherever")

After:

fmt.Sprint("whatever")
errors.New("wherever")

evalOrder

Detects potentially unsafe dependencies on evaluation order.

Before:

return mayModifySlice(&xs), xs[0]

After:

// A)
v := mayModifySlice(&xs)
return v, xs[0]
// B)
v := xs[0]
return mayModifySlice(&xs), v

flagDeref

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")

Dereferencing returned pointers will lead to hard to find errors where flag values are not updated after flag.Parse(). flagDeref is syntax-only checker (fast).

floatCompare

Detects fragile float variables comparisons.

Before:

// x and y are floats
return x == y

After:

// x and y are floats
return math.Abs(x - y) < eps

hugeParam

Detects params that incur excessive amount of copying.

Before:

func f(x [1024]int) {}

After:

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

ifElseChain

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

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.
}

Permits single else or else-if; repeated else-if or else + else-if will trigger suggestion to use switch statement. See EffectiveGo#switch. ifElseChain is syntax-only checker (fast).

importPackageName

Detects when imported package names are unnecessary renamed.

Before:

import lint "github.com/go-critic/go-critic/lint"

After:

import "github.com/go-critic/go-critic/lint"

importShadow

Detects when imported package names shadowed in assignments.

Before:

// "path/filepath" is imported.
func myFunc(filepath string) {
}

After:

func myFunc(filename string) {
}

indexAlloc

Detects strings.Index calls that may cause unwanted allocs.

Before:

strings.Index(string(x), y)

After:

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

indexOnlyLoop

Detects for loops that can benefit from rewrite to range loop.

Suggests to use for key, v := range container form.

Before:

for i := range files {
	if files[i] != nil {
		files[i].Close()
	}
}

After:

for _, f := range files {
	if f != nil {
		f.Close()
	}
}

initClause

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

Before:

if sideEffect(); cond {
}

After:

sideEffect()
if cond {
}

initClause is syntax-only checker (fast).

longChain

Detects repeated expression chains and suggest to refactor them.

Before:

a := q.w.e.r.t + 1
b := q.w.e.r.t + 2
c := q.w.e.r.t + 3
v := (a + xs[i+1]) + (b + xs[i+1]) + (c + xs[i+1])

After:

x := xs[i+1]
qwert := q.w.e.r.t
a := qwert + 1
b := qwert + 2
c := qwert + 3
v := (a + x) + (b + x) + (c + x)

longChain is very opinionated.

methodExprCall

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

Before:

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

After:

f := foo{}
f.bar()

methodExprCall is very opinionated.

namedConst

Detects literals that can be replaced with defined named const.

Before:

// pos has type of token.Pos.
return pos != 0

After:

return pos != token.NoPos

nestingReduce

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()
}

nilValReturn

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 nil
}

paramTypeCombine

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) {}

paramTypeCombine is syntax-only checker (fast).paramTypeCombine is very opinionated.

ptrToRefParam

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)

rangeExprCopy

Detects expensive copies of for loop range expressions.

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

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.
}

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

rangeValCopy

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.
}

regexpMust

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

Before:

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

After:

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

singleCaseSwitch

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

Before:

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

After:

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

singleCaseSwitch is syntax-only checker (fast).

sloppyLen

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

Before:

len(arr) >= 0 // Sloppy
len(arr) <= 0 // Sloppy
len(arr) < 0  // Doesn't make sense at all

After:

len(arr) > 0
len(arr) == 0

sloppyLen is syntax-only checker (fast).

sqlRowsClose

Detects uses of *sql.Rows without call Close method.

Before:

rows, _ := db.Query( /**/ )
for rows.Next {
}

After:

rows, _ := db.Query( /**/ )
for rows.Next {
}
rows.Close()

stdExpr

Detects constant expressions that can be replaced by a stdlib const.

Before:

intBytes := make([]byte, unsafe.Sizeof(0))
maxVal := 1<<7 - 1

After:

intBytes := make([]byte, bits.IntSize)
maxVal := math.MaxInt8

switchTrue

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

Before:

switch true {
case x > y:
}

After:

switch {
case x > y:
}

switchTrue is syntax-only checker (fast).

typeSwitchVar

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

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

Before:

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

After:

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

typeUnparen is syntax-only checker (fast).

underef

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]

unexportedCall

Detects calls of unexported method from unexported type outside that type.

Before:

func baz(f foo) {
	fo.bar()
}

After:

func baz(f foo) {
	fo.Bar() // Made method exported
}

unexportedCall is very opinionated.

unlabelStmt

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

Detects function literals that can be simplified.

Before:

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

After:

fn

unnamedResult

Detects unnamed results that may benefit from names.

Before:

func f() (float64, float64)

After:

func f() (x, y float64)

unnecessaryBlock

Detects unnecessary braced statement blocks.

Before:

x := 1
{
	print(x)
}

After:

x := 1
print(x)

unnecessaryBlock is syntax-only checker (fast).

unslice

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

Before:

f(s[:])               // s is string
copy(b[:], values...) // b is []byte

After:

f(s)
copy(b, values...)

yodaStyleExpr

Detects Yoda style expressions that suggest to replace them.

Before:

return nil != ptr

After:

return ptr != nil

yodaStyleExpr is very opinionated.