honnef.co/go/tools@v0.4.7/staticcheck/doc.go (about)

     1  // Package staticcheck contains analyzes that find bugs and performance issues.
     2  // Barring the rare false positive, any code flagged by these analyzes needs to be fixed.
     3  package staticcheck
     4  
     5  import "honnef.co/go/tools/analysis/lint"
     6  
     7  var Docs = lint.Markdownify(map[string]*lint.RawDocumentation{
     8  	"SA1000": {
     9  		Title:    `Invalid regular expression`,
    10  		Since:    "2017.1",
    11  		Severity: lint.SeverityError,
    12  		MergeIf:  lint.MergeIfAny,
    13  	},
    14  
    15  	"SA1001": {
    16  		Title:    `Invalid template`,
    17  		Since:    "2017.1",
    18  		Severity: lint.SeverityError,
    19  		MergeIf:  lint.MergeIfAny,
    20  	},
    21  
    22  	"SA1002": {
    23  		Title:    `Invalid format in \'time.Parse\'`,
    24  		Since:    "2017.1",
    25  		Severity: lint.SeverityError,
    26  		MergeIf:  lint.MergeIfAny,
    27  	},
    28  
    29  	"SA1003": {
    30  		Title: `Unsupported argument to functions in \'encoding/binary\'`,
    31  		Text: `The \'encoding/binary\' package can only serialize types with known sizes.
    32  This precludes the use of the \'int\' and \'uint\' types, as their sizes
    33  differ on different architectures. Furthermore, it doesn't support
    34  serializing maps, channels, strings, or functions.
    35  
    36  Before Go 1.8, \'bool\' wasn't supported, either.`,
    37  		Since:    "2017.1",
    38  		Severity: lint.SeverityError,
    39  		MergeIf:  lint.MergeIfAny,
    40  	},
    41  
    42  	"SA1004": {
    43  		Title: `Suspiciously small untyped constant in \'time.Sleep\'`,
    44  		Text: `The \'time\'.Sleep function takes a \'time.Duration\' as its only argument.
    45  Durations are expressed in nanoseconds. Thus, calling \'time.Sleep(1)\'
    46  will sleep for 1 nanosecond. This is a common source of bugs, as sleep
    47  functions in other languages often accept seconds or milliseconds.
    48  
    49  The \'time\' package provides constants such as \'time.Second\' to express
    50  large durations. These can be combined with arithmetic to express
    51  arbitrary durations, for example \'5 * time.Second\' for 5 seconds.
    52  
    53  If you truly meant to sleep for a tiny amount of time, use
    54  \'n * time.Nanosecond\' to signal to Staticcheck that you did mean to sleep
    55  for some amount of nanoseconds.`,
    56  		Since:    "2017.1",
    57  		Severity: lint.SeverityWarning,
    58  		MergeIf:  lint.MergeIfAny,
    59  	},
    60  
    61  	"SA1005": {
    62  		Title: `Invalid first argument to \'exec.Command\'`,
    63  		Text: `\'os/exec\' runs programs directly (using variants of the fork and exec
    64  system calls on Unix systems). This shouldn't be confused with running
    65  a command in a shell. The shell will allow for features such as input
    66  redirection, pipes, and general scripting. The shell is also
    67  responsible for splitting the user's input into a program name and its
    68  arguments. For example, the equivalent to
    69  
    70      ls / /tmp
    71  
    72  would be
    73  
    74      exec.Command("ls", "/", "/tmp")
    75  
    76  If you want to run a command in a shell, consider using something like
    77  the following – but be aware that not all systems, particularly
    78  Windows, will have a \'/bin/sh\' program:
    79  
    80      exec.Command("/bin/sh", "-c", "ls | grep Awesome")`,
    81  		Since:    "2017.1",
    82  		Severity: lint.SeverityWarning,
    83  		MergeIf:  lint.MergeIfAny,
    84  	},
    85  
    86  	"SA1006": {
    87  		Title: `\'Printf\' with dynamic first argument and no further arguments`,
    88  		Text: `Using \'fmt.Printf\' with a dynamic first argument can lead to unexpected
    89  output. The first argument is a format string, where certain character
    90  combinations have special meaning. If, for example, a user were to
    91  enter a string such as
    92  
    93      Interest rate: 5%
    94  
    95  and you printed it with
    96  
    97      fmt.Printf(s)
    98  
    99  it would lead to the following output:
   100  
   101      Interest rate: 5%!(NOVERB).
   102  
   103  Similarly, forming the first parameter via string concatenation with
   104  user input should be avoided for the same reason. When printing user
   105  input, either use a variant of \'fmt.Print\', or use the \'%s\' Printf verb
   106  and pass the string as an argument.`,
   107  		Since:    "2017.1",
   108  		Severity: lint.SeverityWarning,
   109  		MergeIf:  lint.MergeIfAny,
   110  	},
   111  
   112  	"SA1007": {
   113  		Title:    `Invalid URL in \'net/url.Parse\'`,
   114  		Since:    "2017.1",
   115  		Severity: lint.SeverityError,
   116  		MergeIf:  lint.MergeIfAny,
   117  	},
   118  
   119  	"SA1008": {
   120  		Title: `Non-canonical key in \'http.Header\' map`,
   121  		Text: `Keys in \'http.Header\' maps are canonical, meaning they follow a specific
   122  combination of uppercase and lowercase letters. Methods such as
   123  \'http.Header.Add\' and \'http.Header.Del\' convert inputs into this canonical
   124  form before manipulating the map.
   125  
   126  When manipulating \'http.Header\' maps directly, as opposed to using the
   127  provided methods, care should be taken to stick to canonical form in
   128  order to avoid inconsistencies. The following piece of code
   129  demonstrates one such inconsistency:
   130  
   131      h := http.Header{}
   132      h["etag"] = []string{"1234"}
   133      h.Add("etag", "5678")
   134      fmt.Println(h)
   135  
   136      // Output:
   137      // map[Etag:[5678] etag:[1234]]
   138  
   139  The easiest way of obtaining the canonical form of a key is to use
   140  \'http.CanonicalHeaderKey\'.`,
   141  		Since:    "2017.1",
   142  		Severity: lint.SeverityWarning,
   143  		MergeIf:  lint.MergeIfAny,
   144  	},
   145  
   146  	"SA1010": {
   147  		Title: `\'(*regexp.Regexp).FindAll\' called with \'n == 0\', which will always return zero results`,
   148  		Text: `If \'n >= 0\', the function returns at most \'n\' matches/submatches. To
   149  return all results, specify a negative number.`,
   150  		Since:    "2017.1",
   151  		Severity: lint.SeverityWarning,
   152  		MergeIf:  lint.MergeIfAny, // MergeIfAny if we only flag literals, not named constants
   153  	},
   154  
   155  	"SA1011": {
   156  		Title:    `Various methods in the \"strings\" package expect valid UTF-8, but invalid input is provided`,
   157  		Since:    "2017.1",
   158  		Severity: lint.SeverityError,
   159  		MergeIf:  lint.MergeIfAny,
   160  	},
   161  
   162  	"SA1012": {
   163  		Title:    `A nil \'context.Context\' is being passed to a function, consider using \'context.TODO\' instead`,
   164  		Since:    "2017.1",
   165  		Severity: lint.SeverityWarning,
   166  		MergeIf:  lint.MergeIfAny,
   167  	},
   168  
   169  	"SA1013": {
   170  		Title:    `\'io.Seeker.Seek\' is being called with the whence constant as the first argument, but it should be the second`,
   171  		Since:    "2017.1",
   172  		Severity: lint.SeverityWarning,
   173  		MergeIf:  lint.MergeIfAny,
   174  	},
   175  
   176  	"SA1014": {
   177  		Title:    `Non-pointer value passed to \'Unmarshal\' or \'Decode\'`,
   178  		Since:    "2017.1",
   179  		Severity: lint.SeverityError,
   180  		MergeIf:  lint.MergeIfAny,
   181  	},
   182  
   183  	"SA1015": {
   184  		Title:    `Using \'time.Tick\' in a way that will leak. Consider using \'time.NewTicker\', and only use \'time.Tick\' in tests, commands and endless functions`,
   185  		Since:    "2017.1",
   186  		Severity: lint.SeverityWarning,
   187  		MergeIf:  lint.MergeIfAny,
   188  	},
   189  
   190  	"SA1016": {
   191  		Title: `Trapping a signal that cannot be trapped`,
   192  		Text: `Not all signals can be intercepted by a process. Specifically, on
   193  UNIX-like systems, the \'syscall.SIGKILL\' and \'syscall.SIGSTOP\' signals are
   194  never passed to the process, but instead handled directly by the
   195  kernel. It is therefore pointless to try and handle these signals.`,
   196  		Since:    "2017.1",
   197  		Severity: lint.SeverityWarning,
   198  		MergeIf:  lint.MergeIfAny,
   199  	},
   200  
   201  	"SA1017": {
   202  		Title: `Channels used with \'os/signal.Notify\' should be buffered`,
   203  		Text: `The \'os/signal\' package uses non-blocking channel sends when delivering
   204  signals. If the receiving end of the channel isn't ready and the
   205  channel is either unbuffered or full, the signal will be dropped. To
   206  avoid missing signals, the channel should be buffered and of the
   207  appropriate size. For a channel used for notification of just one
   208  signal value, a buffer of size 1 is sufficient.`,
   209  		Since:    "2017.1",
   210  		Severity: lint.SeverityWarning,
   211  		MergeIf:  lint.MergeIfAny,
   212  	},
   213  
   214  	"SA1018": {
   215  		Title: `\'strings.Replace\' called with \'n == 0\', which does nothing`,
   216  		Text: `With \'n == 0\', zero instances will be replaced. To replace all
   217  instances, use a negative number, or use \'strings.ReplaceAll\'.`,
   218  		Since:    "2017.1",
   219  		Severity: lint.SeverityWarning,
   220  		MergeIf:  lint.MergeIfAny, // MergeIfAny if we only flag literals, not named constants
   221  	},
   222  
   223  	"SA1019": {
   224  		Title:    `Using a deprecated function, variable, constant or field`,
   225  		Since:    "2017.1",
   226  		Severity: lint.SeverityDeprecated,
   227  		MergeIf:  lint.MergeIfAny,
   228  	},
   229  
   230  	"SA1020": {
   231  		Title:    `Using an invalid host:port pair with a \'net.Listen\'-related function`,
   232  		Since:    "2017.1",
   233  		Severity: lint.SeverityError,
   234  		MergeIf:  lint.MergeIfAny,
   235  	},
   236  
   237  	"SA1021": {
   238  		Title: `Using \'bytes.Equal\' to compare two \'net.IP\'`,
   239  		Text: `A \'net.IP\' stores an IPv4 or IPv6 address as a slice of bytes. The
   240  length of the slice for an IPv4 address, however, can be either 4 or
   241  16 bytes long, using different ways of representing IPv4 addresses. In
   242  order to correctly compare two \'net.IP\'s, the \'net.IP.Equal\' method should
   243  be used, as it takes both representations into account.`,
   244  		Since:    "2017.1",
   245  		Severity: lint.SeverityWarning,
   246  		MergeIf:  lint.MergeIfAny,
   247  	},
   248  
   249  	"SA1023": {
   250  		Title:    `Modifying the buffer in an \'io.Writer\' implementation`,
   251  		Text:     `\'Write\' must not modify the slice data, even temporarily.`,
   252  		Since:    "2017.1",
   253  		Severity: lint.SeverityError,
   254  		MergeIf:  lint.MergeIfAny,
   255  	},
   256  
   257  	"SA1024": {
   258  		Title: `A string cutset contains duplicate characters`,
   259  		Text: `The \'strings.TrimLeft\' and \'strings.TrimRight\' functions take cutsets, not
   260  prefixes. A cutset is treated as a set of characters to remove from a
   261  string. For example,
   262  
   263      strings.TrimLeft("42133word", "1234")
   264  
   265  will result in the string \'"word"\' – any characters that are 1, 2, 3 or
   266  4 are cut from the left of the string.
   267  
   268  In order to remove one string from another, use \'strings.TrimPrefix\' instead.`,
   269  		Since:    "2017.1",
   270  		Severity: lint.SeverityWarning,
   271  		MergeIf:  lint.MergeIfAny,
   272  	},
   273  
   274  	"SA1025": {
   275  		Title:    `It is not possible to use \'(*time.Timer).Reset\''s return value correctly`,
   276  		Since:    "2019.1",
   277  		Severity: lint.SeverityWarning,
   278  		MergeIf:  lint.MergeIfAny,
   279  	},
   280  
   281  	"SA1026": {
   282  		Title:    `Cannot marshal channels or functions`,
   283  		Since:    "2019.2",
   284  		Severity: lint.SeverityError,
   285  		MergeIf:  lint.MergeIfAny,
   286  	},
   287  
   288  	"SA1027": {
   289  		Title: `Atomic access to 64-bit variable must be 64-bit aligned`,
   290  		Text: `On ARM, x86-32, and 32-bit MIPS, it is the caller's responsibility to
   291  arrange for 64-bit alignment of 64-bit words accessed atomically. The
   292  first word in a variable or in an allocated struct, array, or slice
   293  can be relied upon to be 64-bit aligned.
   294  
   295  You can use the structlayout tool to inspect the alignment of fields
   296  in a struct.`,
   297  		Since:    "2019.2",
   298  		Severity: lint.SeverityWarning,
   299  		MergeIf:  lint.MergeIfAny,
   300  	},
   301  
   302  	"SA1028": {
   303  		Title:    `\'sort.Slice\' can only be used on slices`,
   304  		Text:     `The first argument of \'sort.Slice\' must be a slice.`,
   305  		Since:    "2020.1",
   306  		Severity: lint.SeverityError,
   307  		MergeIf:  lint.MergeIfAny,
   308  	},
   309  
   310  	"SA1029": {
   311  		Title: `Inappropriate key in call to \'context.WithValue\'`,
   312  		Text: `The provided key must be comparable and should not be
   313  of type \'string\' or any other built-in type to avoid collisions between
   314  packages using context. Users of \'WithValue\' should define their own
   315  types for keys.
   316  
   317  To avoid allocating when assigning to an \'interface{}\',
   318  context keys often have concrete type \'struct{}\'. Alternatively,
   319  exported context key variables' static type should be a pointer or
   320  interface.`,
   321  		Since:    "2020.1",
   322  		Severity: lint.SeverityWarning,
   323  		MergeIf:  lint.MergeIfAny,
   324  	},
   325  
   326  	"SA1030": {
   327  		Title: `Invalid argument in call to a \'strconv\' function`,
   328  		Text: `This check validates the format, number base and bit size arguments of
   329  the various parsing and formatting functions in \'strconv\'.`,
   330  		Since:    "2021.1",
   331  		Severity: lint.SeverityError,
   332  		MergeIf:  lint.MergeIfAny,
   333  	},
   334  
   335  	"SA2000": {
   336  		Title:    `\'sync.WaitGroup.Add\' called inside the goroutine, leading to a race condition`,
   337  		Since:    "2017.1",
   338  		Severity: lint.SeverityWarning,
   339  		MergeIf:  lint.MergeIfAny,
   340  	},
   341  
   342  	"SA2001": {
   343  		Title: `Empty critical section, did you mean to defer the unlock?`,
   344  		Text: `Empty critical sections of the kind
   345  
   346      mu.Lock()
   347      mu.Unlock()
   348  
   349  are very often a typo, and the following was intended instead:
   350  
   351      mu.Lock()
   352      defer mu.Unlock()
   353  
   354  Do note that sometimes empty critical sections can be useful, as a
   355  form of signaling to wait on another goroutine. Many times, there are
   356  simpler ways of achieving the same effect. When that isn't the case,
   357  the code should be amply commented to avoid confusion. Combining such
   358  comments with a \'//lint:ignore\' directive can be used to suppress this
   359  rare false positive.`,
   360  		Since:    "2017.1",
   361  		Severity: lint.SeverityWarning,
   362  		MergeIf:  lint.MergeIfAny,
   363  	},
   364  
   365  	"SA2002": {
   366  		Title:    `Called \'testing.T.FailNow\' or \'SkipNow\' in a goroutine, which isn't allowed`,
   367  		Since:    "2017.1",
   368  		Severity: lint.SeverityError,
   369  		MergeIf:  lint.MergeIfAny,
   370  	},
   371  
   372  	"SA2003": {
   373  		Title:    `Deferred \'Lock\' right after locking, likely meant to defer \'Unlock\' instead`,
   374  		Since:    "2017.1",
   375  		Severity: lint.SeverityWarning,
   376  		MergeIf:  lint.MergeIfAny,
   377  	},
   378  
   379  	"SA3000": {
   380  		Title: `\'TestMain\' doesn't call \'os.Exit\', hiding test failures`,
   381  		Text: `Test executables (and in turn \"go test\") exit with a non-zero status
   382  code if any tests failed. When specifying your own \'TestMain\' function,
   383  it is your responsibility to arrange for this, by calling \'os.Exit\' with
   384  the correct code. The correct code is returned by \'(*testing.M).Run\', so
   385  the usual way of implementing \'TestMain\' is to end it with
   386  \'os.Exit(m.Run())\'.`,
   387  		Since:    "2017.1",
   388  		Severity: lint.SeverityWarning,
   389  		MergeIf:  lint.MergeIfAny,
   390  	},
   391  
   392  	"SA3001": {
   393  		Title: `Assigning to \'b.N\' in benchmarks distorts the results`,
   394  		Text: `The testing package dynamically sets \'b.N\' to improve the reliability of
   395  benchmarks and uses it in computations to determine the duration of a
   396  single operation. Benchmark code must not alter \'b.N\' as this would
   397  falsify results.`,
   398  		Since:    "2017.1",
   399  		Severity: lint.SeverityError,
   400  		MergeIf:  lint.MergeIfAny,
   401  	},
   402  
   403  	"SA4000": {
   404  		Title:    `Binary operator has identical expressions on both sides`,
   405  		Since:    "2017.1",
   406  		Severity: lint.SeverityWarning,
   407  		MergeIf:  lint.MergeIfAny,
   408  	},
   409  
   410  	"SA4001": {
   411  		Title:    `\'&*x\' gets simplified to \'x\', it does not copy \'x\'`,
   412  		Since:    "2017.1",
   413  		Severity: lint.SeverityWarning,
   414  		MergeIf:  lint.MergeIfAny,
   415  	},
   416  
   417  	"SA4003": {
   418  		Title:    `Comparing unsigned values against negative values is pointless`,
   419  		Since:    "2017.1",
   420  		Severity: lint.SeverityWarning,
   421  		MergeIf:  lint.MergeIfAll,
   422  	},
   423  
   424  	"SA4004": {
   425  		Title:    `The loop exits unconditionally after one iteration`,
   426  		Since:    "2017.1",
   427  		Severity: lint.SeverityWarning,
   428  		MergeIf:  lint.MergeIfAll,
   429  	},
   430  
   431  	"SA4005": {
   432  		Title:    `Field assignment that will never be observed. Did you mean to use a pointer receiver?`,
   433  		Since:    "2021.1",
   434  		Severity: lint.SeverityWarning,
   435  		MergeIf:  lint.MergeIfAny,
   436  	},
   437  
   438  	"SA4006": {
   439  		Title:    `A value assigned to a variable is never read before being overwritten. Forgotten error check or dead code?`,
   440  		Since:    "2017.1",
   441  		Severity: lint.SeverityWarning,
   442  		MergeIf:  lint.MergeIfAll,
   443  	},
   444  
   445  	"SA4008": {
   446  		Title:    `The variable in the loop condition never changes, are you incrementing the wrong variable?`,
   447  		Since:    "2017.1",
   448  		Severity: lint.SeverityWarning,
   449  		MergeIf:  lint.MergeIfAll,
   450  	},
   451  
   452  	"SA4009": {
   453  		Title:    `A function argument is overwritten before its first use`,
   454  		Since:    "2017.1",
   455  		Severity: lint.SeverityWarning,
   456  		MergeIf:  lint.MergeIfAny,
   457  	},
   458  
   459  	"SA4010": {
   460  		Title:    `The result of \'append\' will never be observed anywhere`,
   461  		Since:    "2017.1",
   462  		Severity: lint.SeverityWarning,
   463  		MergeIf:  lint.MergeIfAll,
   464  	},
   465  
   466  	"SA4011": {
   467  		Title:    `Break statement with no effect. Did you mean to break out of an outer loop?`,
   468  		Since:    "2017.1",
   469  		Severity: lint.SeverityWarning,
   470  		MergeIf:  lint.MergeIfAny,
   471  	},
   472  
   473  	"SA4012": {
   474  		Title:    `Comparing a value against NaN even though no value is equal to NaN`,
   475  		Since:    "2017.1",
   476  		Severity: lint.SeverityWarning,
   477  		MergeIf:  lint.MergeIfAny,
   478  	},
   479  
   480  	"SA4013": {
   481  		Title:    `Negating a boolean twice (\'!!b\') is the same as writing \'b\'. This is either redundant, or a typo.`,
   482  		Since:    "2017.1",
   483  		Severity: lint.SeverityWarning,
   484  		MergeIf:  lint.MergeIfAny,
   485  	},
   486  
   487  	"SA4014": {
   488  		Title:    `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`,
   489  		Since:    "2017.1",
   490  		Severity: lint.SeverityWarning,
   491  		MergeIf:  lint.MergeIfAll,
   492  	},
   493  
   494  	"SA4015": {
   495  		Title:    `Calling functions like \'math.Ceil\' on floats converted from integers doesn't do anything useful`,
   496  		Since:    "2017.1",
   497  		Severity: lint.SeverityWarning,
   498  		MergeIf:  lint.MergeIfAll,
   499  	},
   500  
   501  	"SA4016": {
   502  		Title:    `Certain bitwise operations, such as \'x ^ 0\', do not do anything useful`,
   503  		Since:    "2017.1",
   504  		Severity: lint.SeverityWarning,
   505  		MergeIf:  lint.MergeIfAny, // MergeIfAny if we only flag literals, not named constants
   506  	},
   507  
   508  	"SA4017": {
   509  		Title:    `Discarding the return values of a function without side effects, making the call pointless`,
   510  		Since:    "2017.1",
   511  		Severity: lint.SeverityWarning,
   512  		MergeIf:  lint.MergeIfAll,
   513  	},
   514  
   515  	"SA4018": {
   516  		Title:    `Self-assignment of variables`,
   517  		Since:    "2017.1",
   518  		Severity: lint.SeverityWarning,
   519  		MergeIf:  lint.MergeIfAny,
   520  	},
   521  
   522  	"SA4019": {
   523  		Title:    `Multiple, identical build constraints in the same file`,
   524  		Since:    "2017.1",
   525  		Severity: lint.SeverityWarning,
   526  		MergeIf:  lint.MergeIfAny,
   527  	},
   528  
   529  	"SA4020": {
   530  		Title: `Unreachable case clause in a type switch`,
   531  		Text: `In a type switch like the following
   532  
   533      type T struct{}
   534      func (T) Read(b []byte) (int, error) { return 0, nil }
   535  
   536      var v interface{} = T{}
   537  
   538      switch v.(type) {
   539      case io.Reader:
   540          // ...
   541      case T:
   542          // unreachable
   543      }
   544  
   545  the second case clause can never be reached because \'T\' implements
   546  \'io.Reader\' and case clauses are evaluated in source order.
   547  
   548  Another example:
   549  
   550      type T struct{}
   551      func (T) Read(b []byte) (int, error) { return 0, nil }
   552      func (T) Close() error { return nil }
   553  
   554      var v interface{} = T{}
   555  
   556      switch v.(type) {
   557      case io.Reader:
   558          // ...
   559      case io.ReadCloser:
   560          // unreachable
   561      }
   562  
   563  Even though \'T\' has a \'Close\' method and thus implements \'io.ReadCloser\',
   564  \'io.Reader\' will always match first. The method set of \'io.Reader\' is a
   565  subset of \'io.ReadCloser\'. Thus it is impossible to match the second
   566  case without matching the first case.
   567  
   568  
   569  Structurally equivalent interfaces
   570  
   571  A special case of the previous example are structurally identical
   572  interfaces. Given these declarations
   573  
   574      type T error
   575      type V error
   576  
   577      func doSomething() error {
   578          err, ok := doAnotherThing()
   579          if ok {
   580              return T(err)
   581          }
   582  
   583          return U(err)
   584      }
   585  
   586  the following type switch will have an unreachable case clause:
   587  
   588      switch doSomething().(type) {
   589      case T:
   590          // ...
   591      case V:
   592          // unreachable
   593      }
   594  
   595  \'T\' will always match before V because they are structurally equivalent
   596  and therefore \'doSomething()\''s return value implements both.`,
   597  		Since:    "2019.2",
   598  		Severity: lint.SeverityWarning,
   599  		MergeIf:  lint.MergeIfAll,
   600  	},
   601  
   602  	"SA4021": {
   603  		Title:    `\"x = append(y)\" is equivalent to \"x = y\"`,
   604  		Since:    "2019.2",
   605  		Severity: lint.SeverityWarning,
   606  		MergeIf:  lint.MergeIfAny,
   607  	},
   608  
   609  	"SA4022": {
   610  		Title:    `Comparing the address of a variable against nil`,
   611  		Text:     `Code such as \"if &x == nil\" is meaningless, because taking the address of a variable always yields a non-nil pointer.`,
   612  		Since:    "2020.1",
   613  		Severity: lint.SeverityWarning,
   614  		MergeIf:  lint.MergeIfAny,
   615  	},
   616  
   617  	"SA4023": {
   618  		Title: `Impossible comparison of interface value with untyped nil`,
   619  		Text: `Under the covers, interfaces are implemented as two elements, a
   620  type T and a value V. V is a concrete value such as an int,
   621  struct or pointer, never an interface itself, and has type T. For
   622  instance, if we store the int value 3 in an interface, the
   623  resulting interface value has, schematically, (T=int, V=3). The
   624  value V is also known as the interface's dynamic value, since a
   625  given interface variable might hold different values V (and
   626  corresponding types T) during the execution of the program.
   627  
   628  An interface value is nil only if the V and T are both
   629  unset, (T=nil, V is not set), In particular, a nil interface will
   630  always hold a nil type. If we store a nil pointer of type *int
   631  inside an interface value, the inner type will be *int regardless
   632  of the value of the pointer: (T=*int, V=nil). Such an interface
   633  value will therefore be non-nil even when the pointer value V
   634  inside is nil.
   635  
   636  This situation can be confusing, and arises when a nil value is
   637  stored inside an interface value such as an error return:
   638  
   639      func returnsError() error {
   640          var p *MyError = nil
   641          if bad() {
   642              p = ErrBad
   643          }
   644          return p // Will always return a non-nil error.
   645      }
   646  
   647  If all goes well, the function returns a nil p, so the return
   648  value is an error interface value holding (T=*MyError, V=nil).
   649  This means that if the caller compares the returned error to nil,
   650  it will always look as if there was an error even if nothing bad
   651  happened. To return a proper nil error to the caller, the
   652  function must return an explicit nil:
   653  
   654      func returnsError() error {
   655          if bad() {
   656              return ErrBad
   657          }
   658          return nil
   659      }
   660  
   661  It's a good idea for functions that return errors always to use
   662  the error type in their signature (as we did above) rather than a
   663  concrete type such as \'*MyError\', to help guarantee the error is
   664  created correctly. As an example, \'os.Open\' returns an error even
   665  though, if not nil, it's always of concrete type *os.PathError.
   666  
   667  Similar situations to those described here can arise whenever
   668  interfaces are used. Just keep in mind that if any concrete value
   669  has been stored in the interface, the interface will not be nil.
   670  For more information, see The Laws of
   671  Reflection (https://golang.org/doc/articles/laws_of_reflection.html).
   672  
   673  This text has been copied from
   674  https://golang.org/doc/faq#nil_error, licensed under the Creative
   675  Commons Attribution 3.0 License.`,
   676  		Since:    "2020.2",
   677  		Severity: lint.SeverityWarning,
   678  		MergeIf:  lint.MergeIfAny, // TODO should this be MergeIfAll?
   679  	},
   680  
   681  	"SA4024": {
   682  		Title: `Checking for impossible return value from a builtin function`,
   683  		Text: `Return values of the \'len\' and \'cap\' builtins cannot be negative.
   684  
   685  See https://golang.org/pkg/builtin/#len and https://golang.org/pkg/builtin/#cap.
   686  
   687  Example:
   688  
   689      if len(slice) < 0 {
   690          fmt.Println("unreachable code")
   691      }`,
   692  		Since:    "2021.1",
   693  		Severity: lint.SeverityWarning,
   694  		MergeIf:  lint.MergeIfAny,
   695  	},
   696  
   697  	"SA4025": {
   698  		Title: "Integer division of literals that results in zero",
   699  		Text: `When dividing two integer constants, the result will
   700  also be an integer. Thus, a division such as \'2 / 3\' results in \'0\'.
   701  This is true for all of the following examples:
   702  
   703  	_ = 2 / 3
   704  	const _ = 2 / 3
   705  	const _ float64 = 2 / 3
   706  	_ = float64(2 / 3)
   707  
   708  Staticcheck will flag such divisions if both sides of the division are
   709  integer literals, as it is highly unlikely that the division was
   710  intended to truncate to zero. Staticcheck will not flag integer
   711  division involving named constants, to avoid noisy positives.
   712  `,
   713  		Since:    "2021.1",
   714  		Severity: lint.SeverityWarning,
   715  		MergeIf:  lint.MergeIfAny,
   716  	},
   717  
   718  	"SA4026": {
   719  		Title: "Go constants cannot express negative zero",
   720  		Text: `In IEEE 754 floating point math, zero has a sign and can be positive
   721  or negative. This can be useful in certain numerical code.
   722  
   723  Go constants, however, cannot express negative zero. This means that
   724  the literals \'-0.0\' and \'0.0\' have the same ideal value (zero) and
   725  will both represent positive zero at runtime.
   726  
   727  To explicitly and reliably create a negative zero, you can use the
   728  \'math.Copysign\' function: \'math.Copysign(0, -1)\'.`,
   729  		Since:    "2021.1",
   730  		Severity: lint.SeverityWarning,
   731  		MergeIf:  lint.MergeIfAny,
   732  	},
   733  
   734  	"SA4027": {
   735  		Title: `\'(*net/url.URL).Query\' returns a copy, modifying it doesn't change the URL`,
   736  		Text: `\'(*net/url.URL).Query\' parses the current value of \'net/url.URL.RawQuery\'
   737  and returns it as a map of type \'net/url.Values\'. Subsequent changes to
   738  this map will not affect the URL unless the map gets encoded and
   739  assigned to the URL's \'RawQuery\'.
   740  
   741  As a consequence, the following code pattern is an expensive no-op:
   742  \'u.Query().Add(key, value)\'.`,
   743  		Since:    "2021.1",
   744  		Severity: lint.SeverityWarning,
   745  		MergeIf:  lint.MergeIfAny,
   746  	},
   747  
   748  	"SA4028": {
   749  		Title:    `\'x % 1\' is always zero`,
   750  		Since:    "2022.1",
   751  		Severity: lint.SeverityWarning,
   752  		MergeIf:  lint.MergeIfAny, // MergeIfAny if we only flag literals, not named constants
   753  	},
   754  
   755  	"SA4029": {
   756  		Title: "Ineffective attempt at sorting slice",
   757  		Text: `
   758  \'sort.Float64Slice\', \'sort.IntSlice\', and \'sort.StringSlice\' are
   759  types, not functions. Doing \'x = sort.StringSlice(x)\' does nothing,
   760  especially not sort any values. The correct usage is
   761  \'sort.Sort(sort.StringSlice(x))\' or \'sort.StringSlice(x).Sort()\',
   762  but there are more convenient helpers, namely \'sort.Float64s\',
   763  \'sort.Ints\', and \'sort.Strings\'.
   764  `,
   765  		Since:    "2022.1",
   766  		Severity: lint.SeverityWarning,
   767  		MergeIf:  lint.MergeIfAny,
   768  	},
   769  
   770  	"SA4030": {
   771  		Title: "Ineffective attempt at generating random number",
   772  		Text: `
   773  Functions in the \'math/rand\' package that accept upper limits, such
   774  as \'Intn\', generate random numbers in the half-open interval [0,n). In
   775  other words, the generated numbers will be \'>= 0\' and \'< n\' – they
   776  don't include \'n\'. \'rand.Intn(1)\' therefore doesn't generate \'0\'
   777  or \'1\', it always generates \'0\'.`,
   778  		Since:    "2022.1",
   779  		Severity: lint.SeverityWarning,
   780  		MergeIf:  lint.MergeIfAny,
   781  	},
   782  
   783  	"SA4031": {
   784  		Title:    `Checking never-nil value against nil`,
   785  		Since:    "2022.1",
   786  		Severity: lint.SeverityWarning,
   787  		MergeIf:  lint.MergeIfAny,
   788  	},
   789  
   790  	"SA5000": {
   791  		Title:    `Assignment to nil map`,
   792  		Since:    "2017.1",
   793  		Severity: lint.SeverityError,
   794  		MergeIf:  lint.MergeIfAny,
   795  	},
   796  
   797  	"SA5001": {
   798  		Title:    `Deferring \'Close\' before checking for a possible error`,
   799  		Since:    "2017.1",
   800  		Severity: lint.SeverityWarning,
   801  		MergeIf:  lint.MergeIfAny,
   802  	},
   803  
   804  	"SA5002": {
   805  		Title:    `The empty for loop (\"for {}\") spins and can block the scheduler`,
   806  		Since:    "2017.1",
   807  		Severity: lint.SeverityWarning,
   808  		MergeIf:  lint.MergeIfAny,
   809  	},
   810  
   811  	"SA5003": {
   812  		Title: `Defers in infinite loops will never execute`,
   813  		Text: `Defers are scoped to the surrounding function, not the surrounding
   814  block. In a function that never returns, i.e. one containing an
   815  infinite loop, defers will never execute.`,
   816  		Since:    "2017.1",
   817  		Severity: lint.SeverityWarning,
   818  		MergeIf:  lint.MergeIfAny,
   819  	},
   820  
   821  	"SA5004": {
   822  		Title:    `\"for { select { ...\" with an empty default branch spins`,
   823  		Since:    "2017.1",
   824  		Severity: lint.SeverityWarning,
   825  		MergeIf:  lint.MergeIfAny,
   826  	},
   827  
   828  	"SA5005": {
   829  		Title: `The finalizer references the finalized object, preventing garbage collection`,
   830  		Text: `A finalizer is a function associated with an object that runs when the
   831  garbage collector is ready to collect said object, that is when the
   832  object is no longer referenced by anything.
   833  
   834  If the finalizer references the object, however, it will always remain
   835  as the final reference to that object, preventing the garbage
   836  collector from collecting the object. The finalizer will never run,
   837  and the object will never be collected, leading to a memory leak. That
   838  is why the finalizer should instead use its first argument to operate
   839  on the object. That way, the number of references can temporarily go
   840  to zero before the object is being passed to the finalizer.`,
   841  		Since:    "2017.1",
   842  		Severity: lint.SeverityWarning,
   843  		MergeIf:  lint.MergeIfAny,
   844  	},
   845  
   846  	"SA5007": {
   847  		Title: `Infinite recursive call`,
   848  		Text: `A function that calls itself recursively needs to have an exit
   849  condition. Otherwise it will recurse forever, until the system runs
   850  out of memory.
   851  
   852  This issue can be caused by simple bugs such as forgetting to add an
   853  exit condition. It can also happen "on purpose". Some languages have
   854  tail call optimization which makes certain infinite recursive calls
   855  safe to use. Go, however, does not implement TCO, and as such a loop
   856  should be used instead.`,
   857  		Since:    "2017.1",
   858  		Severity: lint.SeverityWarning,
   859  		MergeIf:  lint.MergeIfAny,
   860  	},
   861  
   862  	"SA5008": {
   863  		Title:    `Invalid struct tag`,
   864  		Since:    "2019.2",
   865  		Severity: lint.SeverityWarning,
   866  		MergeIf:  lint.MergeIfAny,
   867  	},
   868  
   869  	"SA5009": {
   870  		Title:    `Invalid Printf call`,
   871  		Since:    "2019.2",
   872  		Severity: lint.SeverityError,
   873  		MergeIf:  lint.MergeIfAny,
   874  	},
   875  
   876  	"SA5010": {
   877  		Title: `Impossible type assertion`,
   878  
   879  		Text: `Some type assertions can be statically proven to be
   880  impossible. This is the case when the method sets of both
   881  arguments of the type assertion conflict with each other, for
   882  example by containing the same method with different
   883  signatures.
   884  
   885  The Go compiler already applies this check when asserting from an
   886  interface value to a concrete type. If the concrete type misses
   887  methods from the interface, or if function signatures don't match,
   888  then the type assertion can never succeed.
   889  
   890  This check applies the same logic when asserting from one interface to
   891  another. If both interface types contain the same method but with
   892  different signatures, then the type assertion can never succeed,
   893  either.`,
   894  
   895  		Since:    "2020.1",
   896  		Severity: lint.SeverityWarning,
   897  		// Technically this should be MergeIfAll, but the Go compiler
   898  		// already flags some impossible type assertions, so
   899  		// MergeIfAny is consistent with the compiler.
   900  		MergeIf: lint.MergeIfAny,
   901  	},
   902  
   903  	"SA5011": {
   904  		Title: `Possible nil pointer dereference`,
   905  
   906  		Text: `A pointer is being dereferenced unconditionally, while
   907  also being checked against nil in another place. This suggests that
   908  the pointer may be nil and dereferencing it may panic. This is
   909  commonly a result of improperly ordered code or missing return
   910  statements. Consider the following examples:
   911  
   912      func fn(x *int) {
   913          fmt.Println(*x)
   914  
   915          // This nil check is equally important for the previous dereference
   916          if x != nil {
   917              foo(*x)
   918          }
   919      }
   920  
   921      func TestFoo(t *testing.T) {
   922          x := compute()
   923          if x == nil {
   924              t.Errorf("nil pointer received")
   925          }
   926  
   927          // t.Errorf does not abort the test, so if x is nil, the next line will panic.
   928          foo(*x)
   929      }
   930  
   931  Staticcheck tries to deduce which functions abort control flow.
   932  For example, it is aware that a function will not continue
   933  execution after a call to \'panic\' or \'log.Fatal\'. However, sometimes
   934  this detection fails, in particular in the presence of
   935  conditionals. Consider the following example:
   936  
   937      func Log(msg string, level int) {
   938          fmt.Println(msg)
   939          if level == levelFatal {
   940              os.Exit(1)
   941          }
   942      }
   943  
   944      func Fatal(msg string) {
   945          Log(msg, levelFatal)
   946      }
   947  
   948      func fn(x *int) {
   949          if x == nil {
   950              Fatal("unexpected nil pointer")
   951          }
   952          fmt.Println(*x)
   953      }
   954  
   955  Staticcheck will flag the dereference of \'x\', even though it is perfectly
   956  safe. Staticcheck is not able to deduce that a call to
   957  Fatal will exit the program. For the time being, the easiest
   958  workaround is to modify the definition of Fatal like so:
   959  
   960      func Fatal(msg string) {
   961          Log(msg, levelFatal)
   962          panic("unreachable")
   963      }
   964  
   965  We also hard-code functions from common logging packages such as
   966  logrus. Please file an issue if we're missing support for a
   967  popular package.`,
   968  		Since:    "2020.1",
   969  		Severity: lint.SeverityWarning,
   970  		MergeIf:  lint.MergeIfAny,
   971  	},
   972  
   973  	"SA5012": {
   974  		Title: "Passing odd-sized slice to function expecting even size",
   975  		Text: `Some functions that take slices as parameters expect the slices to have an even number of elements. 
   976  Often, these functions treat elements in a slice as pairs. 
   977  For example, \'strings.NewReplacer\' takes pairs of old and new strings, 
   978  and calling it with an odd number of elements would be an error.`,
   979  		Since:    "2020.2",
   980  		Severity: lint.SeverityError,
   981  		MergeIf:  lint.MergeIfAny,
   982  	},
   983  
   984  	"SA6000": {
   985  		Title:    `Using \'regexp.Match\' or related in a loop, should use \'regexp.Compile\'`,
   986  		Since:    "2017.1",
   987  		Severity: lint.SeverityWarning,
   988  		MergeIf:  lint.MergeIfAny,
   989  	},
   990  
   991  	"SA6001": {
   992  		Title: `Missing an optimization opportunity when indexing maps by byte slices`,
   993  
   994  		Text: `Map keys must be comparable, which precludes the use of byte slices.
   995  This usually leads to using string keys and converting byte slices to
   996  strings.
   997  
   998  Normally, a conversion of a byte slice to a string needs to copy the data and
   999  causes allocations. The compiler, however, recognizes \'m[string(b)]\' and
  1000  uses the data of \'b\' directly, without copying it, because it knows that
  1001  the data can't change during the map lookup. This leads to the
  1002  counter-intuitive situation that
  1003  
  1004      k := string(b)
  1005      println(m[k])
  1006      println(m[k])
  1007  
  1008  will be less efficient than
  1009  
  1010      println(m[string(b)])
  1011      println(m[string(b)])
  1012  
  1013  because the first version needs to copy and allocate, while the second
  1014  one does not.
  1015  
  1016  For some history on this optimization, check out commit
  1017  f5f5a8b6209f84961687d993b93ea0d397f5d5bf in the Go repository.`,
  1018  		Since:    "2017.1",
  1019  		Severity: lint.SeverityWarning,
  1020  		MergeIf:  lint.MergeIfAny,
  1021  	},
  1022  
  1023  	"SA6002": {
  1024  		Title: `Storing non-pointer values in \'sync.Pool\' allocates memory`,
  1025  		Text: `A \'sync.Pool\' is used to avoid unnecessary allocations and reduce the
  1026  amount of work the garbage collector has to do.
  1027  
  1028  When passing a value that is not a pointer to a function that accepts
  1029  an interface, the value needs to be placed on the heap, which means an
  1030  additional allocation. Slices are a common thing to put in sync.Pools,
  1031  and they're structs with 3 fields (length, capacity, and a pointer to
  1032  an array). In order to avoid the extra allocation, one should store a
  1033  pointer to the slice instead.
  1034  
  1035  See the comments on https://go-review.googlesource.com/c/go/+/24371
  1036  that discuss this problem.`,
  1037  		Since:    "2017.1",
  1038  		Severity: lint.SeverityWarning,
  1039  		MergeIf:  lint.MergeIfAny,
  1040  	},
  1041  
  1042  	"SA6003": {
  1043  		Title: `Converting a string to a slice of runes before ranging over it`,
  1044  		Text: `You may want to loop over the runes in a string. Instead of converting
  1045  the string to a slice of runes and looping over that, you can loop
  1046  over the string itself. That is,
  1047  
  1048      for _, r := range s {}
  1049  
  1050  and
  1051  
  1052      for _, r := range []rune(s) {}
  1053  
  1054  will yield the same values. The first version, however, will be faster
  1055  and avoid unnecessary memory allocations.
  1056  
  1057  Do note that if you are interested in the indices, ranging over a
  1058  string and over a slice of runes will yield different indices. The
  1059  first one yields byte offsets, while the second one yields indices in
  1060  the slice of runes.`,
  1061  		Since:    "2017.1",
  1062  		Severity: lint.SeverityWarning,
  1063  		MergeIf:  lint.MergeIfAny,
  1064  	},
  1065  
  1066  	"SA6005": {
  1067  		Title: `Inefficient string comparison with \'strings.ToLower\' or \'strings.ToUpper\'`,
  1068  		Text: `Converting two strings to the same case and comparing them like so
  1069  
  1070      if strings.ToLower(s1) == strings.ToLower(s2) {
  1071          ...
  1072      }
  1073  
  1074  is significantly more expensive than comparing them with
  1075  \'strings.EqualFold(s1, s2)\'. This is due to memory usage as well as
  1076  computational complexity.
  1077  
  1078  \'strings.ToLower\' will have to allocate memory for the new strings, as
  1079  well as convert both strings fully, even if they differ on the very
  1080  first byte. strings.EqualFold, on the other hand, compares the strings
  1081  one character at a time. It doesn't need to create two intermediate
  1082  strings and can return as soon as the first non-matching character has
  1083  been found.
  1084  
  1085  For a more in-depth explanation of this issue, see
  1086  https://blog.digitalocean.com/how-to-efficiently-compare-strings-in-go/`,
  1087  		Since:    "2019.2",
  1088  		Severity: lint.SeverityWarning,
  1089  		MergeIf:  lint.MergeIfAny,
  1090  	},
  1091  
  1092  	"SA9001": {
  1093  		Title:    `Defers in range loops may not run when you expect them to`,
  1094  		Since:    "2017.1",
  1095  		Severity: lint.SeverityWarning,
  1096  		MergeIf:  lint.MergeIfAny,
  1097  	},
  1098  
  1099  	"SA9002": {
  1100  		Title:    `Using a non-octal \'os.FileMode\' that looks like it was meant to be in octal.`,
  1101  		Since:    "2017.1",
  1102  		Severity: lint.SeverityWarning,
  1103  		MergeIf:  lint.MergeIfAny,
  1104  	},
  1105  
  1106  	"SA9003": {
  1107  		Title:    `Empty body in an if or else branch`,
  1108  		Since:    "2017.1",
  1109  		Severity: lint.SeverityWarning,
  1110  		MergeIf:  lint.MergeIfAny,
  1111  	},
  1112  
  1113  	"SA9004": {
  1114  		Title: `Only the first constant has an explicit type`,
  1115  
  1116  		Text: `In a constant declaration such as the following:
  1117  
  1118      const (
  1119          First byte = 1
  1120          Second     = 2
  1121      )
  1122  
  1123  the constant Second does not have the same type as the constant First.
  1124  This construct shouldn't be confused with
  1125  
  1126      const (
  1127          First byte = iota
  1128          Second
  1129      )
  1130  
  1131  where \'First\' and \'Second\' do indeed have the same type. The type is only
  1132  passed on when no explicit value is assigned to the constant.
  1133  
  1134  When declaring enumerations with explicit values it is therefore
  1135  important not to write
  1136  
  1137      const (
  1138            EnumFirst EnumType = 1
  1139            EnumSecond         = 2
  1140            EnumThird          = 3
  1141      )
  1142  
  1143  This discrepancy in types can cause various confusing behaviors and
  1144  bugs.
  1145  
  1146  
  1147  Wrong type in variable declarations
  1148  
  1149  The most obvious issue with such incorrect enumerations expresses
  1150  itself as a compile error:
  1151  
  1152      package pkg
  1153  
  1154      const (
  1155          EnumFirst  uint8 = 1
  1156          EnumSecond       = 2
  1157      )
  1158  
  1159      func fn(useFirst bool) {
  1160          x := EnumSecond
  1161          if useFirst {
  1162              x = EnumFirst
  1163          }
  1164      }
  1165  
  1166  fails to compile with
  1167  
  1168      ./const.go:11:5: cannot use EnumFirst (type uint8) as type int in assignment
  1169  
  1170  
  1171  Losing method sets
  1172  
  1173  A more subtle issue occurs with types that have methods and optional
  1174  interfaces. Consider the following:
  1175  
  1176      package main
  1177  
  1178      import "fmt"
  1179  
  1180      type Enum int
  1181  
  1182      func (e Enum) String() string {
  1183          return "an enum"
  1184      }
  1185  
  1186      const (
  1187          EnumFirst  Enum = 1
  1188          EnumSecond      = 2
  1189      )
  1190  
  1191      func main() {
  1192          fmt.Println(EnumFirst)
  1193          fmt.Println(EnumSecond)
  1194      }
  1195  
  1196  This code will output
  1197  
  1198      an enum
  1199      2
  1200  
  1201  as \'EnumSecond\' has no explicit type, and thus defaults to \'int\'.`,
  1202  		Since:    "2019.1",
  1203  		Severity: lint.SeverityWarning,
  1204  		MergeIf:  lint.MergeIfAny,
  1205  	},
  1206  
  1207  	"SA9005": {
  1208  		Title: `Trying to marshal a struct with no public fields nor custom marshaling`,
  1209  		Text: `
  1210  The \'encoding/json\' and \'encoding/xml\' packages only operate on exported
  1211  fields in structs, not unexported ones. It is usually an error to try
  1212  to (un)marshal structs that only consist of unexported fields.
  1213  
  1214  This check will not flag calls involving types that define custom
  1215  marshaling behavior, e.g. via \'MarshalJSON\' methods. It will also not
  1216  flag empty structs.`,
  1217  		Since:    "2019.2",
  1218  		Severity: lint.SeverityWarning,
  1219  		MergeIf:  lint.MergeIfAll,
  1220  	},
  1221  
  1222  	"SA9006": {
  1223  		Title: `Dubious bit shifting of a fixed size integer value`,
  1224  		Text: `Bit shifting a value past its size will always clear the value.
  1225  
  1226  For instance:
  1227  
  1228      v := int8(42)
  1229      v >>= 8
  1230  
  1231  will always result in 0.
  1232  
  1233  This check flags bit shifting operations on fixed size integer values only.
  1234  That is, int, uint and uintptr are never flagged to avoid potential false
  1235  positives in somewhat exotic but valid bit twiddling tricks:
  1236  
  1237      // Clear any value above 32 bits if integers are more than 32 bits.
  1238      func f(i int) int {
  1239          v := i >> 32
  1240          v = v << 32
  1241          return i-v
  1242      }`,
  1243  		Since:    "2020.2",
  1244  		Severity: lint.SeverityWarning,
  1245  		// Technically this should be MergeIfAll, because the type of
  1246  		// v might be different for different build tags. Practically,
  1247  		// don't write code that depends on that.
  1248  		MergeIf: lint.MergeIfAny,
  1249  	},
  1250  
  1251  	"SA9007": {
  1252  		Title: "Deleting a directory that shouldn't be deleted",
  1253  		Text: `
  1254  It is virtually never correct to delete system directories such as
  1255  /tmp or the user's home directory. However, it can be fairly easy to
  1256  do by mistake, for example by mistakingly using \'os.TempDir\' instead
  1257  of \'ioutil.TempDir\', or by forgetting to add a suffix to the result
  1258  of \'os.UserHomeDir\'.
  1259  
  1260  Writing
  1261  
  1262      d := os.TempDir()
  1263      defer os.RemoveAll(d)
  1264  
  1265  in your unit tests will have a devastating effect on the stability of your system.
  1266  
  1267  This check flags attempts at deleting the following directories:
  1268  
  1269  - os.TempDir
  1270  - os.UserCacheDir
  1271  - os.UserConfigDir
  1272  - os.UserHomeDir
  1273  `,
  1274  		Since:    "2022.1",
  1275  		Severity: lint.SeverityWarning,
  1276  		MergeIf:  lint.MergeIfAny,
  1277  	},
  1278  
  1279  	"SA9008": {
  1280  		Title: `\'else\' branch of a type assertion is probably not reading the right value`,
  1281  		Text: `
  1282  When declaring variables as part of an \'if\' statement (like in \"if
  1283  foo := ...; foo {\"), the same variables will also be in the scope of
  1284  the \'else\' branch. This means that in the following example
  1285  
  1286      if x, ok := x.(int); ok {
  1287          // ...
  1288      } else {
  1289          fmt.Printf("unexpected type %T", x)
  1290      }
  1291  
  1292  \'x\' in the \'else\' branch will refer to the \'x\' from \'x, ok
  1293  :=\'; it will not refer to the \'x\' that is being type-asserted. The
  1294  result of a failed type assertion is the zero value of the type that
  1295  is being asserted to, so \'x\' in the else branch will always have the
  1296  value \'0\' and the type \'int\'.
  1297  `,
  1298  		Since:    "2022.1",
  1299  		Severity: lint.SeverityWarning,
  1300  		MergeIf:  lint.MergeIfAny,
  1301  	},
  1302  })