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.
captLocal Detects capitalized names for local variables.
defaultCaseOrder Detects when default case in switch isn't on 1st or last position.
flagDeref Detects immediate dereferencing of `flag` package pointers.
ifElseChain Detects repeated if-else statements and suggests to replace them with switch statement.
paramTypeCombine 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.
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.
boolExprSimplify Detects bool expressions that can be simplified for the sake of readability.
boolFuncPrefix :nerd_face: Detects function returning only bool and suggests to add Is/Has/Contains prefix to it's name.
caseOrder Detects erroneous case order inside switch statements.
commentedOutCode Detects commented-out code inside function bodies.
deferInLoop Detects defer in loop and warns that it will not be executed till the end of function's scope.
docStub Detects comments that silence go lint complaints about doc-comment.
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.
emptyFmt Detects usages of formatting functions without formatting arguments.
evalOrder Detects potentially unsafe dependencies on evaluation order.
hugeParam Detects params that incur excessive amount of copying.
importShadow Detects when imported package names shadowed in assignments.
indexOnlyLoop Detects for loops that can benefit from rewrite to range loop.
longChain Detects repeated expression chains and suggest to refactor them.
namedConst Detects literals that can be replaced with defined named const.
nestingReduce Finds where nesting level could be reduced.
ptrToRefParam Detects input and output parameters that have a type of pointer to referential type.
regexpMust Detects `regexp.Compile*` that can be replaced with `regexp.MustCompile*`.
stdExpr Detects constant expressions that can be replaced by a named constant
unexportedCall :nerd_face: Detects calls of unexported method from unexported type outside that type.
unnamedResult For functions with multiple return values, detects unnamed results
unusedParam Detects unused params and suggests to name them as `_` (underscore).
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)

boolExprSimplify

Detects bool expressions that can be simplified for the sake of readability.

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:

func main() {
	// shadowing len function
	len := 10
	println(len)
}

After:

func main() {
	// change identificator name
	length := 10
	println(length)
}

builtinShadow is syntax-only checker (fast).

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)

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: // <- everything is good
	// ...
}

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

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

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.

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

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.

Permits single else or else-if; repeated else-if or else + else-if will trigger suggestion to use 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.
}

ifElseChain is syntax-only checker (fast).

importShadow

Detects when imported package names shadowed in assignments.

Before:

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

After:

func myFunc(filename string) {
}

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

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)

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

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

ptrToRefParam

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

Before:

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

After:

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

Slices are not as referential as maps or channels, but it’s usually better to return them by value rather than modyfing them by pointer.

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 [256]byte
for _, x := range xs {
	// Loop body.
}

After:

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

rangeValCopy

Detects loops that copy big objects during each iteration.

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

stdExpr

Detects constant expressions that can be replaced by a named constant

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
_ := (*a)[5] // only if a is array

After:

k.field = 5
_ := 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.

unnamedResult

For functions with multiple return values, detects unnamed results

Before:

func f() (float64, float64)

After:

func f() (x, y float64)

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

unusedParam

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

Before:

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

After:

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

yodaStyleExpr

Detects Yoda style expressions that suggest to replace them.

Before:

return nil != ptr

After:

return ptr != nil

yodaStyleExpr is very opinionated.