Documentation

Staticcheck – Checks

Checks

Check Short description
S1??? Code simplifications
S1000 Use plain channel send or receive
S1001 Replace with copy()
S1002 Omit comparison with boolean constant
S1003 Replace with strings.Contains
S1004 Replace with bytes.Equal
S1005 Drop unnecessary use of the blank identifier
S1006 Replace with for { ... }
S1007 Simplify regular expression by using raw string literal
S1008 Simplify returning boolean expression
S1009 Omit redundant nil check on slices
S1010 Omit default slice index
S1011 Use a single append to concatenate two slices
S1012 Replace with time.Since(x)
S1016 Use a type conversion
S1017 Replace with strings.TrimPrefix
S1018 Replace with copy()
S1019 Simplify make call
S1020 Omit redundant nil check in type assertion
S1021 Merge variable declaration and assignment
S1023 Omit redundant control flow
S1024 Replace with time.Until(x)
S1025 Don't use fmt.Sprintf("%s", x) unnecessarily
S1028 Replace with fmt.Errorf
S1029 Range over the string
S1030 Use bytes.Buffer.String or bytes.Buffer.Bytes
S1031 Omit redundant nil check around loop
S1032 Replace with sort.Ints(x), sort.Float64s(x), sort.Strings(x)
SA1??? Various misuses of the standard library
SA1000 Invalid regular expression
SA1001 Invalid template
SA1002 Invalid format in time.Parse
SA1003 Unsupported argument to functions in encoding/binary
SA1004 Suspiciously small untyped constant in time.Sleep
SA1005 Invalid first argument to exec.Command
SA1006 Printf with dynamic first argument and no further arguments
SA1007 Invalid URL in net/url.Parse
SA1008 Non-canonical key in http.Header map
SA1010 (*regexp.Regexp).FindAll called with n == 0, which will always return zero results
SA1011 Various methods in the strings package expect valid UTF-8, but invalid input is provided
SA1012 A nil context.Context is being passed to a function, consider using context.TODO instead
SA1013 io.Seeker.Seek is being called with the whence constant as the first argument, but it should be the second
SA1014 Non-pointer value passed to Unmarshal or Decode
SA1015 Using time.Tick in a way that will leak. Consider using time.NewTicker, and only use time.Tick in tests, commands and endless functions
SA1016 Trapping a signal that cannot be trapped
SA1017 Channels used with signal.Notify should be buffered
SA1018 strings.Replace called with n == 0, which does nothing
SA1019 Using a deprecated function, variable, constant or field
SA1020 Using an invalid host:port pair with a net.Listen-related function
SA1021 Using bytes.Equal to compare two net.IP
SA1023 Modifying the buffer in an io.Writer implementation
SA1024 A string cutset contains duplicate characters, suggesting TrimPrefix or TrimSuffix should be used instead of TrimLeft or TrimRight
SA1025 it is not possible to use Reset's return value correctly
SA2??? Concurrency issues
SA2000 sync.WaitGroup.Add called inside the goroutine, leading to a race condition
SA2001 Empty critical section, did you mean to defer the unlock?
SA2002 Called testing.T.FailNow or SkipNow in a goroutine, which isn't allowed
SA2003 Deferred Lock right after locking, likely meant to defer Unlock instead
SA3??? Testing issues
SA3000 TestMain doesn't call os.Exit, hiding test failures
SA3001 Assigning to b.N in benchmarks distorts the results
SA4??? Code that isn't really doing anything
SA4000 Boolean expression has identical expressions on both sides
SA4001 &*x gets simplified to x, it does not copy x
SA4002 Comparing strings with known different sizes has predictable results
SA4003 Comparing unsigned values against negative values is pointless
SA4004 The loop exits unconditionally after one iteration
SA4005 Field assignment that will never be observed. Did you mean to use a pointer receiver?
SA4006 A value assigned to a variable is never read before being overwritten. Forgotten error check or dead code?
SA4008 The variable in the loop condition never changes, are you incrementing the wrong variable?
SA4009 A function argument is overwritten before its first use
SA4010 The result of append will never be observed anywhere
SA4011 Break statement with no effect. Did you mean to break out of an outer loop?
SA4012 Comparing a value against NaN even though no value is equal to NaN
SA4013 Negating a boolean twice (!!b) is the same as writing b. This is either redundant, or a typo.
SA4014 An if/else if chain has repeated conditions and no side-effects; if the condition didn't match the first time, it won't match the second time, either
SA4015 Calling functions like math.Ceil on floats converted from integers doesn't do anything useful
SA4016 Certain bitwise operations, such as x ^ 0, do not do anything useful
SA4017 A pure function's return value is discarded, making the call pointless
SA4018 Self-assignment of variables
SA4019 Multiple, identical build constraints in the same file
SA4020 Unreachable case clause in a type switch
SA5??? Correctness issues
SA5000 Assignment to nil map
SA5001 Defering Close before checking for a possible error
SA5002 The empty for loop (for {}) spins and can block the scheduler
SA5003 Defers in infinite loops will never execute
SA5004 for { select { ... with an empty default branch spins
SA5005 The finalizer references the finalized object, preventing garbage collection
SA5006 Slice index out of bounds
SA5007 Infinite recursive call
SA6??? Performance issues
SA6000 Using regexp.Match or related in a loop, should use regexp.Compile
SA6001 Missing an optimization opportunity when indexing maps by byte slices
SA6002 Storing non-pointer values in sync.Pool allocates memory
SA6003 Converting a string to a slice of runes before ranging over it
SA6005 Inefficient string comparison with strings.ToLower or strings.ToUpper
SA9??? Dubious code constructs that have a high probability of being wrong
SA9001 defers in for range loops may not run when you expect them to
SA9002 Using a non-octal os.FileMode that looks like it was meant to be in octal.
SA9003 Empty body in an if or else branch
SA9004 Only the first constant has an explicit type
SA9005 Trying to marshal a struct with no public fields nor custom marshaling
ST1???
ST1000 Incorrect or missing package comment
ST1001 Dot imports are discouraged
ST1003 Poorly chosen identifier
ST1005 Incorrectly formatted error string
ST1006 Poorly chosen receiver name
ST1008 A function's error value should be its last return value
ST1011 Poorly chosen name for variable of type time.Duration
ST1012 Poorly chosen name for error variable
ST1013 Should use constants for HTTP error codes, not magic numbers
ST1015 A switch's default case should be the first or last case
ST1016 Use consistent method receiver names
U1??? Unused code
U1000 Unused code

S1000 – Use plain channel send or receive

select with a single case can be replaced with a simple send or receive.

Before:

select {
case x := <-ch:
  fmt.Println(x)
}

After:

x := <-ch
fmt.Println(x)

Available since
2017.1

S1001 – Replace with copy()

Use copy() for copying elements from one slice to another.

Before:

for i, x := range src {
  dst[i] = x
}
After:
copy(dst, src)

Available since
2017.1

S1002 – Omit comparison with boolean constant

Before:

if x == true {}
After:
if x {}

Available since
2017.1

S1003 – Replace with strings.Contains

Before:

if strings.Index(x, y) != -1 {}
After:
if strings.Contains(x, y) {}

Available since
2017.1

S1004 – Replace with bytes.Equal

Before:

if bytes.Compare(x, y) == 0 {}
After:
if bytes.Equal(x, y) {}

Available since
2017.1

S1005 – Drop unnecessary use of the blank identifier

In many cases, assigning to the blank identifier is unnecessary.

Before:

for _ = range s {}
x, _ = someMap[key]
_ = <-ch
After:
for range s{}
x = someMap[key]
<-ch

Available since
2017.1

S1006 – Replace with for { ... }

For infinite loops, using for { ... } is the most idiomatic choice.

Available since
2017.1

S1007 – Simplify regular expression by using raw string literal

Raw string literals use ` instead of " and do not support any escape sequences. This means that the backslash (\) can be used freely, without the need of escaping.

Since regular expressions have their own escape sequences, raw strings can improve their readability.

Before:

regexp.Compile("\\A(\\w+) profile: total \\d+\\n\\z")
After:
regexp.Compile(`\A(\w+) profile: total \d+\n\z`)

Available since
2017.1

S1008 – Simplify returning boolean expression

Before:

if <expr> {
  return true
}
return false
After:
return <expr>

Available since
2017.1

S1009 – Omit redundant nil check on slices

The len function is defined for all slices, even nil ones, which have a length of zero. It is not necessary to check if a slice is not nil before checking that its length is not zero.

Before:

if x != nil && len(x) != 0 {}
After:
if len(x) != 0 {}

Available since
2017.1

S1010 – Omit default slice index

When slicing, the second index defaults to the length of the value, making s[n:len(s)] and s[n:] equivalent.

Available since
2017.1

S1011 – Use a single append to concatenate two slices

Before:

for _, e := range y {
  x = append(x, e)
}

After:

x = append(x, y...)

Available since
2017.1

S1012 – Replace with time.Since(x)

The time.Since helper has the same effect as using time.Now().Sub(x) but is easier to read.

Before:

time.Now().Sub(x)

After:

time.Since(x)

Available since
2017.1

S1016 – Use a type conversion

Two struct types with identical fields can be converted between each other. In older versions of Go, the fields had to have identical struct tags. Since Go 1.8, however, struct tags are ignored during conversions. It is thus not necessary to manually copy every field individually.

Before:

var x T1
y := T2{
  Field1: x.Field1,
  Field2: x.Field2,
}

After:

var x T1
y := T2(x)

Available since
2017.1

S1017 – Replace with strings.TrimPrefix

Instead of using strings.HasPrefix and manual slicing, use the strings.TrimPrefix function. If the string doesn't start with the prefix, the original string will be returned. Using strings.TrimPrefix reduces complexity, and avoids common bugs, such as off-by-one mistakes.

Before:

if strings.HasPrefix(str, prefix) {
  str = str[len(prefix):]
}

After:

str = strings.TrimPrefix(str, prefix)

Available since
2017.1

S1018 – Replace with copy()

copy() permits using the same source and destination slice, even with overlapping ranges. This makes it ideal for sliding elements in a slice.

Before:

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

After:

copy(bs[:n], bs[offset:])

Available since
2017.1

S1019 – Simplify make call

The make function has default values for the length and capacity arguments. For channels and maps, the length defaults to zero. Additionally, for slices the capacity defaults to the length.

Available since
2017.1

S1020 – Omit redundant nil check in type assertion

Before:

if _, ok := i.(T); ok && i != nil {}

After:

if _, ok := i.(T); ok {}

Available since
2017.1

S1021 – Merge variable declaration and assignment

Before:

var x uint
x = 1

After:

var x uint = 1

Available since
2017.1

S1023 – Omit redundant control flow

Functions that have no return value do not need a return statement as the final statement of the function.

Switches in Go do not have automatic fallthrough, unlike languages like C. It is not necessary to have a break statement as the final statement in a case block.

Available since
2017.1

S1024 – Replace with time.Until(x)

The time.Until helper has the same effect as using x.Sub(time.Now()) but is easier to read.

Before:

x.Sub(time.Now())

After:

time.Until(x)

Available since
2017.1

S1025 – Don't use fmt.Sprintf("%s", x) unnecessarily

In many instances, there are easier and more efficient ways of getting a value's string representation. Whenever a value's underlying type is a string already, or the type has a String method, they should be used directly.

Given the following shared definitions

type T1 string
type T2 int

func (T2) String() string { return "Hello, world" }

var x string
var y T1
var z T2

we can simplify the following

fmt.Sprintf("%s", x)
fmt.Sprintf("%s", y)
fmt.Sprintf("%s", z)

to

x
string(y)
z.String()

Available since
2017.1

S1028 – Replace with fmt.Errorf

Before:

errors.New(fmt.Sprintf(...))

After:

fmt.Errorf(...)

Available since
2017.1

S1029 – Range over the string

Ranging over a string will yield byte offsets and runes. If the offset isn't used, this is functionally equivalent to converting the string to a slice of runes and ranging over that. Ranging directly over the string will be more performant, however, as it avoids allocating a new slice, the size of which depends on the length of the string.

Before:

for _, r := range []rune(s) {}

After:

for _, r := range s {}

Available since
2017.1

S1030 – Use bytes.Buffer.String or bytes.Buffer.Bytes

bytes.Buffer has both a String and a Bytes method. It is never necessary to use string(buf.Bytes()) or []byte(buf.String()) – simply use the other method.

Available since
2017.1

S1031 – Omit redundant nil check around loop

You can use range on nil slices and maps, the loop will simply never execute. This makes an additional nil check around the loop unnecessary.

Before:

if s != nil {
  for _, x := range s {
    ...
  }
}

After:

for _, x := range s {
  ...
}

Available since
2017.1

S1032 – Replace with sort.Ints(x), sort.Float64s(x), sort.Strings(x)

The sort.Ints, sort.Float64s and sort.Strings functions are easier to read than sort.Sort(sort.IntSlice(x)), sort.Sort(sort.Float64Slice(x)) and sort.Sort(sort.StringSlice(x)).

Before:

sort.Sort(sort.StringSlice(x))

After:

sort.Strings(x)

Available since
2019.1

SA1000 – Invalid regular expression

Available since
2017.1

SA1001 – Invalid template

Available since
2017.1

SA1002 – Invalid format in time.Parse

Available since
2017.1

SA1003 – Unsupported argument to functions in encoding/binary

Available since
2017.1

SA1004 – Suspiciously small untyped constant in time.Sleep

Available since
2017.1

SA1005 – Invalid first argument to exec.Command

os/exec runs programs directly (using variants of the fork and exec system calls on Unix systems). This shouldn't be confused with running a command in a shell. The shell will allow for features such as input redirection, pipes, and general scripting. The shell is also responsible for splitting the user's input into a program name and its arguments. For example, the equivalent to ls / /tmp would be exec.Command("ls", "/", "/tmp").

If you want to run a command in a shell, consider using something like the following – but be aware that not all systems, particularly Windows, will have a /bin/sh program:

exec.Command("/bin/sh", "-c", "ls | grep Awesome")

Available since
2017.1

SA1006 – Printf with dynamic first argument and no further arguments

Using fmt.Printf with a dynamic first argument can lead to unexpected output. The first argument is a format string, where certain character combinations have special meaning. If, for example, a user were to enter a string such as Interest rate: 5% and you printed it with fmt.Printf(s), it would lead to the following output: Interest rate: 5%!(NOVERB).

Similarly, forming the first parameter via string concatenation with user input should be avoided for the same reason. When printing user input, either use a variant of fmt.Print, or use the %s Printf verb and pass the string as an argument.

Available since
2017.1

SA1007 – Invalid URL in net/url.Parse

Available since
2017.1

SA1008 – Non-canonical key in http.Header map

Available since
2017.1

SA1010 – (*regexp.Regexp).FindAll called with n == 0, which will always return zero results

Available since
2017.1

SA1011 – Various methods in the strings package expect valid UTF-8, but invalid input is provided

Available since
2017.1

SA1012 – A nil context.Context is being passed to a function, consider using context.TODO instead

Available since
2017.1

SA1013 – io.Seeker.Seek is being called with the whence constant as the first argument, but it should be the second

Available since
2017.1

SA1014 – Non-pointer value passed to Unmarshal or Decode

Available since
2017.1

SA1015 – Using time.Tick in a way that will leak. Consider using time.NewTicker, and only use time.Tick in tests, commands and endless functions

Available since
2017.1

SA1016 – Trapping a signal that cannot be trapped

Available since
2017.1

SA1017 – Channels used with signal.Notify should be buffered

Available since
2017.1

SA1018 – strings.Replace called with n == 0, which does nothing

Available since
2017.1

SA1019 – Using a deprecated function, variable, constant or field

Available since
2017.1

SA1020 – Using an invalid host:port pair with a net.Listen-related function

Available since
2017.1

SA1021 – Using bytes.Equal to compare two net.IP

A net.IP stores an IPv4 or IPv6 address as a slice of bytes. The length of the slice for an IPv4 address, however, can be either 4 or 16 bytes long, using different ways of representing IPv4 addresses. In order to correctly compare two net.IPs, the net.IP.Equal method should be used, as it takes both representations into account.

Available since
2017.1

SA1023 – Modifying the buffer in an io.Writer implementation

Available since
2017.1

SA1024 – A string cutset contains duplicate characters, suggesting TrimPrefix or TrimSuffix should be used instead of TrimLeft or TrimRight

Available since
2017.1

SA1025 – it is not possible to use Reset's return value correctly

Available since
2019.1

SA2000 – sync.WaitGroup.Add called inside the goroutine, leading to a race condition

Available since
2017.1

SA2001 – Empty critical section, did you mean to defer the unlock?

Available since
2017.1

SA2002 – Called testing.T.FailNow or SkipNow in a goroutine, which isn't allowed

Available since
2017.1

SA2003 – Deferred Lock right after locking, likely meant to defer Unlock instead

Available since
2017.1

SA3000 – TestMain doesn't call os.Exit, hiding test failures

Available since
2017.1

SA3001 – Assigning to b.N in benchmarks distorts the results

Available since
2017.1

SA4000 – Boolean expression has identical expressions on both sides

Available since
2017.1

SA4001 – &*x gets simplified to x, it does not copy x

Available since
2017.1

SA4002 – Comparing strings with known different sizes has predictable results

Available since
2017.1

SA4003 – Comparing unsigned values against negative values is pointless

Available since
2017.1

SA4004 – The loop exits unconditionally after one iteration

Available since
2017.1

SA4005 – Field assignment that will never be observed. Did you mean to use a pointer receiver?

Available since
2017.1

SA4006 – A value assigned to a variable is never read before being overwritten. Forgotten error check or dead code?

Available since
2017.1

SA4008 – The variable in the loop condition never changes, are you incrementing the wrong variable?

Available since
2017.1

SA4009 – A function argument is overwritten before its first use

Available since
2017.1

SA4010 – The result of append will never be observed anywhere

Available since
2017.1

SA4011 – Break statement with no effect. Did you mean to break out of an outer loop?

Available since
2017.1

SA4012 – Comparing a value against NaN even though no value is equal to NaN

Available since
2017.1

SA4013 – Negating a boolean twice (!!b) is the same as writing b. This is either redundant, or a typo.

Available since
2017.1

SA4014 – An if/else if chain has repeated conditions and no side-effects; if the condition didn't match the first time, it won't match the second time, either

Available since
2017.1

SA4015 – Calling functions like math.Ceil on floats converted from integers doesn't do anything useful

Available since
2017.1

SA4016 – Certain bitwise operations, such as x ^ 0, do not do anything useful

Available since
2017.1

SA4017 – A pure function's return value is discarded, making the call pointless

Available since
2017.1

SA4018 – Self-assignment of variables

Available since
2017.1

SA4019 – Multiple, identical build constraints in the same file

Available since
2017.1

SA4020 – Unreachable case clause in a type switch

In a type switch like the following

type T struct{}
func (T) Read(b []byte) (int, error) { return 0, nil }

var v interface{} = T{}

switch v.(type) {
case io.Reader:
    // ...
case T:
    // unreachable
}

the second case clause can never be reached because T implements io.Reader and case clauses are evaluated in source order.

Another example:

type T struct{}
func (T) Read(b []byte) (int, error) { return 0, nil }
func (T) Close() error { return nil }

var v interface{} = T{}

switch v.(type) {
case io.Reader:
    // ...
case io.ReadCloser:
    // unreachable
}

Even though T has a Close method and thus implements io.ReadCloser, io.Reader will always match first. The method set of io.Reader is a subset of io.ReadCloser. Thus it is impossible to match the second case without mtching the first case.

Structurally equivalent interfaces

A special case of the previous example are structurally identical interfaces. Given these declarations

type T error
type V error

func doSomething() error {
    err, ok := doAnotherThing()
    if ok {
        return T(err)
    }

    return U(err)
}

the following type switch will have an unreachable case clause:

switch doSomething().(type) {
case T:
    // ...
case V:
    // unreachable
}

T will always match before V because they are structurally equivalent and therefore doSomething()'s return value implements both.

Available since
Unreleased

SA5000 – Assignment to nil map

Available since
2017.1

SA5001 – Defering Close before checking for a possible error

Available since
2017.1

SA5002 – The empty for loop (for {}) spins and can block the scheduler

Available since
2017.1

SA5003 – Defers in infinite loops will never execute

Available since
2017.1

SA5004 – for { select { ... with an empty default branch spins

Available since
2017.1

SA5005 – The finalizer references the finalized object, preventing garbage collection

A finalizer is a function associated with an object that runs when the garbage collector is ready to collect said object, that is when the object is no longer referenced by anything.

If the finalizer references the object, however, it will always remain as the final reference to that object, preventing the garbage collector from collecting the object. The finalizer will never run, and the object will never be collected, leading to a memory leak. That is why the finalizer should instead use its first argument to operate on the object. That way, the number of references can temporarily go to zero before the object is being passed to the finalizer.

Available since
2017.1

SA5006 – Slice index out of bounds

Available since
2017.1

SA5007 – Infinite recursive call

A function that calls itself recursively needs to have an exit condition. Otherwise it will recurse forever, until the system runs out of memory.

This issue can be caused by simple bugs such as forgetting adding an exit condition. It can also happen "on purpose". Some languages have tail call optimization which makes certain infinite recursive calls safe to use. Go, however, does not implement TCO, and as such a loop should be used instead.

Available since
2017.1

SA6000 – Using regexp.Match or related in a loop, should use regexp.Compile

Available since
2017.1

SA6001 – Missing an optimization opportunity when indexing maps by byte slices

Map keys must be comparable, which precludes the use of []byte. This usually leads to using string keys and converting []bytes to strings.

Normally, a conversion of []byte to string needs to copy the data and causes allocations. The compiler, however, recognizes m[string(b)] and uses the data of b directly, without copying it, because it knows that the data can't change during the map lookup. This leads to the counter-intuitive situation that

k := string(b)
println(m[k])
println(m[k])

will be less efficient than

println(m[string(b)])
println(m[string(b)])

because the first version needs to copy and allocate, while the second one does not.

For some history on this optimization, check out commit f5f5a8b6209f84961687d993b93ea0d397f5d5bf.

Available since
2017.1

SA6002 – Storing non-pointer values in sync.Pool allocates memory

A sync.Pool is used to avoid unnecessary allocations and reduce the amount of work the garbage collector has to do.

When passing a value that is not a pointer to a function that accepts an interface, the value needs to be placed on the heap, which means an additional allocation. Slices are a common thing to put in sync.Pools, and they're structs with 3 fields (length, capacity, and a pointer to an array). In order to avoid the extra allocation, one should store a pointer to the slice instead.

See the comments on a Go CL that discuss this problem.

Available since
2017.1

SA6003 – Converting a string to a slice of runes before ranging over it

You may want to loop over the runes in a string. Instead of converting the string to a slice of runes and looping over that, you can loop over the string itself. That is,

for _, r := range s {}

and

for _, r := range []rune(s) {}

will yield the same values. The first version, however, will be faster and avoid unnecessary memory allocations.

Do note that if you are interested in the indices, ranging over a string and over a slice of runes will yield different indices. The first one yields byte offsets, while the second one yields indices in the slice of runes.

Available since
2017.1

SA6005 – Inefficient string comparison with strings.ToLower or strings.ToUpper

Converting two strings to the same case and comparing them like so

if strings.ToLower(s1) == strings.ToLower(s2) {
    ...
}
is significantly more expensive than comparing them with strings.EqualFold(s1, s2). This is due to memory usage as well as computational complexity.

strings.ToLower will have to allocate memory for the new strings, as well as convert both strings fully, even if they differ on the very first byte. strings.EqualFold, on the other hand, compares the strings one character at a time. It doesn't need to create two intermediate strings and can return as soon as the first non-matching character has been found.

For a more in-depth explanation of this issue, see How to Efficiently Compare Strings in Go.

Available since
Unreleased

SA9001 – defers in for range loops may not run when you expect them to

Available since
2017.1

SA9002 – Using a non-octal os.FileMode that looks like it was meant to be in octal.

Available since
2017.1

SA9003 – Empty body in an if or else branch

Available since
2017.1

SA9004 – Only the first constant has an explicit type

In a constant declaration such as the following:

const (
    First byte = 1
    Second     = 2
)

the constant Second does not have the same type as the constant First. This construct shouldn't be confused with

const (
    First byte = iota
    Second
)

where First and Second do indeed have the same type. The type is only passed on when no explicit value is assigned to the constant.

When declaring enumerations with explicit values it is therefore important not to write

const (
      EnumFirst EnumType = 1
      EnumSecond         = 2
      EnumThird          = 3
)

This discrepancy in types can cause various confusing behaviors and bugs.

Wrong type in variable declarations

The most obvious issue with such incorrect enumerations expresses itself as a compile error:

package pkg

const (
    EnumFirst  uint8 = 1
    EnumSecond       = 2
)

func fn(useFirst bool) {
    x := EnumSecond
    if useFirst {
        x = EnumFirst
    }
}

fails to compile with

./const.go:11:5: cannot use EnumFirst (type uint8) as type int in assignment

Losing method sets

A more subtle issue occurs with types that have methods and optional interfaces. Consider the following:

package main

import "fmt"

type Enum int

func (e Enum) String() string {
    return "an enum"
}

const (
    EnumFirst  Enum = 1
    EnumSecond      = 2
)

func main() {
    fmt.Println(EnumFirst)
    fmt.Println(EnumSecond)
}

This code will output

an enum
2

as EnumSecond has no explicit type, and thus defaults to int.

Available since
2019.1

SA9005 – Trying to marshal a struct with no public fields nor custom marshaling

The encoding/json and encoding/xml packages only operate on exported fields in structs, not unexported ones. It is usually an error to try to (un)marshal structs that only consist of unexported fields.

This check will not flag calls involving types that define custom marshaling behavior, e.g. via MarshalJSON methods. It will also not flag empty structs.

Available since
Unreleased

ST1000 – Incorrect or missing package comment non-default

Packages must have a package comment that is formatted according to the guidelines laid out in https://github.com/golang/go/wiki/CodeReviewComments#package-comments.

Available since
2019.1

ST1001 – Dot imports are discouraged

Dot imports that aren't in external test packages are discouraged.

The dot_import_whitelist option can be used to whitelist certain imports.

The import . form can be useful in tests that, due to circular dependencies, cannot be made part of the package being tested:

package foo_test

import (
    "bar/testutil" // also imports "foo"
    . "foo"
)

In this case, the test file cannot be in package foo because it uses bar/testutil, which imports foo. So we use the 'import .' form to let the file pretend to be part of package foo even though it is not. Except for this one case, do not use import . in your programs. It makes the programs much harder to read because it is unclear whether a name like Quux is a top-level identifier in the current package or in an imported package.

Available since
2019.1
Options
dot_import_whitelist

ST1003 – Poorly chosen identifier non-default

Identifiers, such as variable and package names, follow certain rules.

See the following links for details:

Available since
2019.1
Options
initialisms

ST1005 – Incorrectly formatted error string

Error strings follow a set of guidelines to ensure uniformity and good composability.

Error strings should not be capitalized (unless beginning with proper nouns or acronyms) or end with punctuation, since they are usually printed following other context. That is, use fmt.Errorf("something bad") not fmt.Errorf("Something bad"), so that log.Printf("Reading %s: %v", filename, err) formats without a spurious capital letter mid-message.

Available since
2019.1

ST1006 – Poorly chosen receiver name

The name of a method's receiver should be a reflection of its identity; often a one or two letter abbreviation of its type suffices (such as "c" or "cl" for "Client"). Don't use generic names such as "me", "this" or "self", identifiers typical of object-oriented languages that place more emphasis on methods as opposed to functions. The name need not be as descriptive as that of a method argument, as its role is obvious and serves no documentary purpose. It can be very short as it will appear on almost every line of every method of the type; familiarity admits brevity. Be consistent, too: if you call the receiver "c" in one method, don't call it "cl" in another.

Available since
2019.1

ST1008 – A function's error value should be its last return value

A function's error value should be its last return value.

Available since
2019.1

ST1011 – Poorly chosen name for variable of type time.Duration

time.Duration values represent an amount of time, which is represented as a count of nanoseconds. An expression like 5 * time.Microsecond yields the value 5000. It is therefore not appropriate to suffix a variable of type time.Duration with any time unit, such as Msec or Milli.

Available since
2019.1

ST1012 – Poorly chosen name for error variable

Error variables that are part of an API should be called errFoo or ErrFoo.

Available since
2019.1

ST1013 – Should use constants for HTTP error codes, not magic numbers

HTTP has a tremendous number of status codes. While some of those are well known (200, 400, 404, 500), most of them are not. The net/http package provides constants for all status codes that are part of the various specifications. It is recommended to use these constants instead of hard-coding magic numbers, to vastly improve the readability of your code.

Available since
2019.1
Options
http_status_code_whitelist

ST1015 – A switch's default case should be the first or last case

Available since
2019.1

ST1016 – Use consistent method receiver names non-default

Available since
2019.1

U1000 – Unused code

Available since
2017.1