Source file src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go

     1  // Copyright 2024 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  /*
     6  Package modernize provides a suite of analyzers that suggest
     7  simplifications to Go code, using modern language and library
     8  features.
     9  
    10  Each diagnostic provides a fix. Our intent is that these fixes may
    11  be safely applied en masse without changing the behavior of your
    12  program. In some cases the suggested fixes are imperfect and may
    13  lead to (for example) unused imports or unused local variables,
    14  causing build breakage. However, these problems are generally
    15  trivial to fix. We regard any modernizer whose fix changes program
    16  behavior to have a serious bug and will endeavor to fix it.
    17  
    18  To apply all modernization fixes en masse, you can use the
    19  following command:
    20  
    21  	$ go run golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest -fix ./...
    22  
    23  (Do not use "go get -tool" to add gopls as a dependency of your
    24  module; gopls commands must be built from their release branch.)
    25  
    26  If the tool warns of conflicting fixes, you may need to run it more
    27  than once until it has applied all fixes cleanly. This command is
    28  not an officially supported interface and may change in the future.
    29  
    30  Changes produced by this tool should be reviewed as usual before
    31  being merged. In some cases, a loop may be replaced by a simple
    32  function call, causing comments within the loop to be discarded.
    33  Human judgment may be required to avoid losing comments of value.
    34  
    35  The modernize suite contains many analyzers. Diagnostics from some,
    36  such as "any" (which replaces "interface{}" with "any" where it
    37  is safe to do so), are particularly numerous. It may ease the burden of
    38  code review to apply fixes in two steps, the first consisting only of
    39  fixes from the "any" analyzer, the second consisting of all
    40  other analyzers. This can be achieved using flags, as in this example:
    41  
    42  	$ modernize -any=true  -fix ./...
    43  	$ modernize -any=false -fix ./...
    44  
    45  # Analyzer appendclipped
    46  
    47  appendclipped: simplify append chains using slices.Concat
    48  
    49  The appendclipped analyzer suggests replacing chains of append calls with a
    50  single call to slices.Concat, which was added in Go 1.21. For example,
    51  append(append(s, s1...), s2...) would be simplified to slices.Concat(s, s1, s2).
    52  
    53  In the simple case of appending to a newly allocated slice, such as
    54  append([]T(nil), s...), the analyzer suggests the more concise slices.Clone(s).
    55  For byte slices, it will prefer bytes.Clone if the "bytes" package is
    56  already imported.
    57  
    58  This fix is only applied when the base of the append tower is a
    59  "clipped" slice, meaning its length and capacity are equal (e.g.
    60  x[:0:0] or []T{}). This is to avoid changing program behavior by
    61  eliminating intended side effects on the base slice's underlying
    62  array.
    63  
    64  This analyzer is currently disabled by default as the
    65  transformation does not preserve the nilness of the base slice in
    66  all cases; see https://go.dev/issue/73557.
    67  
    68  # Analyzer atomictypes
    69  
    70  atomictypes: replace basic types in sync/atomic calls with atomic types
    71  
    72  The atomictypes analyzer suggests replacing the primitive sync/atomic functions with
    73  the strongly typed atomic wrapper types introduced in Go1.19 (e.g.
    74  atomic.Int32). For example,
    75  
    76  	var x int32
    77  	atomic.AddInt32(&x, 1)
    78  
    79  would become
    80  
    81  	var x atomic.Int32
    82  	x.Add(1)
    83  
    84  The atomic types are safer because they don't allow non-atomic access, which is
    85  a common source of bugs. These types also resolve memory alignment issues that
    86  plagued the old atomic functions on 32-bit architectures.
    87  
    88  # Analyzer bloop
    89  
    90  bloop: replace for-range over b.N with b.Loop
    91  
    92  The bloop analyzer suggests replacing benchmark loops of the form
    93  `for i := 0; i < b.N; i++` or `for range b.N` with the more modern
    94  `for b.Loop()`, which was added in Go 1.24.
    95  
    96  This change makes benchmark code more readable and also removes the need for
    97  manual timer control, so any preceding calls to b.StartTimer, b.StopTimer,
    98  or b.ResetTimer within the same function will also be removed.
    99  
   100  Caveats: The b.Loop() method is designed to prevent the compiler from
   101  optimizing away the benchmark loop, which can occasionally result in
   102  slower execution due to increased allocations in some specific cases.
   103  Since its fix may change the performance of nanosecond-scale benchmarks,
   104  bloop is disabled by default in the `go fix` analyzer suite; see golang/go#74967.
   105  
   106  # Analyzer any
   107  
   108  any: replace interface{} with any
   109  
   110  The any analyzer suggests replacing uses of the empty interface type,
   111  `interface{}`, with the `any` alias, which was introduced in Go 1.18.
   112  This is a purely stylistic change that makes code more readable.
   113  
   114  # Analyzer embedlit
   115  
   116  embedlit: simplify references to embedded fields in composite literals
   117  
   118  The embedlit analyzer suggests removing redundant embedded field type specifiers
   119  from composite literals. Go1.27 introduced the ability to directly initialize
   120  fields promoted from embedded struct types without a nested literal. For
   121  example, given the following structs:
   122  
   123  	type T struct {
   124  		U
   125  	}
   126  
   127  	type U struct {
   128  		x int
   129  	}
   130  
   131  A composite literal such as
   132  
   133  	t := T{U: U{x: 1}}
   134  
   135  would become
   136  
   137  	t := T{x: 1}
   138  
   139  # Analyzer errorsastype
   140  
   141  errorsastype: replace errors.As with errors.AsType[T]
   142  
   143  This analyzer suggests fixes to simplify uses of [errors.As] of
   144  this form:
   145  
   146  	var myerr *MyErr
   147  	if errors.As(err, &myerr) {
   148  		handle(myerr)
   149  	}
   150  
   151  by using the less error-prone generic [errors.AsType] function,
   152  introduced in Go 1.26:
   153  
   154  	if myerr, ok := errors.AsType[*MyErr](err); ok {
   155  		handle(myerr)
   156  	}
   157  
   158  The fix is only offered if the var declaration has the form shown and
   159  there are no uses of myerr outside the if statement.
   160  
   161  # Analyzer fmtappendf
   162  
   163  fmtappendf: replace []byte(fmt.Sprintf) with fmt.Appendf
   164  
   165  The fmtappendf analyzer suggests replacing `[]byte(fmt.Sprintf(...))` with
   166  `fmt.Appendf(nil, ...)`. This avoids the intermediate allocation of a string
   167  by Sprintf, making the code more efficient. The suggestion also applies to
   168  fmt.Sprint and fmt.Sprintln.
   169  
   170  Since its fix is not a Pareto improvement, fmtappendf is disabled by default in
   171  the `go fix` analyzer suite; see golang/go#77581.
   172  
   173  # Analyzer forvar
   174  
   175  forvar: remove redundant re-declaration of loop variables
   176  
   177  The forvar analyzer removes unnecessary shadowing of loop variables.
   178  Before Go 1.22, it was common to write `for _, x := range s { x := x ... }`
   179  to create a fresh variable for each iteration. Go 1.22 changed the semantics
   180  of `for` loops, making this pattern redundant. This analyzer removes the
   181  unnecessary `x := x` statement.
   182  
   183  This fix only applies to `range` loops.
   184  
   185  # Analyzer mapsloop
   186  
   187  mapsloop: replace explicit loops over maps with calls to maps package
   188  
   189  The mapsloop analyzer replaces loops of the form
   190  
   191  	for k, v := range x { m[k] = v }
   192  
   193  with a single call to a function from the `maps` package, added in Go 1.23.
   194  Depending on the context, this could be `maps.Copy`, `maps.Insert`,
   195  `maps.Clone`, or `maps.Collect`.
   196  
   197  The transformation to `maps.Clone` is applied conservatively, as it
   198  preserves the nilness of the source map, which may be a subtle change in
   199  behavior if the original code did not handle a nil map in the same way.
   200  
   201  # Analyzer minmax
   202  
   203  minmax: replace if/else statements with calls to min or max
   204  
   205  The minmax analyzer simplifies conditional assignments by suggesting the use
   206  of the built-in `min` and `max` functions, introduced in Go 1.21. For example,
   207  
   208  	if a < b { x = a } else { x = b }
   209  
   210  is replaced by
   211  
   212  	x = min(a, b).
   213  
   214  This analyzer avoids making suggestions for floating-point types,
   215  as the behavior of `min` and `max` with NaN values can differ from
   216  the original if/else statement.
   217  
   218  # Analyzer newexpr
   219  
   220  newexpr: simplify code by using go1.26's new(expr)
   221  
   222  This analyzer finds declarations of functions of this form:
   223  
   224  	func varOf(x int) *int { return &x }
   225  
   226  and suggests a fix to turn them into inlinable wrappers around
   227  go1.26's built-in new(expr) function:
   228  
   229  	//go:fix inline
   230  	func varOf(x int) *int { return new(x) }
   231  
   232  (The directive comment causes the 'inline' analyzer to suggest
   233  that calls to such functions are inlined.)
   234  
   235  In addition, this analyzer suggests a fix for each call
   236  to one of the functions before it is transformed, so that
   237  
   238  	use(varOf(123))
   239  
   240  is replaced by:
   241  
   242  	use(new(123))
   243  
   244  Wrapper functions such as varOf are common when working with Go
   245  serialization packages such as for JSON or protobuf, where pointers
   246  are often used to express optionality.
   247  
   248  # Analyzer omitzero
   249  
   250  omitzero: suggest replacing omitempty with omitzero for struct fields
   251  
   252  The omitzero analyzer identifies uses of the `omitempty` JSON struct
   253  tag on fields that are themselves structs. For struct-typed fields,
   254  the `omitempty` tag has no effect on the behavior of json.Marshal and
   255  json.Unmarshal. The analyzer offers two suggestions: either remove the
   256  tag, or replace it with `omitzero` (added in Go 1.24), which correctly
   257  omits the field if the struct value is zero.
   258  
   259  However, some other serialization packages (notably kubebuilder, see
   260  https://book.kubebuilder.io/reference/markers.html) may have their own
   261  interpretation of the `json:",omitzero"` tag, so removing it may affect
   262  program behavior. For this reason, the omitzero modernizer will not
   263  make changes in any package that contains +kubebuilder annotations.
   264  
   265  Replacing `omitempty` with `omitzero` is a change in behavior. The
   266  original code would always encode the struct field, whereas the
   267  modified code will omit it if it is a zero-value.
   268  
   269  # Analyzer plusbuild
   270  
   271  plusbuild: remove obsolete //+build comments
   272  
   273  The plusbuild analyzer suggests a fix to remove obsolete build tags
   274  of the form:
   275  
   276  	//+build linux,amd64
   277  
   278  in files that also contain a Go 1.18-style tag such as:
   279  
   280  	//go:build linux && amd64
   281  
   282  (It does not check that the old and new tags are consistent;
   283  that is the job of the 'buildtag' analyzer in the vet suite.)
   284  
   285  # Analyzer rangeint
   286  
   287  rangeint: replace 3-clause for loops with for-range over integers
   288  
   289  The rangeint analyzer suggests replacing traditional for loops such
   290  as
   291  
   292  	for i := 0; i < n; i++ { ... }
   293  
   294  with the more idiomatic Go 1.22 style:
   295  
   296  	for i := range n { ... }
   297  
   298  This transformation is applied only if (a) the loop variable is not
   299  modified within the loop body and (b) the loop's limit expression
   300  is not modified within the loop, as `for range` evaluates its
   301  operand only once.
   302  
   303  # Analyzer reflecttypefor
   304  
   305  reflecttypefor: replace reflect.TypeOf(x) with TypeFor[T]()
   306  
   307  This analyzer suggests fixes to replace uses of reflect.TypeOf(x) with
   308  reflect.TypeFor, introduced in go1.22, when the desired runtime type
   309  is known at compile time, for example:
   310  
   311  	reflect.TypeOf(uint32(0))        -> reflect.TypeFor[uint32]()
   312  	reflect.TypeOf((*ast.File)(nil)) -> reflect.TypeFor[*ast.File]()
   313  
   314  It also offers a fix to simplify the constructions below, which use
   315  reflect.TypeOf to return the runtime type for an interface type,
   316  
   317  	reflect.TypeOf((*io.Reader)(nil)).Elem()
   318  
   319  or:
   320  
   321  	reflect.TypeOf([]io.Reader(nil)).Elem()
   322  
   323  to:
   324  
   325  	reflect.TypeFor[io.Reader]()
   326  
   327  No fix is offered in cases when the runtime type is dynamic, such as:
   328  
   329  	var r io.Reader = ...
   330  	reflect.TypeOf(r)
   331  
   332  or when the operand has potential side effects.
   333  
   334  # Analyzer slicesbackward
   335  
   336  slicesbackward: replace backward loops over slices with slices.Backward
   337  
   338  The slicesbackward analyzer suggests replacing manually-written backward
   339  loops of the form
   340  
   341  	for i := len(s) - 1; i >= 0; i-- {
   342  	    use(s[i])
   343  	}
   344  
   345  with the more readable Go 1.23 style using slices.Backward:
   346  
   347  	for _, v := range slices.Backward(s) {
   348  	    use(v)
   349  	}
   350  
   351  If the loop index is needed beyond just indexing into the slice, both
   352  the index and value variables are kept:
   353  
   354  	for i, v := range slices.Backward(s) { ... }
   355  
   356  # Analyzer slicescontains
   357  
   358  slicescontains: replace loops with slices.Contains or slices.ContainsFunc
   359  
   360  The slicescontains analyzer simplifies loops that check for the existence of
   361  an element in a slice. It replaces them with calls to `slices.Contains` or
   362  `slices.ContainsFunc`, which were added in Go 1.21.
   363  
   364  If the expression for the target element has side effects, this
   365  transformation will cause those effects to occur only once, not
   366  once per tested slice element.
   367  
   368  # Analyzer slicesdelete
   369  
   370  slicesdelete: replace append-based slice deletion with slices.Delete
   371  
   372  The slicesdelete analyzer suggests replacing the idiom
   373  
   374  	s = append(s[:i], s[j:]...)
   375  
   376  with the more explicit
   377  
   378  	s = slices.Delete(s, i, j)
   379  
   380  introduced in Go 1.21.
   381  
   382  This analyzer is disabled by default. The `slices.Delete` function
   383  zeros the elements between the new length and the old length of the
   384  slice to prevent memory leaks, which is a subtle difference in
   385  behavior compared to the append-based idiom; see https://go.dev/issue/73686.
   386  
   387  # Analyzer slicessort
   388  
   389  slicessort: replace sort.Slice with slices.Sort for basic types
   390  
   391  The slicessort analyzer simplifies sorting slices of basic ordered
   392  types. It replaces
   393  
   394  	sort.Slice(s, func(i, j int) bool { return s[i] < s[j] })
   395  
   396  with the simpler `slices.Sort(s)`, which was added in Go 1.21.
   397  
   398  # Analyzer stditerators
   399  
   400  stditerators: use iterators instead of Len/At-style APIs
   401  
   402  This analyzer suggests a fix to replace each loop of the form:
   403  
   404  	for i := 0; i < x.Len(); i++ {
   405  		use(x.At(i))
   406  	}
   407  
   408  or its "for elem := range x.Len()" equivalent by a range loop over an
   409  iterator offered by the same data type:
   410  
   411  	for elem := range x.All() {
   412  		use(x.At(i)
   413  	}
   414  
   415  where x is one of various well-known types in the standard library.
   416  
   417  # Analyzer stringscut
   418  
   419  stringscut: replace strings.Index etc. with strings.Cut
   420  
   421  This analyzer replaces certain patterns of use of [strings.Index] and string slicing by [strings.Cut], added in go1.18.
   422  
   423  For example:
   424  
   425  	idx := strings.Index(s, substr)
   426  	if idx >= 0 {
   427  	    return s[:idx]
   428  	}
   429  
   430  is replaced by:
   431  
   432  	before, _, ok := strings.Cut(s, substr)
   433  	if ok {
   434  	    return before
   435  	}
   436  
   437  And:
   438  
   439  	idx := strings.Index(s, substr)
   440  	if idx >= 0 {
   441  	    return
   442  	}
   443  
   444  is replaced by:
   445  
   446  	found := strings.Contains(s, substr)
   447  	if found {
   448  	    return
   449  	}
   450  
   451  It also handles variants using [strings.IndexByte] instead of Index, or the bytes package instead of strings.
   452  
   453  Fixes are offered only in cases in which there are no potential modifications of the idx, s, or substr expressions between their definition and use.
   454  
   455  It also replaces [strings.SplitN](s, sep, 2)[0] and [strings.Split](s, sep)[0] with the "before" result of strings.Cut, when sep is a non-empty string constant:
   456  
   457  	x := strings.SplitN(s, sep, 2)[0]
   458  
   459  is replaced by:
   460  
   461  	x, _, _ := strings.Cut(s, sep)
   462  
   463  The fix is only offered when sep is a non-empty string literal. When sep is a variable or the empty string, the semantics differ (strings.Split(s, "")[0] returns the first character of s, but strings.Cut(s, "").before is ""), so no fix is suggested.
   464  
   465  # Analyzer stringscutprefix
   466  
   467  stringscutprefix: replace HasPrefix/TrimPrefix with CutPrefix
   468  
   469  The stringscutprefix analyzer simplifies a common pattern where code first
   470  checks for a prefix with `strings.HasPrefix` and then removes it with
   471  `strings.TrimPrefix`. It replaces this two-step process with a single call
   472  to `strings.CutPrefix`, introduced in Go 1.20. The analyzer also handles
   473  the equivalent functions in the `bytes` package.
   474  
   475  For example, this input:
   476  
   477  	if strings.HasPrefix(s, prefix) {
   478  	    use(strings.TrimPrefix(s, prefix))
   479  	}
   480  
   481  is fixed to:
   482  
   483  	if after, ok := strings.CutPrefix(s, prefix); ok {
   484  	    use(after)
   485  	}
   486  
   487  The analyzer also offers fixes to use CutSuffix in a similar way.
   488  This input:
   489  
   490  	if strings.HasSuffix(s, suffix) {
   491  	    use(strings.TrimSuffix(s, suffix))
   492  	}
   493  
   494  is fixed to:
   495  
   496  	if before, ok := strings.CutSuffix(s, suffix); ok {
   497  	    use(before)
   498  	}
   499  
   500  # Analyzer stringsseq
   501  
   502  stringsseq: replace ranging over Split/Fields with SplitSeq/FieldsSeq
   503  
   504  The stringsseq analyzer improves the efficiency of iterating over substrings.
   505  It replaces
   506  
   507  	for range strings.Split(...)
   508  
   509  with the more efficient
   510  
   511  	for range strings.SplitSeq(...)
   512  
   513  which was added in Go 1.24 and avoids allocating a slice for the
   514  substrings. The analyzer also handles strings.Fields and the
   515  equivalent functions in the bytes package.
   516  
   517  # Analyzer stringsbuilder
   518  
   519  stringsbuilder: replace += with strings.Builder
   520  
   521  This analyzer replaces repeated string += string concatenation
   522  operations with calls to Go 1.10's strings.Builder.
   523  
   524  For example:
   525  
   526  	var s = "["
   527  	for x := range seq {
   528  		s += x
   529  		s += "."
   530  	}
   531  	s += "]"
   532  	use(s)
   533  
   534  is replaced by:
   535  
   536  	var s strings.Builder
   537  	s.WriteString("[")
   538  	for x := range seq {
   539  		s.WriteString(x)
   540  		s.WriteString(".")
   541  	}
   542  	s.WriteString("]")
   543  	use(s.String())
   544  
   545  This avoids quadratic memory allocation and improves performance.
   546  
   547  No diagnostics are issued in tests, where data sizes are often
   548  small and asymptotic performance is not a security concern.
   549  
   550  The analyzer requires that all references to s before the final uses
   551  are += operations. To avoid warning about trivial cases, at least one
   552  must appear within a loop. The variable s must be a local
   553  variable, not a global or parameter.
   554  
   555  All uses of the finished string must come after the last += operation.
   556  Each such use will be replaced by a call to strings.Builder's String method.
   557  (These may appear within an intervening loop or function literal, since even
   558  if s.String() is called repeatedly, it does not allocate memory.)
   559  
   560  Often the addend is a call to fmt.Sprintf, as in this example:
   561  
   562  	var s string
   563  	for x := range seq {
   564  		s += fmt.Sprintf("%v", x)
   565  	}
   566  
   567  which, once the suggested fix is applied, becomes:
   568  
   569  	var s strings.Builder
   570  	for x := range seq {
   571  		s.WriteString(fmt.Sprintf("%v", x))
   572  	}
   573  
   574  The WriteString call can be further simplified to the more efficient
   575  fmt.Fprintf(&s, "%v", x), avoiding the allocation of an intermediary.
   576  However, stringsbuilder does not perform this simplification;
   577  it requires staticcheck analyzer QF1012. (See https://go.dev/issue/76918.)
   578  
   579  # Analyzer testingcontext
   580  
   581  testingcontext: replace context.WithCancel with t.Context in tests
   582  
   583  The testingcontext analyzer simplifies context management in tests. It
   584  replaces the manual creation of a cancellable context,
   585  
   586  	ctx, cancel := context.WithCancel(context.Background())
   587  	defer cancel()
   588  
   589  with a single call to t.Context(), which was added in Go 1.24.
   590  
   591  This change is only suggested if the `cancel` function is not used
   592  for any other purpose.
   593  
   594  # Analyzer unsafefuncs
   595  
   596  unsafefuncs: replace unsafe pointer arithmetic with function calls
   597  
   598  The unsafefuncs analyzer simplifies pointer arithmetic expressions by
   599  replacing them with calls to helper functions such as unsafe.Add,
   600  added in Go 1.17.
   601  
   602  Example:
   603  
   604  	unsafe.Pointer(uintptr(ptr) + uintptr(n))
   605  
   606  where ptr is an unsafe.Pointer, is replaced by:
   607  
   608  	unsafe.Add(ptr, n)
   609  
   610  # Analyzer waitgroupgo
   611  
   612  waitgroupgo: replace wg.Add(1)/go/wg.Done() with wg.Go
   613  
   614  The waitgroupgo analyzer simplifies goroutine management with `sync.WaitGroup`.
   615  It replaces the common pattern
   616  
   617  	wg.Add(1)
   618  	go func() {
   619  		defer wg.Done()
   620  		...
   621  	}()
   622  
   623  with a single call to
   624  
   625  	wg.Go(func(){ ... })
   626  
   627  which was added in Go 1.25.
   628  */
   629  package modernize
   630  

View as plain text