Omit Redundant Nil Check
ID |
go.omit_redundant_nil_check |
Severity |
info |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Code Smell |
Language |
Go |
Tags |
CWE:1164, code-style, readability |
Description
Reports a nil check that is made redundant by an adjacent len comparison on the same value.
The len builtin is defined for nil slices, maps and channels — a nil one has length zero — so a
guard like if x != nil && len(x) != 0 can drop the x != nil operand, and if x == nil ||
len(x) == 0 can drop the x == nil operand.
Rationale
Because len(nil) is 0 for a slice, map or channel, the length comparison already decides the
nil case, and the explicit nil test adds nothing but noise. The check only fires when the length
comparison is genuinely conclusive: with && it must be false at length zero (!= 0, > 0,
>= 1, == 5, …), and with || it must be true at length zero (== 0, ⇐ 0, < 2, …).
Comparisons that are not conclusive — len(x) >= 0 (always true) or x != nil && len(x) == 0
(non-nil but empty is a real distinction) — are left alone. A pointer to an array (*[N]T) is
excluded because len dereferences it, making the nil test necessary, and an impure operand such
as gen() != nil && len(gen()) != 0 is never flagged.
func fn(s []int) {
if s != nil && len(s) != 0 { // FLAW — len(s) != 0 already implies s != nil
// ...
}
if len(s) != 0 { // OK — the nil check was redundant
// ...
}
if s != nil && len(s) == 0 { // OK — non-nil but empty is a meaningful case
// ...
}
}