# Go Critic > This document exists to make it clear what fits`go-critic`project and what is not. --- # Source: https://github.com/go-critic/go-critic/blob/master/docs/manifest.md # Project manifest This document exists to make it clear what fits `go-critic` project and what is not.
In a sense, this manifest describes project philosophy. This document may change over time.
Contributors and maintainers are encouraged to discuss it and propose changes.
## What go-critic is It's hard to classify a particular linter due to similarities between them. There are at least 4 linters-related categories: 1. Ones that you run frequently: on your CI, from your editor or IDE. They usually have a false positive rate that is close to zero. Warnings they give are not advices, but directives. [staticcheck](https://github.com/dominikh/go-tools) is a good example. 2. Rule-based checkers. An example of these is project-local codestyle checkers. They are highly customizable and usually check for local conventions as opposed to generally accepted guidelines. [checkstyle](https://github.com/qiniu/checkstyle) may be close to this category. 3. Linter runners. They typically don't implement checks by themselves, but are able to run other linters and aggregate their output. Examples: [gometalinter](https://github.com/alecthomas/gometalinter) and [golangci-lint](https://github.com/golangci/golangci-lint). 4. Linters that are made for code audit. Ones that help you to do code review, 3rd-party library code quality evaluation and so on. False positive rate is quite high to make them worthwhile inside CI. You don't want to break a build due to the warnings they produce. There are advantages of this, see below. Example: [go-critic](https://github.com/go-critic/go-critic). The advantages of not being bound to CI and close-to-zero false positive rate requirement is freedom. We can find code that looks like a bug or suspicious. Some checks can't be done without false positives, but they are still useful. You *have* to check most `go-critic` warnings manually, this is why `quickfix`-like features doesn't play well with `go-critic`. You may not want to fix issues found by `go-critic` automatically. --- # Source: https://github.com/go-critic/go-critic/blob/master/docs/overview.md ## Checks overview This page describes checks supported by [go-critic](https://github.com/go-critic/go-critic) linter. [//]: # (This is generated file, please don't edit it yourself.) ## Checkers Total number of checks is 108 :rocket: * :heavy_check_mark: checker is enabled by default. * :white_check_mark: checker is disabled by default. ### Checkers from the "diagnostic" group Diagnostics try to find programming errors in the code. They also detect code that may be correct, but looks suspicious. > All diagnostics are enabled by default (unless it has "experimental" tag). | Name | Short description | |------|-------------------| |:heavy_check_mark:[appendAssign](#appendassign)|Detects suspicious append result assignments| |:heavy_check_mark:[argOrder](#argorder)|Detects suspicious arguments order| |:heavy_check_mark:[badCall](#badcall)|Detects suspicious function calls| |:heavy_check_mark:[badCond](#badcond)|Detects suspicious condition expressions| |:white_check_mark:[badLock](#badlock)|Detects suspicious mutex lock/unlock operations| |:white_check_mark:[badRegexp](#badregexp)|Detects suspicious regexp patterns| |:white_check_mark:[badSorting](#badsorting)|Detects bad usage of sort package| |:white_check_mark:[badSyncOnceFunc](#badsynconcefunc)|Detects bad usage of sync.OnceFunc| |:white_check_mark:[builtinShadowDecl](#builtinshadowdecl)|Detects top-level declarations that shadow the predeclared identifiers| |:heavy_check_mark:[caseOrder](#caseorder)|Detects erroneous case order inside switch statements| |:heavy_check_mark:[codegenComment](#codegencomment)|Detects malformed 'code generated' file comments| |:white_check_mark:[commentedOutCode](#commentedoutcode)|Detects commented-out code inside function bodies| |:white_check_mark:[deferInLoop](#deferinloop)|Detects loops inside functions that use defer| |:heavy_check_mark:[deprecatedComment](#deprecatedcomment)|Detects malformed 'deprecated' doc-comments| |:heavy_check_mark:[dupArg](#duparg)|Detects suspicious duplicated arguments| |:heavy_check_mark:[dupBranchBody](#dupbranchbody)|Detects duplicated branch bodies inside conditional statements| |:heavy_check_mark:[dupCase](#dupcase)|Detects duplicated case clauses inside switch or select statements| |:white_check_mark:[dupOption](#dupoption)|Detects duplicated option function arguments in variadic function calls| |:heavy_check_mark:[dupSubExpr](#dupsubexpr)|Detects suspicious duplicated sub-expressions| |:white_check_mark:[dynamicFmtString](#dynamicfmtstring)|Detects suspicious formatting strings usage| |:white_check_mark:[emptyDecl](#emptydecl)|Detects suspicious empty declarations blocks| |:white_check_mark:[evalOrder](#evalorder)|Detects unwanted dependencies on the evaluation order| |:heavy_check_mark:[exitAfterDefer](#exitafterdefer)|Detects calls to exit/fatal inside functions that use defer| |:white_check_mark:[externalErrorReassign](#externalerrorreassign)|Detects suspicious reassignment of error from another package| |:white_check_mark:[filepathJoin](#filepathjoin)|Detects problems in filepath.Join() function calls| |:heavy_check_mark:[flagDeref](#flagderef)|Detects immediate dereferencing of `flag` package pointers| |:heavy_check_mark:[flagName](#flagname)|Detects suspicious flag names| |:heavy_check_mark:[mapKey](#mapkey)|Detects suspicious map literal keys| |:white_check_mark:[nilValReturn](#nilvalreturn)|Detects return statements those results evaluate to nil| |:heavy_check_mark:[offBy1](#offby1)|Detects various off-by-one kind of errors| |:white_check_mark:[rangeAppendAll](#rangeappendall)|Detects append all its data while range it| |:white_check_mark:[regexpPattern](#regexppattern)|Detects suspicious regexp patterns| |:white_check_mark:[returnAfterHttpError](#returnafterhttperror)|Detects suspicious http.Error call without following return| |:heavy_check_mark:[sloppyLen](#sloppylen)|Detects usage of `len` when result is obvious or doesn't make sense| |:white_check_mark:[sloppyReassign](#sloppyreassign)|Detects suspicious/confusing re-assignments| |:heavy_check_mark:[sloppyTypeAssert](#sloppytypeassert)|Detects redundant type assertions| |:white_check_mark:[sortSlice](#sortslice)|Detects suspicious sort.Slice calls| |:white_check_mark:[sprintfQuotedString](#sprintfquotedstring)|Detects "%s" formatting directives that can be replaced with %q| |:white_check_mark:[sqlQuery](#sqlquery)|Detects issue in Query() and Exec() calls| |:white_check_mark:[syncMapLoadAndDelete](#syncmaploadanddelete)|Detects sync.Map load+delete operations that can be replaced with LoadAndDelete| |:white_check_mark:[truncateCmp](#truncatecmp)|Detects potential truncation issues when comparing ints of different sizes| |:white_check_mark:[uncheckedInlineErr](#uncheckedinlineerr)|Detects unchecked errors in if statements| |:white_check_mark:[unnecessaryDefer](#unnecessarydefer)|Detects redundantly deferred calls| |:white_check_mark:[weakCond](#weakcond)|Detects conditions that are unsafe due to not being exhaustive| ### Checkers from the "style" group Style checks suggest replacing some form of expression/statement with another one that is considered more idiomatic or simple. > Only non-opinionated style checks are enabled by default. | Name | Short description | |------|-------------------| |:heavy_check_mark:[assignOp](#assignop)|Detects assignments that can be simplified by using assignment operators| |:white_check_mark:[boolExprSimplify](#boolexprsimplify)|Detects bool expressions that can be simplified| |:white_check_mark:[builtinShadow](#builtinshadow)|Detects when predeclared identifiers are shadowed in assignments| |:heavy_check_mark:[captLocal](#captlocal)|Detects capitalized names for local variables| |:heavy_check_mark:[commentFormatting](#commentformatting)|Detects comments with non-idiomatic formatting| |:white_check_mark:[commentedOutImport](#commentedoutimport)|Detects commented-out imports| |:heavy_check_mark:[defaultCaseOrder](#defaultcaseorder)|Detects when default case in switch isn't on 1st or last position| |:white_check_mark:[deferUnlambda](#deferunlambda)|Detects deferred function literals that can be simplified| |:white_check_mark:[docStub](#docstub)|Detects comments that silence go lint complaints about doc-comment| |:white_check_mark:[dupImport](#dupimport)|Detects multiple imports of the same package under different aliases| |:heavy_check_mark:[elseif](#elseif)|Detects else with nested if statement that can be replaced with else-if| |:white_check_mark:[emptyFallthrough](#emptyfallthrough)|Detects fallthrough that can be avoided by using multi case values| |:white_check_mark:[emptyStringTest](#emptystringtest)|Detects empty string checks that can be written more idiomatically| |:white_check_mark:[exposedSyncMutex](#exposedsyncmutex)|Detects exposed methods from sync.Mutex and sync.RWMutex| |:white_check_mark:[hexLiteral](#hexliteral)|Detects hex literals that have mixed case letter digits| |:white_check_mark:[httpNoBody](#httpnobody)|Detects nil usages in http.NewRequest calls, suggesting http.NoBody as an alternative| |:heavy_check_mark:[ifElseChain](#ifelsechain)|Detects repeated if-else statements and suggests to replace them with switch statement| |:white_check_mark:[importShadow](#importshadow)|Detects when imported package names shadowed in the assignments| |:white_check_mark:[initClause](#initclause)|Detects non-assignment statements inside if/switch init clause| |:white_check_mark:[methodExprCall](#methodexprcall)|Detects method expression call that can be replaced with a method call| |:white_check_mark:[nestingReduce](#nestingreduce)|Finds where nesting level could be reduced| |:heavy_check_mark:[newDeref](#newderef)|Detects immediate dereferencing of `new` expressions| |:white_check_mark:[octalLiteral](#octalliteral)|Detects old-style octal literals| |:white_check_mark:[paramTypeCombine](#paramtypecombine)|Detects if function parameters could be combined by type and suggest the way to do it| |:white_check_mark:[preferFilepathJoin](#preferfilepathjoin)|Detects concatenation with os.PathSeparator which can be replaced with filepath.Join| |:white_check_mark:[ptrToRefParam](#ptrtorefparam)|Detects input and output parameters that have a type of pointer to referential type| |:white_check_mark:[redundantSprint](#redundantsprint)|Detects redundant fmt.Sprint calls| |:heavy_check_mark:[regexpMust](#regexpmust)|Detects `regexp.Compile*` that can be replaced with `regexp.MustCompile*`| |:white_check_mark:[regexpSimplify](#regexpsimplify)|Detects regexp patterns that can be simplified| |:white_check_mark:[ruleguard](#ruleguard)|Runs user-defined rules using ruleguard linter| |:heavy_check_mark:[singleCaseSwitch](#singlecaseswitch)|Detects switch statements that could be better written as if statement| |:white_check_mark:[stringConcatSimplify](#stringconcatsimplify)|Detects string concat operations that can be simplified| |:white_check_mark:[stringsCompare](#stringscompare)|Detects strings.Compare usage| |:heavy_check_mark:[switchTrue](#switchtrue)|Detects switch-over-bool statements that use explicit `true` tag value| |:white_check_mark:[timeExprSimplify](#timeexprsimplify)|Detects manual conversion to milli- or microseconds| |:white_check_mark:[todoCommentWithoutDetail](#todocommentwithoutdetail)|Detects TODO comments without detail/assignee| |:white_check_mark:[tooManyResultsChecker](#toomanyresultschecker)|Detects function with too many results| |:white_check_mark:[typeAssertChain](#typeassertchain)|Detects repeated type assertions and suggests to replace them with type switch statement| |:white_check_mark:[typeDefFirst](#typedeffirst)|Detects method declarations preceding the type definition itself| |:heavy_check_mark:[typeSwitchVar](#typeswitchvar)|Detects type switches that can benefit from type guard clause with variable| |:white_check_mark:[typeUnparen](#typeunparen)|Detects unneeded parenthesis inside type expressions and suggests to remove them| |:heavy_check_mark:[underef](#underef)|Detects dereference expressions that can be omitted| |:white_check_mark:[unlabelStmt](#unlabelstmt)|Detects redundant statement labels| |:heavy_check_mark:[unlambda](#unlambda)|Detects function literals that can be simplified| |:white_check_mark:[unnamedResult](#unnamedresult)|Detects unnamed results that may benefit from names| |:white_check_mark:[unnecessaryBlock](#unnecessaryblock)|Detects unnecessary braced statement blocks| |:heavy_check_mark:[unslice](#unslice)|Detects slice expressions that can be simplified to sliced expression itself| |:heavy_check_mark:[valSwap](#valswap)|Detects value swapping code that are not using parallel assignment| |:white_check_mark:[whyNoLint](#whynolint)|Ensures that `//nolint` comments include an explanation| |:heavy_check_mark:[wrapperFunc](#wrapperfunc)|Detects function calls that can be replaced with convenience wrappers| |:white_check_mark:[yodaStyleExpr](#yodastyleexpr)|Detects Yoda style expressions and suggests to replace them| ### Checkers from the "performance" group Performance checks tell you about potential issues that can make your code run slower than it could be. > All performance checks are disabled by default. | Name | Short description | |------|-------------------| |:white_check_mark:[appendCombine](#appendcombine)|Detects `append` chains to the same slice that can be done in a single `append` call| |:white_check_mark:[equalFold](#equalfold)|Detects unoptimal strings/bytes case-insensitive comparison| |:white_check_mark:[hugeParam](#hugeparam)|Detects params that incur excessive amount of copying| |:white_check_mark:[indexAlloc](#indexalloc)|Detects strings.Index calls that may cause unwanted allocs| |:white_check_mark:[preferDecodeRune](#preferdecoderune)|Detects expressions like []rune(s)[0] that may cause unwanted rune slice allocation| |:white_check_mark:[preferFprint](#preferfprint)|Detects fmt.Sprint(f/ln) calls which can be replaced with fmt.Fprint(f/ln)| |:white_check_mark:[preferStringWriter](#preferstringwriter)|Detects w.Write or io.WriteString calls which can be replaced with w.WriteString| |:white_check_mark:[preferWriteByte](#preferwritebyte)|Detects WriteRune calls with rune literal argument that is single byte and reports to use WriteByte instead| |:white_check_mark:[rangeExprCopy](#rangeexprcopy)|Detects expensive copies of `for` loop range expressions| |:white_check_mark:[rangeValCopy](#rangevalcopy)|Detects loops that copy big objects during each iteration| |:white_check_mark:[sliceClear](#sliceclear)|Detects slice clear loops, suggests an idiom that is recognized by the Go compiler| |:white_check_mark:[stringXbytes](#stringxbytes)|Detects redundant conversions between string and []byte| |:white_check_mark:[zeroByteRepeat](#zerobyterepeat)|Detects bytes.Repeat with 0 value| ## appendAssign [ **diagnostic** ] Detects suspicious append result assignments. **Before:** ```go p.positives = append(p.negatives, x) p.negatives = append(p.negatives, y) ``` **After:** ```go p.positives = append(p.positives, x) p.negatives = append(p.negatives, y) ``` ## appendCombine [ **performance** ] Detects `append` chains to the same slice that can be done in a single `append` call. **Before:** ```go xs = append(xs, 1) xs = append(xs, 2) ``` **After:** ```go xs = append(xs, 1, 2) ``` ## argOrder [ **diagnostic** ] Detects suspicious arguments order. **Before:** ```go strings.HasPrefix("#", userpass) ``` **After:** ```go strings.HasPrefix(userpass, "#") ``` ## assignOp [ **style** ] Detects assignments that can be simplified by using assignment operators. **Before:** ```go x = x * 2 ``` **After:** ```go x *= 2 ``` ## badCall [ **diagnostic** ] Detects suspicious function calls. **Before:** ```go strings.Replace(s, from, to, 0) ``` **After:** ```go strings.Replace(s, from, to, -1) ``` ## badCond [ **diagnostic** ] Detects suspicious condition expressions. **Before:** ```go for i := 0; i > n; i++ { xs[i] = 0 } ``` **After:** ```go for i := 0; i < n; i++ { xs[i] = 0 } ``` ## badLock [ **diagnostic** **experimental** ] Detects suspicious mutex lock/unlock operations. **Before:** ```go mu.Lock(); mu.Unlock() ``` **After:** ```go mu.Lock(); defer mu.Unlock() ``` ## badRegexp [ **diagnostic** **experimental** ] Detects suspicious regexp patterns. **Before:** ```go regexp.MustCompile(`(?:^aa|bb|cc)foo[aba]`) ``` **After:** ```go regexp.MustCompile(`^(?:aa|bb|cc)foo[ab]`) ``` ## badSorting [ **diagnostic** **experimental** ] Detects bad usage of sort package. **Before:** ```go xs = sort.StringSlice(xs) ``` **After:** ```go sort.Strings(xs) ``` ## badSyncOnceFunc [ **diagnostic** **experimental** ] Detects bad usage of sync.OnceFunc. **Before:** ```go sync.OnceFunc(foo)() ``` **After:** ```go fooOnce := sync.OnceFunc(foo); ...; fooOnce() ``` ## boolExprSimplify [ **style** **experimental** ] Detects bool expressions that can be simplified. **Before:** ```go a := !(elapsed >= expectElapsedMin) b := !(x) == !(y) ``` **After:** ```go a := elapsed < expectElapsedMin b := (x) == (y) ``` ## builtinShadow [ **style** **opinionated** ] Detects when predeclared identifiers are shadowed in assignments. **Before:** ```go len := 10 ``` **After:** ```go length := 10 ``` ## builtinShadowDecl [ **diagnostic** **experimental** ] Detects top-level declarations that shadow the predeclared identifiers. **Before:** ```go type int struct {} ``` **After:** ```go type myInt struct {} ``` ## captLocal [ **style** ] Detects capitalized names for local variables. **Before:** ```go func f(IN int, OUT *int) (ERR error) {} ``` **After:** ```go func f(in int, out *int) (err error) {} ``` Checker parameters: ## caseOrder [ **diagnostic** ] Detects erroneous case order inside switch statements. **Before:** ```go switch x.(type) { case ast.Expr: fmt.Println("expr") case *ast.BasicLit: fmt.Println("basic lit") // Never executed } ``` **After:** ```go switch x.(type) { case *ast.BasicLit: fmt.Println("basic lit") // Now reachable case ast.Expr: fmt.Println("expr") } ``` ## codegenComment [ **diagnostic** ] Detects malformed 'code generated' file comments. **Before:** ```go // This file was automatically generated by foogen ``` **After:** ```go // Code generated by foogen. DO NOT EDIT. ``` ## commentFormatting [ **style** ] Detects comments with non-idiomatic formatting. **Before:** ```go //This is a comment ``` **After:** ```go // This is a comment ``` ## commentedOutCode [ **diagnostic** **experimental** ] Detects commented-out code inside function bodies. **Before:** ```go // fmt.Println("Debugging hard") foo(1, 2) ``` **After:** ```go foo(1, 2) ``` Checker parameters: ## commentedOutImport [ **style** **experimental** ] Detects commented-out imports. **Before:** ```go import ( "fmt" //"os" ) ``` **After:** ```go import ( "fmt" ) ``` ## defaultCaseOrder [ **style** ] Detects when default case in switch isn't on 1st or last position. **Before:** ```go switch { case x > y: // ... default: // <- not the best position // ... case x == 10: // ... } ``` **After:** ```go switch { case x > y: // ... case x == 10: // ... default: // <- last case (could also be the first one) // ... } ``` ## deferInLoop [ **diagnostic** **experimental** ] Detects loops inside functions that use defer. **Before:** ```go for _, filename := range []string{"foo", "bar"} { f, err := os.Open(filename) defer f.Close() } ``` **After:** ```go func process(filename string) { f, err := os.Open(filename) defer f.Close() } /* ... */ for _, filename := range []string{"foo", "bar"} { process(filename) } ``` ## deferUnlambda [ **style** **experimental** ] Detects deferred function literals that can be simplified. **Before:** ```go defer func() { f() }() ``` **After:** ```go defer f() ``` ## deprecatedComment [ **diagnostic** ] Detects malformed 'deprecated' doc-comments. **Before:** ```go // deprecated, use FuncNew instead func FuncOld() int ``` **After:** ```go // Deprecated: use FuncNew instead func FuncOld() int ``` ## docStub [ **style** **experimental** ] Detects comments that silence go lint complaints about doc-comment. **Before:** ```go // Foo ... func Foo() { } ``` **After:** ```go // (A) - remove the doc-comment stub func Foo() {} // (B) - replace it with meaningful comment // Foo is a demonstration-only function. func Foo() {} ``` ## dupArg [ **diagnostic** ] Detects suspicious duplicated arguments. **Before:** ```go copy(dst, dst) ``` **After:** ```go copy(dst, src) ``` ## dupBranchBody [ **diagnostic** ] Detects duplicated branch bodies inside conditional statements. **Before:** ```go if cond { println("cond=true") } else { println("cond=true") } ``` **After:** ```go if cond { println("cond=true") } else { println("cond=false") } ``` ## dupCase [ **diagnostic** ] Detects duplicated case clauses inside switch or select statements. **Before:** ```go switch x { case ys[0], ys[1], ys[2], ys[0], ys[4]: } ``` **After:** ```go switch x { case ys[0], ys[1], ys[2], ys[3], ys[4]: } ``` ## dupImport [ **style** **experimental** ] Detects multiple imports of the same package under different aliases. **Before:** ```go import ( "fmt" printing "fmt" // Imported the second time ) ``` **After:** ```go import( "fmt" ) ``` ## dupOption [ **diagnostic** **experimental** ] Detects duplicated option function arguments in variadic function calls. **Before:** ```go doSomething(name, withWidth(w), withHeight(h), withWidth(w), ) ``` **After:** ```go doSomething(name, withWidth(w), withHeight(h), ) ``` ## dupSubExpr [ **diagnostic** ] Detects suspicious duplicated sub-expressions. **Before:** ```go sort.Slice(xs, func(i, j int) bool { return xs[i].v < xs[i].v // Duplicated index }) ``` **After:** ```go sort.Slice(xs, func(i, j int) bool { return xs[i].v < xs[j].v }) ``` ## dynamicFmtString [ **diagnostic** **experimental** ] Detects suspicious formatting strings usage. **Before:** ```go fmt.Errorf(msg) ``` **After:** ```go errors.New(msg) or fmt.Errorf("%s", msg) ``` ## elseif [ **style** ] Detects else with nested if statement that can be replaced with else-if. **Before:** ```go if cond1 { } else { if x := cond2; x { } } ``` **After:** ```go if cond1 { } else if x := cond2; x { } ``` Checker parameters: ## emptyDecl [ **diagnostic** **experimental** ] Detects suspicious empty declarations blocks. **Before:** ```go var() ``` **After:** ```go /* nothing */ ``` ## emptyFallthrough [ **style** **experimental** ] Detects fallthrough that can be avoided by using multi case values. **Before:** ```go switch kind { case reflect.Int: fallthrough case reflect.Int32: return Int } ``` **After:** ```go switch kind { case reflect.Int, reflect.Int32: return Int } ``` ## emptyStringTest [ **style** **experimental** ] Detects empty string checks that can be written more idiomatically. **Before:** ```go len(s) == 0 ``` **After:** ```go s == "" ``` ## equalFold [ **performance** **experimental** ] Detects unoptimal strings/bytes case-insensitive comparison. **Before:** ```go strings.ToLower(x) == strings.ToLower(y) ``` **After:** ```go strings.EqualFold(x, y) ``` ## evalOrder [ **diagnostic** **experimental** ] Detects unwanted dependencies on the evaluation order. **Before:** ```go return x, f(&x) ``` **After:** ```go err := f(&x) return x, err ``` ## exitAfterDefer [ **diagnostic** ] Detects calls to exit/fatal inside functions that use defer. **Before:** ```go defer os.Remove(filename) if bad { log.Fatalf("something bad happened") } ``` **After:** ```go defer os.Remove(filename) if bad { log.Printf("something bad happened") return } ``` ## exposedSyncMutex [ **style** **experimental** ] Detects exposed methods from sync.Mutex and sync.RWMutex. **Before:** ```go type Foo struct{ ...; sync.Mutex; ... } ``` **After:** ```go type Foo struct{ ...; mu sync.Mutex; ... } ``` ## externalErrorReassign [ **diagnostic** **experimental** ] Detects suspicious reassignment of error from another package. **Before:** ```go io.EOF = nil ``` **After:** ```go /* don't do it */ ``` ## filepathJoin [ **diagnostic** **experimental** ] Detects problems in filepath.Join() function calls. **Before:** ```go filepath.Join("dir/", filename) ``` **After:** ```go filepath.Join("dir", filename) ``` ## flagDeref [ **diagnostic** ] Detects immediate dereferencing of `flag` package pointers. **Before:** ```go b := *flag.Bool("b", false, "b docs") ``` **After:** ```go var b bool; flag.BoolVar(&b, "b", false, "b docs") ``` ## flagName [ **diagnostic** ] Detects suspicious flag names. > https://github.com/golang/go/issues/41792 **Before:** ```go b := flag.Bool(" foo ", false, "description") ``` **After:** ```go b := flag.Bool("foo", false, "description") ``` ## hexLiteral [ **style** **experimental** ] Detects hex literals that have mixed case letter digits. **Before:** ```go x := 0X12 y := 0xfF ``` **After:** ```go x := 0x12 // (A) y := 0xff // (B) y := 0xFF ``` ## httpNoBody [ **style** **experimental** ] Detects nil usages in http.NewRequest calls, suggesting http.NoBody as an alternative. **Before:** ```go http.NewRequest("GET", url, nil) ``` **After:** ```go http.NewRequest("GET", url, http.NoBody) ``` ## hugeParam [ **performance** ] Detects params that incur excessive amount of copying. **Before:** ```go func f(x [1024]int) {} ``` **After:** ```go func f(x *[1024]int) {} ``` Checker parameters: ## ifElseChain [ **style** ] 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. See [EffectiveGo#switch](https://golang.org/doc/effective_go.html#switch). **Before:** ```go if cond1 { // Code A. } else if cond2 { // Code B. } else { // Code C. } ``` **After:** ```go switch { case cond1: // Code A. case cond2: // Code B. default: // Code C. } ``` Checker parameters: ## importShadow [ **style** **opinionated** ] Detects when imported package names shadowed in the assignments. **Before:** ```go // "path/filepath" is imported. filepath := "foo.txt" ``` **After:** ```go filename := "foo.txt" ``` ## indexAlloc [ **performance** ] Detects strings.Index calls that may cause unwanted allocs. > See Go issue for details: https://github.com/golang/go/issues/25864 **Before:** ```go strings.Index(string(x), y) ``` **After:** ```go bytes.Index(x, []byte(y)) ``` ## initClause [ **style** **opinionated** **experimental** ] Detects non-assignment statements inside if/switch init clause. **Before:** ```go if sideEffect(); cond { } ``` **After:** ```go sideEffect() if cond { } ``` ## mapKey [ **diagnostic** ] Detects suspicious map literal keys. **Before:** ```go _ = map[string]int{ "foo": 1, "bar ": 2, } ``` **After:** ```go _ = map[string]int{ "foo": 1, "bar": 2, } ``` ## methodExprCall [ **style** **experimental** ] Detects method expression call that can be replaced with a method call. **Before:** ```go f := foo{} foo.bar(f) ``` **After:** ```go f := foo{} f.bar() ``` ## nestingReduce [ **style** **opinionated** **experimental** ] Finds where nesting level could be reduced. **Before:** ```go for _, v := range a { if v.Bool { body() } } ``` **After:** ```go for _, v := range a { if !v.Bool { continue } body() } ``` Checker parameters: ## newDeref [ **style** ] Detects immediate dereferencing of `new` expressions. **Before:** ```go x := *new(bool) ``` **After:** ```go x := false ``` ## nilValReturn [ **diagnostic** **experimental** ] Detects return statements those results evaluate to nil. **Before:** ```go if err == nil { return err } ``` **After:** ```go // (A) - return nil explicitly if err == nil { return nil } // (B) - typo in "==", change to "!=" if err != nil { return err } ``` ## octalLiteral [ **style** **experimental** **opinionated** ] Detects old-style octal literals. **Before:** ```go foo(02) ``` **After:** ```go foo(0o2) ``` ## offBy1 [ **diagnostic** ] Detects various off-by-one kind of errors. **Before:** ```go xs[len(xs)] ``` **After:** ```go xs[len(xs)-1] ``` ## paramTypeCombine [ **style** **opinionated** ] Detects if function parameters could be combined by type and suggest the way to do it. **Before:** ```go func foo(a, b int, c, d int, e, f int, g int) {} ``` **After:** ```go func foo(a, b, c, d, e, f, g int) {} ``` ## preferDecodeRune [ **performance** **experimental** ] Detects expressions like []rune(s)[0] that may cause unwanted rune slice allocation. > See Go issue for details: https://github.com/golang/go/issues/45260 **Before:** ```go r := []rune(s)[0] ``` **After:** ```go r, _ := utf8.DecodeRuneInString(s) ``` ## preferFilepathJoin [ **style** **experimental** ] Detects concatenation with os.PathSeparator which can be replaced with filepath.Join. **Before:** ```go x + string(os.PathSeparator) + y ``` **After:** ```go filepath.Join(x, y) ``` ## preferFprint [ **performance** **experimental** ] Detects fmt.Sprint(f/ln) calls which can be replaced with fmt.Fprint(f/ln). **Before:** ```go w.Write([]byte(fmt.Sprintf("%x", 10))) ``` **After:** ```go fmt.Fprintf(w, "%x", 10) ``` ## preferStringWriter [ **performance** **experimental** ] Detects w.Write or io.WriteString calls which can be replaced with w.WriteString. **Before:** ```go w.Write([]byte("foo")) ``` **After:** ```go w.WriteString("foo") ``` ## preferWriteByte [ **performance** **experimental** **opinionated** ] Detects WriteRune calls with rune literal argument that is single byte and reports to use WriteByte instead. **Before:** ```go w.WriteRune('\n') ``` **After:** ```go w.WriteByte('\n') ``` ## ptrToRefParam [ **style** **opinionated** **experimental** ] Detects input and output parameters that have a type of pointer to referential type. **Before:** ```go func f(m *map[string]int) (*chan *int) ``` **After:** ```go func f(m map[string]int) (chan *int) ``` ## rangeAppendAll [ **diagnostic** **experimental** ] Detects append all its data while range it. **Before:** ```go for _, n := range ns { ... rs = append(rs, ns...) // append all slice data } } ``` **After:** ```go for _, n := range ns { ... rs = append(rs, n) } } ``` ## rangeExprCopy [ **performance** ] Detects expensive copies of `for` loop range expressions. Suggests to use pointer to array to avoid the copy using `&` on range expression. > See Go issue for details: https://github.com/golang/go/issues/15812. **Before:** ```go var xs [2048]byte for _, x := range xs { // Copies 2048 bytes // Loop body. } ``` **After:** ```go var xs [2048]byte for _, x := range &xs { // No copy // Loop body. } ``` Checker parameters: ## rangeValCopy [ **performance** ] Detects loops that copy big objects during each iteration. Suggests to use index access or take address and make use pointer instead. **Before:** ```go xs := make([][1024]byte, length) for _, x := range xs { // Loop body. } ``` **After:** ```go xs := make([][1024]byte, length) for i := range xs { x := &xs[i] // Loop body. } ``` Checker parameters: ## redundantSprint [ **style** **experimental** ] Detects redundant fmt.Sprint calls. **Before:** ```go fmt.Sprint(x) ``` **After:** ```go x.String() ``` ## regexpMust [ **style** ] Detects `regexp.Compile*` that can be replaced with `regexp.MustCompile*`. **Before:** ```go re, _ := regexp.Compile("const pattern") ``` **After:** ```go re := regexp.MustCompile("const pattern") ``` ## regexpPattern [ **diagnostic** **experimental** ] Detects suspicious regexp patterns. **Before:** ```go regexp.MustCompile(`google.com|yandex.ru`) ``` **After:** ```go regexp.MustCompile(`google\.com|yandex\.ru`) ``` ## regexpSimplify [ **style** **experimental** **opinionated** ] Detects regexp patterns that can be simplified. **Before:** ```go regexp.MustCompile(`(?:a|b|c) [a-z][a-z]*`) ``` **After:** ```go regexp.MustCompile(`[abc] {3}[a-z]+`) ``` ## returnAfterHttpError [ **diagnostic** **experimental** ] Detects suspicious http.Error call without following return. **Before:** ```go if err != nil { http.Error(...); } ``` **After:** ```go if err != nil { http.Error(...); return; } ``` ## ruleguard [ **style** **experimental** ] Runs user-defined rules using ruleguard linter. Reads a rules file and turns them into go-critic checkers. > See https://github.com/quasilyte/go-ruleguard. **Before:** ```go N/A ``` **After:** ```go N/A ``` Checker parameters: ## singleCaseSwitch [ **style** ] Detects switch statements that could be better written as if statement. **Before:** ```go switch x := x.(type) { case int: body() } ``` **After:** ```go if x, ok := x.(int); ok { body() } ``` ## sliceClear [ **performance** **experimental** ] Detects slice clear loops, suggests an idiom that is recognized by the Go compiler. **Before:** ```go for i := 0; i < len(buf); i++ { buf[i] = 0 } ``` **After:** ```go for i := range buf { buf[i] = 0 } ``` ## sloppyLen [ **diagnostic** ] Detects usage of `len` when result is obvious or doesn't make sense. **Before:** ```go len(arr) <= 0 ``` **After:** ```go len(arr) == 0 ``` ## sloppyReassign [ **diagnostic** **experimental** ] Detects suspicious/confusing re-assignments. **Before:** ```go if err = f(); err != nil { return err } ``` **After:** ```go if err := f(); err != nil { return err } ``` ## sloppyTypeAssert [ **diagnostic** ] Detects redundant type assertions. **Before:** ```go func f(r io.Reader) interface{} { return r.(interface{}) } ``` **After:** ```go func f(r io.Reader) interface{} { return r } ``` ## sortSlice [ **diagnostic** **experimental** ] Detects suspicious sort.Slice calls. **Before:** ```go sort.Slice(xs, func(i, j) bool { return keys[i] < keys[j] }) ``` **After:** ```go sort.Slice(kv, func(i, j) bool { return kv[i].key < kv[j].key }) ``` ## sprintfQuotedString [ **diagnostic** **experimental** ] Detects "%s" formatting directives that can be replaced with %q. **Before:** ```go fmt.Sprintf(`"%s"`, s) ``` **After:** ```go fmt.Sprintf(`%q`, s) ``` ## sqlQuery [ **diagnostic** **experimental** ] Detects issue in Query() and Exec() calls. **Before:** ```go _, err := db.Query("UPDATE ...") ``` **After:** ```go _, err := db.Exec("UPDATE ...") ``` ## stringConcatSimplify [ **style** **experimental** ] Detects string concat operations that can be simplified. **Before:** ```go strings.Join([]string{x, y}, "_") ``` **After:** ```go x + "_" + y ``` ## stringXbytes [ **performance** ] Detects redundant conversions between string and []byte. **Before:** ```go copy(b, []byte(s)) ``` **After:** ```go copy(b, s) ``` ## stringsCompare [ **style** **experimental** ] Detects strings.Compare usage. **Before:** ```go strings.Compare(x, y) ``` **After:** ```go x < y ``` ## switchTrue [ **style** ] Detects switch-over-bool statements that use explicit `true` tag value. **Before:** ```go switch true {...} ``` **After:** ```go switch {...} ``` ## syncMapLoadAndDelete [ **diagnostic** **experimental** ] Detects sync.Map load+delete operations that can be replaced with LoadAndDelete. **Before:** ```go v, ok := m.Load(k); if ok { m.Delete($k); f(v); } ``` **After:** ```go v, deleted := m.LoadAndDelete(k); if deleted { f(v) } ``` ## timeExprSimplify [ **style** **experimental** ] Detects manual conversion to milli- or microseconds. **Before:** ```go t.Unix() / 1000 ``` **After:** ```go t.UnixMilli() ``` ## todoCommentWithoutDetail [ **style** **opinionated** **experimental** ] Detects TODO comments without detail/assignee. **Before:** ```go // TODO fiiWithCtx(nil, a, b) ``` **After:** ```go // TODO(admin): pass context.TODO() instead of nil fiiWithCtx(nil, a, b) ``` ## tooManyResultsChecker [ **style** **opinionated** **experimental** ] Detects function with too many results. **Before:** ```go func fn() (a, b, c, d float32, _ int, _ bool) ``` **After:** ```go func fn() (resultStruct, bool) ``` Checker parameters: ## truncateCmp [ **diagnostic** **experimental** ] Detects potential truncation issues when comparing ints of different sizes. **Before:** ```go func f(x int32, y int16) bool { return int16(x) < y } ``` **After:** ```go func f(x int32, int16) bool { return x < int32(y) } ``` Checker parameters: ## typeAssertChain [ **style** **experimental** ] Detects repeated type assertions and suggests to replace them with type switch statement. **Before:** ```go if x, ok := v.(T1); ok { // Code A, uses x. } else if x, ok := v.(T2); ok { // Code B, uses x. } else if x, ok := v.(T3); ok { // Code C, uses x. } ``` **After:** ```go switch x := v.(T1) { case cond1: // Code A, uses x. case cond2: // Code B, uses x. default: // Code C, uses x. } ``` ## typeDefFirst [ **style** **experimental** ] Detects method declarations preceding the type definition itself. **Before:** ```go func (r rec) Method() {} type rec struct{} ``` **After:** ```go type rec struct{} func (r rec) Method() {} ``` ## typeSwitchVar [ **style** ] Detects type switches that can benefit from type guard clause with variable. **Before:** ```go switch v.(type) { case int: return v.(int) case point: return v.(point).x + v.(point).y default: return 0 } ``` **After:** ```go switch v := v.(type) { case int: return v case point: return v.x + v.y default: return 0 } ``` ## typeUnparen [ **style** **opinionated** ] Detects unneeded parenthesis inside type expressions and suggests to remove them. **Before:** ```go type foo [](func([](func()))) ``` **After:** ```go type foo []func([]func()) ``` ## uncheckedInlineErr [ **diagnostic** **experimental** ] Detects unchecked errors in if statements. **Before:** ```go if err := expr(); err2 != nil { /*...*/ } ``` **After:** ```go if err := expr(); err != nil { /*...*/ } ``` ## underef [ **style** ] Detects dereference expressions that can be omitted. **Before:** ```go (*k).field = 5 v := (*a)[5] // only if a is array ``` **After:** ```go k.field = 5 v := a[5] ``` Checker parameters: ## unlabelStmt [ **style** **experimental** ] Detects redundant statement labels. **Before:** ```go derp: for x := range xs { if x == 0 { break derp } } ``` **After:** ```go for x := range xs { if x == 0 { break } } ``` ## unlambda [ **style** ] Detects function literals that can be simplified. **Before:** ```go func(x int) int { return fn(x) } ``` **After:** ```go fn ``` ## unnamedResult [ **style** **opinionated** **experimental** ] Detects unnamed results that may benefit from names. **Before:** ```go func f() (float64, float64) ``` **After:** ```go func f() (x, y float64) ``` Checker parameters: ## unnecessaryBlock [ **style** **opinionated** **experimental** ] Detects unnecessary braced statement blocks. **Before:** ```go x := 1 { print(x) } ``` **After:** ```go x := 1 print(x) ``` ## unnecessaryDefer [ **diagnostic** **experimental** ] Detects redundantly deferred calls. **Before:** ```go func() { defer os.Remove(filename) } ``` **After:** ```go func() { os.Remove(filename) } ``` ## unslice [ **style** ] Detects slice expressions that can be simplified to sliced expression itself. **Before:** ```go copy(b[:], values...) ``` **After:** ```go copy(b, values...) ``` ## valSwap [ **style** ] Detects value swapping code that are not using parallel assignment. **Before:** ```go *tmp = *x; *x = *y; *y = *tmp ``` **After:** ```go *x, *y = *y, *x ``` ## weakCond [ **diagnostic** **experimental** ] Detects conditions that are unsafe due to not being exhaustive. **Before:** ```go xs != nil && xs[0] != nil ``` **After:** ```go len(xs) != 0 && xs[0] != nil ``` ## whyNoLint [ **style** **experimental** ] Ensures that `//nolint` comments include an explanation. **Before:** ```go //nolint ``` **After:** ```go //nolint // reason ``` ## wrapperFunc [ **style** ] Detects function calls that can be replaced with convenience wrappers. **Before:** ```go wg.Add(-1) ``` **After:** ```go wg.Done() ``` ## yodaStyleExpr [ **style** **experimental** ] Detects Yoda style expressions and suggests to replace them. **Before:** ```go return nil != ptr ``` **After:** ```go return ptr != nil ``` ## zeroByteRepeat [ **performance** ] Detects bytes.Repeat with 0 value. **Before:** ```go bytes.Repeat([]byte{0}, x) ``` **After:** ```go make([]byte, x) ```