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