Code Inspections in Go
This topic lists all GoLand code inspections available in Go.
You can toggle specific inspections or change their severity level on the Editor | Inspections page of the IDE settings Ctrl+Alt+S.
Probable bugs
Inspection | Description | Default Severity |
---|---|---|
'FailNow' in a non-test goroutine | Reports calls to FailNow call runtime.Goexit and stop the calling goroutine, not the test. Therefore, they must only be called from the goroutine that runs the test or benchmark. For more information about FailNow , see func (*T) FailNow at golang.org. Example: func TestFoo(t *testing.T) {
go func() {
t.Fatal("oops") //exits goroutine, not TestFoo
}()
} After the Replace with 'Error' and 'return' quick-fix is applied: func TestFoo(t *testing.T) {
go func() {
t.Error("oops")
return
}()
} | Warning |
'Unmarshal' is called with the incorrect argument | Reports calls to Unmarshal , see func Unmarshal at golang.org. Example: var animals []Animal
err := json.Unmarshal(jsonData, animals) // always returns an error After the Prepend '&' quick-fix is applied: var animals []Animal
err := json.Unmarshal(jsonData, &animals) | Warning |
'context.CancelFunc' is not called | Reports execution paths that do not call the WithCancel , WithDeadline , and WithTimeout functions take a Context (the parent) and return a derived Context (the child) and a CancelFunc . Calling the CancelFunc cancels the child and its children, removes the parent's reference to the child, and stops any associated timers. Failing to call the CancelFunc leaks the child and its children until the parent is canceled or the timer fires. For more information about the context package, see Package context at golang.org. Example: func _(ctx context.Context, cancel func()) {
var ctx2 context.Context
ctx2, cancel = context.WithCancel(ctx)
_ = ctx2
}
| Warning |
Defer/go statement calls 'recover' or 'panic' directly | Reports panic() and recover() mechanism. In particular:
| Weak warning |
Division by zero | Reports division by zero. Division by zero will lead to a runtime panic. Example:s := 3 / 0 | Warning |
Exceeded shift expression | Reports shift expressions that equal or exceed the width of the integer. All the bits of the left operand are shifted in such expression resulting in a constant value. The constant value indicates that either the shift offset is incorrect or the shift expression is redundant. Example:
func shift(i int8) {
fmt.Println(i << 8) // always prints 0
}
| Warning |
Imported package name as a name identifier | Reports declarations of variables, arguments or functions that overlap with the used import. While legal, such declarations will make using the package exported identifiers impossible after the declaration or create confusion when reading the code. Example:import "fmt"
import _ "fmt"
import iio "io"
func _() {
fmt.Println("demo")
demo := true
_, _ = iio.EOF, demo
}
func demo() (int, int) {
return 1, 2
}
func _() {
_, _ = iio.EOF, demo
fmt := "demo"
iio := 1
_, _ = iio, fmt
a, _ := demo()
_ = a
} Variable names fmt and iio clash with names of import packages. Not to confuse them later in code, it is better to rename these variables. | Warning |
Impossible interface type assertion | Reports impossible interface-to-interface type assertions. Checks for type assertionsv.(T) and corresponding type-switch cases in which the static type V of v is the interface that cannot possibly implement the target interface T . This occurs when V and T contain methods with the same name but different signatures. Example: var v interface {
Read()
}
_ = v.(io.Reader) The Read method in v has a different signature than the Read method in io.Reader , so this assertion cannot succeed. This inspection only reports if the language version is 1.15 or higher. | Warning |
Incorrect 'strings.Replace' count argument | Reports 0 as it will not replace anything and make the function call redundant. Use -1 instead. Example: a := strings.Replace("SSS", "S", "H", 0) // replaces nothing
b := strings.Replace("SSS", "S", "H", -1) // replaces all S occurrences with H | Warning |
Incorrect usage of 'fmt.Printf' and 'fmt.Println' functions | Reports incorrect usages of %s , %d , %v , and others. If formatting verbs are used incorrectly, the result of a formatting function will contain an error. For more information about formatting verbs, see Package fmt at golang.org. Example: fmt.Printf("id: %s", 42) The output of this function is id: %!s(int=42) . It might be not what you really want. The following function uses the %d formatting verb. The output with the %d formatting verb will be id: 42 . fmt.Printf("id: %d", 42) | Weak warning |
Incorrect usage of the 'errors.As' function | Reports calls of the As function, see func As at golang.org. Example: _, err := os.Open("non-existing")
var pathError *fs.PathError
if errors.As(err, pathError) { // a pointer to *fs.PathError is required
} After the Prepend '&' quick-fix is applied: _, err := os.Open("non-existing")
var pathError *fs.PathError
if errors.As(err, &pathError) {
} This inspection only reports if the language version is 1.13 or higher. | Warning |
Incorrect usage of the 'sync/atomic' package | Reports assignment statements of the form sync/atomic API. To make them atomic, one need to remove the assignment to use a direct call: atomic.AddUint64(&x, 1) . In that case, the value of x will be updated atomically by address. Example: import (
"sync/atomic"
)
type Counter uint64
func AtomicTests() {
x := uint64(1)
x = atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value"
_, x = 10, atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value"
x, _ = atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value"
} | Warning |
Integer to string type conversion | Reports conversions of x , and not a decimal string representation of x as one might expect. Furthermore, if x denotes an invalid code point, the conversion cannot be statically rejected. For conversions that intend on using the code point, consider replacing them with string(rune(x)) . Otherwise, strconv.Itoa and its equivalents return the string representation of the value in the desired base. Example: func main() {
a := 1
_ = string(a)
} After the Convert integer to rune quick-fix is applied: func main() {
a := 1
_ = string(rune(a))
} | Warning |
Invalid conversions of 'uintptr' to 'unsafe.Pointer' | Reports possibly incorrect conversions of uintptr to unsafe.Pointer is invalid if it implies that there is a uintptr -typed word in memory that holds a pointer value, because that word will be invisible to stack copying and to the garbage collector. Example of invalid usage: nums := []int8{42, 24}
ptr := unsafe.Pointer(&nums[0])
addr := uintptr(ptr) // address is stored to a local variable
ptr = unsafe.Pointer(addr + uintptr(1)) Example of valid usage: nums := []int8{42, 24}
ptr := unsafe.Pointer(&nums[0])
ptr = unsafe.Pointer(uintptr(ptr) + uintptr(1)) | Warning |
Locks mistakenly passed by value | Reports locks that are mistakenly passed by values. Accidentally copying a value containing a lock may cause both copies to work incorrectly. Generally, such values should be referred to through a pointer. A lock here means a type implementingsync.Locker , such as sync.Mutex or sync.WaitGroup . Example: type SafeInt struct {
m sync.Mutex
i int
}
func (s SafeInt) Inc() { // mutex is copied
s.m.Lock()
s.i++
s.m.Unlock()
} After the Add pointer quick-fix is applied: type SafeInt struct {
m sync.Mutex
i int
}
func (s *SafeInt) Inc() {
s.m.Lock()
s.i++
s.m.Unlock()
} | Warning |
Loop variables captured by the func literal | Reports references to loop variables from within for _, v := range []string{"a", "b", "c"} {
go func() {
fmt.Println(v) // output will likely be `c c c`, not `a b c`
}()
} After the quick-fix is applied: for _, v := range []string{"a", "b", "c"} {
v := v // `v` is copied now
go func() {
fmt.Println(v)
}()
} Note the analyzer only checks defer and go statements when they are the last statement in the loop body. Otherwise, the analysis might produce false detections. | Warning |
Malformed build tag | Reports malformed build tags and build tags in the incorrect location. The package main
// +build ignore
func main() {} The // +build ignore part should be before the package declaration. To fix that, you can apply the Place build tag before package quick-fix. After the quick-fix is applied: // +build ignore
package main
import "fmt" | Weak warning |
Malformed struct tag | Reports struct tags that do not conform to Go conventions for struct tags. According to these conventions, tag strings are a concatenation of optionally space-separatedkey:"value" pairs. Each key is a non-empty string consisting of non-control characters other than space (U+0020 ' ') , quote (U+0022 '"') , and colon (U+003A ':') . Each value is quoted using U+0022 '"' characters and Go string literal syntax. Also, the inspection checks that fields with tags are exported. Example of a valid tag: type Example struct {
Field int `json:"field" xml:"demo"`
} | Warning |
Non-standard signature for well-known function names | Reports methods with certain names in the following cases:
type MyReader []byte
func (r MyReader) ReadByte(data []byte) (byte, error) {
} The usage is suspicious because it looks like an attempt to implement io.ByteReader but the signature is wrong. More correct version will be as follows: type MyReader []byte
func (r MyReader) ReadByte() (byte, error) {
} | Warning |
Reserved word used as name | Reports declarations of variables, arguments or functions that overlap with the built-in or reserved keyword. If you receive this error then your code might not be as explicit as possible and might confuse other users. Example:type byte struct{}
type string interface{} Types byte and string collide with the built-in type aliases. Therefore, they will be highlighted. consider renaming such declarations. | Warning |
Shadowing variable | Reports declarations of variables that overlap with the declarations in the outer scope. As the meaning of the variable depends on the scope in that case, it may create confusion and lead to unintended consequences. Example:for i := 0; i < len(nums); i++ {
for i := 0; i < len(nums); i++ {
}
} The i variable in the embedded loop is shadowed. To get rid of shadowing, consider renaming the variable in the embedded loop. for i := 0; i < len(nums); i++ {
for j := 0; j < len(nums); j++ {
}
} | No highlighting, only fix |
Unhandled error | Reports calls to functions and methods that do not handle the call result of the
os.Remove("non-existing") // error is ignored After the Handle error quick-fix is applied: err := os.Remove("non-existing") // error is handled
if err != nil {
return err
} | Warning |
Unused function or method call result | Reports calls to certain functions and methods that do not handle a call result. An API of such functions imply that users should call them mostly to get a return value and process it, not for side effects. Calls that do not handle the result could be an indication of a misuse of the API. Example:fmt.Errorf("error: %s", reason) // constructed error is ignored After the Introduce local variable quick-fix is applied: err := fmt.Errorf("error: %s", reason) | Warning |
Control flow issues
Inspection | Description | Default Severity |
---|---|---|
'defer' in the loop | Reports defer in loops can lead to resource leaks or unpredictable execution order of statements. Example: func main() {
for {
field, err := db.Query("SELECT 1")
if err != nil {
// ...
}
defer field.Close()
// ...
}
} Calls of defer row.Close() inside the loop are not executed until the function completes its execution. Not at the end of each step of the for loop. Such implementation might lead to overflow of the function's stack and other issues. | Weak warning |
Assignment to a receiver | Reports assignments to method receivers. When you assign a value to the method receiver, the value will not be reflected outside of the method itself. Values will be reflected in subsequent calls from the same method. Example:package main
import "fmt"
type demo struct {
Val int
}
func (d *demo) change() {
d = nil // Assignment to the method receiver propagates only to callees but not to callers
d.myVal()
}
func (d *demo) myVal() {
fmt.Printf("my val: %#v\n", d)
}
func (d demo) change2() {
d = demo{} // Assignment to the method receiver doesn't propagate to other calls
d.myVal()
}
func (d *demo) change3() {
d.Val = 3
d.myVal()
}
func main() {
d := &demo{}
d.myVal()
d.change()
d.myVal()
d.Val = 2
d.change2()
d.myVal()
d.change3()
d.myVal()
} | Weak warning |
Infinite 'for' loop | Reports empty func main() {
for {
}
} | Warning |
Unreachable code | Reports code that can never be executed because there exists no control flow path to the code from the rest of the program. Example:func _() int {
print(1)
return 2
println() // This code is unreachable
return 0
} | Warning |
Code style issues
Inspection | Description | Default Severity |
---|---|---|
Comment has no leading space | Reports comments without a leading space. Note that the inspection works only if you select the Add a leading space to comments in Editor | Code Style | Go on the Other tab. Comments with a leading space can be easier to read since the first word is separated from the comment by a space. Example://Prints JSON received from the createJSON function
func printJSON(output []byte) {
fmt.Println(string(output))
} | Weak warning |
Comment of exported element starts with the incorrect name | Reports comments that do not start with the name of the exported element. According to Comment Sentences at golang.org, this is a convention to begin a comment with the name of the exported element. Example:// represents a request to run a command.
type Request struct {} The comment starts with the struct description, not with the struct name. To stick to the convention rules, you can apply the Add prefix to comment quick-fix. After the quick-fix is applied, the comment looks as follows:
// Request represents a request to run a command.
type Request struct {} // better
| Weak warning |
Error string should not be capitalized or end with punctuation | Reports format issues in error strings. Example:err := fmt.Errorf("Cannot read the file!")
log.Printf("Reading %s: %v", file, err) According to Error Strings at golang.org, error strings should not be capitalized or end with punctuation because they might appear among other context. | Weak warning |
Exported element should have a comment | Reports exported declarations without a documentation comment. According to Doc Comments at golang.org, all top-level exported names should have doc comments. Also, for more information about comment sentences, see Comment Sentences at golang.org. | |
Exported element should have its own declaration | Reports exported variables or constants in comma-separated lists of declarations. Example:const C1, C3, C2, C44, C9, C11, C6 = 1, 2, 3, 1, 3, 2, 1 This declaration makes it hard to understand what value each constant has. You can apply the Extract to own declaration quick-fix to make this declaration more readable. After the quick-fix is applied to each constant, the declaration looks as follows: const (
C3 = 2
C2 = 3
C44 = 1
C9 = 3
C11 = 2
C6 = 1
C1 = 1
) | Weak warning |
Name starts with a package name | Reports exported names that start with a package name. This inspection does not report such names in the package myPackage
func MyPackageGetIP() {
} The MyPackageGetIP name will be highlighted as it starts with the package name. According to Package Names at golang.org, all references to names in a package will be done using the package name, so one can omit that name from the identifiers. For example, if you are in a package foo , you do not need a type FooFile , which clients will write as foo.FooFile . Instead, we name the type File , which clients will write as foo.File . | Weak warning |
Receiver has a generic name | Reports receiver names like func (self *MeterSnapshot) Rate5() float64 { return math.Float64frombits(self.rate5) } According to Receiver Names at golang.org, you should not use generic names such as "me", "this", or "self". These identifiers are typical for object-oriented languages and might give the method a special meaning. | Weak warning |
Struct initialization without field names | Reports structures that are initialized without specifying their field names. By default, the inspection is available only when you use the type that is defined in a different package. When initializing a structure, it is better to explicitly state field names in order to ensure that in case of changes in order of these fields or in names of the fields, they will correctly continue to be addressed. Example:_ = io.LimitedReader{nil, 10} The LimitedReader initialization will be highlighted because explicit names for struct fields are missing. You can apply the Add keys and delete zero values quick-fix to the struct initialization. After the quick-fix is applied, the code looks as follows: _ = io.LimitedReader{N: 10} The inspection has the following options:
| Weak warning |
Unit-specific suffix for 'time.Duration' | Reports unit-specific suffixes in constant and variable names of go lint . A list of suffixes that imply a time unit is available in the golang repository at github.com. time.Duration represents a value in nanoseconds, so adding a time unit suffix might make the meaning of the variable confusing, or even indicate a misuse of the time.Duration API. Example: var timeoutSeconds = 5 * time.Second | Weak warning |
Unsorted imports | Reports unsorted imports. All Go programs should be formatted in the same way, the formatting rules are fixed by the gofmt tool. Those rules require imports to be sorted. Example of a wrong sorting:import (
"net"
"errors"
"fmt"
) You can apply the Sort imports quick-fix to fix the sorting. After the quick-fix is applied, the sorting looks as follows: import (
"errors"
"fmt"
"net"
) | Weak warning |
Usage of Snake_Case | Reports usage of snake case instead of camelcase for naming variables, constants and functions. According to MixedCaps at golang.org, camelcase is a convention in Go. Example:func get_external_IP() (string, error) {} The get_external_IP is in snake case but should be in camelcase. You can apply a quick-fix to convert the function name to getExternalIp . | Weak warning |
General
Inspection | Description | Default Severity |
---|---|---|
Deprecated element | Reports usages of deprecated elements. Example:// Deprecated: Use io.SeekStart, io.SeekCurrent, and io.SeekEnd.
const (
SEEK_SET int = 0 // seek relative to the origin of the file
SEEK_CUR int = 1 // seek relative to the current offset
SEEK_END int = 2 // seek relative to the end
) According to Constants at golang.org, SEEK_SET , SEEK_CUR , and SEEK_END are deprecated. | Warning |
Disabled GOPATH indexing | Reports disabled GOPATH indexing that might prevent proper resolution of code references. GOPATH stores your code base and all the files that are necessary for your development. Also, it includes packages that you download and install. If you disabled GOPATH indexing, only project and vendored packages are indexed. It might improve the overall performance but makes it impossible to use packages from GOPATH. | Weak warning |
Malformed test function name | Reports malformed names of tests, benchmarks, and examples. According to Package testing at golang.org, names must follow a special convention in order to make the go tool process them correctly. Example:func Testfoo(*testing.T) {} // the 'go' tool will not run this test After the Rename to quick-fix is applied: func TestFoo(*testing.T) {} | Warning |
Missing trailing comma before a newline in a composite literal | Reports a missing trailing comma before a newline in composite literals, function call arguments, and function parameter lists. Example:func f(f int) (
int,
bool // missing a trailing comma
){
println(1, 2 // missing a trailing comma
)
} | Error |
Redundant parentheses | Reports redundant parentheses in expressions and types. Example:func _(x (int), y ((string))) {
}
func _() {
_ = (1 + 1)
_ = (((1 + 1)))
_ = (((1 + 1))) + (((2 + 2)))
} After the Unwrap parentheses quick-fix is applied: func _(x int, y string) {
}
func _() {
_ = 1 + 1
_ = 1 + 1
_ = (1 + 1) + (2 + 2)
} | Weak warning |
Unexported return type of the exported function | Reports exported functions with unexported return types. Unexported types can be difficult to use when viewing documentation under go doc. Example:type hidden struct{}
func Exported() hidden { // Exported function with the `hidden` unexported return type
return hidden{}
} | Warning |
Unnecessarily exported identifier | Reports exported identifiers that are used only in the package where they are defined but are not used in other packages. Making them exported is redundant and may clutter the API of the package. |
Declaration redundancy
Inspection | Description | Default Severity |
---|---|---|
Bool condition | Reports parts of boolean expressions that are either always func isNonZero(x, y int) bool {
// the second comparison is either always true
// or not executed at all
return x > 0 && x > 0
} You can apply the Simplify expression quick-fix for the x > 0 && x > 0 part. After the quick-fix is applied, the expression looks as follows: x > 0 . | Warning |
Empty declaration | Reports empty declarations. Empty declarations have no effect. If you remove them, you might improve code readability. Example:func main() {
const () // empty declaration
} You can apply the Delete empty declaration quick-fix to remove this declaration. | Warning |
Empty slice declared using a literal | Reports slice declarations with empty literal initializers used instead of nil or an empty slice literal. The first approach is preferred as it does not lead to memory allocation. For more information about empty slices, see Declaring Empty Slices at golang.org. Example: s := []string{} To change the declaration, use the Replace with nil slice declaration (changes semantics) quick-fix. After the quick-fix is applied: var s []string | Weak warning |
Redundant blank argument in range | Reports optional blank variables in range loops. When you use therange loop to iterate over a slice, two values are returned for each iteration. The first is the index number, and the second is a copy of the element at that index. If you do not need the second value, you can skip this element instead of using a blank identifier. Example: for a, _ = range v {} // `for a, _ =` is the same as `for a =` To remove the blank identifier, you can use the Delete blank argument quick-fix. After the quick-fix is applied, the code will look as follows: for a = range v {} | Warning |
Redundant comma | Reports commas that may be omitted in the end of argument lists and composite literals. The IDE suggests removing commas that are considered optional. Removing these commas might improve code readability. Example:s := []int{1, 2,} // the last comma may be omitted | Weak warning |
Redundant import alias | Reports aliases of imported packages that may be omitted. Usually, such aliases equal to the names of the imported packages, so aliases have no effect and one can use package names directly. Example:import fmt "fmt" The fmt alias duplicates the package name that is also named "fmt" . To delete the alias, use the Delete import alias quick-fix. After the quick-fix is applied: import "fmt" | Weak warning |
Redundant second index in slices | Reports a redundant second index (a high bound) in slice expressions. Usually, the second index is optional. If you remove it, you might improve code readability. Example:var a []int
a = a[0:len(a)] // `a[0:len(a)]` is the same as `a[0:]` You can apply the Remove redundant index quick-fix to such cases. After the quick-fix is applied, this code looks as follows: var a []int
a = a[0:] | Warning |
Redundant semicolon | Reports redundant semicolons. Idiomatic Go programs have semicolons only in places such as i := 1; | Weak warning |
Redundant type conversion | Reports type conversions that may be omitted. Example:var s = string("hello") The "hello" value is the string type already, the additional conversion to string is redundant. To remove the conversion, consider using the Delete conversion quick-fix. After the quick-fix is applied: var s = "hello" Sometimes conversion of a floating expression to a floating type can be intentional (see this issue as an example). In such cases, the IDE issues a warning about a possibly redundant conversion. | Weak warning |
Redundant types in composite literals | Reports redundant type declarations in composite literals. Example:nums := [][]int{[]int{1}, []int{2}} We have a slice of slices of the int type. In this case, you can use a shorter definition. You can fix this code manually or use the Delete redundant type quick-fix. After the quick-fix is applied, the code looks as follows: nums := [][]int{{1},{2}} For more information about composite literals, see Go Language Specification: Composite Literals at golang.org. | Warning |
Self assignment | Reports expressions that are assigned to themselves. Such assignments have no effect, removing them might improve code readability. Example:func importedVarSelfAssignment() {
http.ErrNotSupported = http.ErrNotSupported
} | Weak warning |
Type can be omitted | Reports types in variable and constant declarations that can be omitted since they can be inferred by the compiler. Such types are redundant, omitting them may improve readability of the code. Example:var s string = fmt.Sprintln("hi") The string type in the variable declaration may be omitted. To remove the type, use the Delete type quick-fix. After the quick-fix is applied: var s = fmt.Sprintln("hi") | Weak warning |
Unused constant | Reports constants that are defined but are never used in code. func main() {
const i = 100
} Unlike unused variables and imports, this code will compile. Unused constants might increase your code base and slow down program compilation. To delete the unused constant, consider using the Delete constant quick-fix. | Warning |
Unused exported function | Reports unused exported functions. In Go, a function is exported if it begins with a capital letter. Names of exported functions that were defined but never used are grayed out.// Unused exported function
func ExportedUnusedFunc() {
}
func main() {
fmt.Println("Hello")
} | Warning |
Unused exported type | Reports unused exported types in the type User struct {}
func main() {} The User struct type is declared but never used in the code. This type will be grayed out. | Warning |
Unused function | Reports unused unexported functions. In Go, a function is unexported if it begins with a small letter. Names of unexported functions that were defined but never used are grayed out.// Unused unexported function
func unExportedUnusedFunc() {
}
func main() {
fmt.Println("Hello")
} | Warning |
Unused global variable | Reports global variables that are defined but are never used in code. If you have unused variables, the code will not compile. For more information about unused variables and imports, see Unused imports and variables at golang.org.func main() {
a := 422
} Code in the example will not compile. Therefore, it is highlighted as an error. You can apply two quick-fixes for such cases: Delete variable and Rename _. The first quick-fix deletes the variable, the second one will convert the variable to a blank identifier. After the Rename _ quick-fix is applied: func main() {
_ := 422
} | Warning |
Unused parameter | Reports unused function parameters. func main() {
printAll(
42,
"bird",
)
}
func printAll(
i int,
s string,
) {
fmt.Println(i)
} We call the printAll function passing 42 and bird as arguments. The printAll function accepts two parameters int and string but uses only the first of them. Therefore, the s string is grayed out. | Warning |
Unused type | Reports unused types. type user struct {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
}
func main() {
} The user type will be grayed out because it is not used anywhere in code. | Warning |