doc.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. // Package simple contains analyzes that simplify code.
  2. // All suggestions made by these analyzes are intended to result in objectively simpler code,
  3. // and following their advice is recommended.
  4. package simple
  5. import "honnef.co/go/tools/analysis/lint"
  6. var Docs = lint.Markdownify(map[string]*lint.RawDocumentation{
  7. "S1000": {
  8. Title: `Use plain channel send or receive instead of single-case select`,
  9. Text: `Select statements with a single case can be replaced with a simple
  10. send or receive.`,
  11. Before: `
  12. select {
  13. case x := <-ch:
  14. fmt.Println(x)
  15. }`,
  16. After: `
  17. x := <-ch
  18. fmt.Println(x)
  19. `,
  20. Since: "2017.1",
  21. MergeIf: lint.MergeIfAny,
  22. },
  23. "S1001": {
  24. Title: `Replace for loop with call to copy`,
  25. Text: `
  26. Use \'copy()\' for copying elements from one slice to another. For
  27. arrays of identical size, you can use simple assignment.`,
  28. Before: `
  29. for i, x := range src {
  30. dst[i] = x
  31. }`,
  32. After: `copy(dst, src)`,
  33. Since: "2017.1",
  34. // MergeIfAll because the types of src and dst might be different under different build tags.
  35. // You shouldn't write code like that…
  36. MergeIf: lint.MergeIfAll,
  37. },
  38. "S1002": {
  39. Title: `Omit comparison with boolean constant`,
  40. Before: `if x == true {}`,
  41. After: `if x {}`,
  42. Since: "2017.1",
  43. // MergeIfAll because 'true' might not be the builtin constant under all build tags.
  44. // You shouldn't write code like that…
  45. MergeIf: lint.MergeIfAll,
  46. },
  47. "S1003": {
  48. Title: `Replace call to \'strings.Index\' with \'strings.Contains\'`,
  49. Before: `if strings.Index(x, y) != -1 {}`,
  50. After: `if strings.Contains(x, y) {}`,
  51. Since: "2017.1",
  52. MergeIf: lint.MergeIfAny,
  53. },
  54. "S1004": {
  55. Title: `Replace call to \'bytes.Compare\' with \'bytes.Equal\'`,
  56. Before: `if bytes.Compare(x, y) == 0 {}`,
  57. After: `if bytes.Equal(x, y) {}`,
  58. Since: "2017.1",
  59. MergeIf: lint.MergeIfAny,
  60. },
  61. "S1005": {
  62. Title: `Drop unnecessary use of the blank identifier`,
  63. Text: `In many cases, assigning to the blank identifier is unnecessary.`,
  64. Before: `
  65. for _ = range s {}
  66. x, _ = someMap[key]
  67. _ = <-ch`,
  68. After: `
  69. for range s{}
  70. x = someMap[key]
  71. <-ch`,
  72. Since: "2017.1",
  73. MergeIf: lint.MergeIfAny,
  74. },
  75. "S1006": {
  76. Title: `Use \"for { ... }\" for infinite loops`,
  77. Text: `For infinite loops, using \'for { ... }\' is the most idiomatic choice.`,
  78. Since: "2017.1",
  79. MergeIf: lint.MergeIfAny,
  80. },
  81. "S1007": {
  82. Title: `Simplify regular expression by using raw string literal`,
  83. Text: `Raw string literals use backticks instead of quotation marks and do not support
  84. any escape sequences. This means that the backslash can be used
  85. freely, without the need of escaping.
  86. Since regular expressions have their own escape sequences, raw strings
  87. can improve their readability.`,
  88. Before: `regexp.Compile("\\A(\\w+) profile: total \\d+\\n\\z")`,
  89. After: "regexp.Compile(`\\A(\\w+) profile: total \\d+\\n\\z`)",
  90. Since: "2017.1",
  91. MergeIf: lint.MergeIfAny,
  92. },
  93. "S1008": {
  94. Title: `Simplify returning boolean expression`,
  95. Before: `
  96. if <expr> {
  97. return true
  98. }
  99. return false`,
  100. After: `return <expr>`,
  101. Since: "2017.1",
  102. MergeIf: lint.MergeIfAny,
  103. },
  104. "S1009": {
  105. Title: `Omit redundant nil check on slices`,
  106. Text: `The \'len\' function is defined for all slices, even nil ones, which have
  107. a length of zero. It is not necessary to check if a slice is not nil
  108. before checking that its length is not zero.`,
  109. Before: `if x != nil && len(x) != 0 {}`,
  110. After: `if len(x) != 0 {}`,
  111. Since: "2017.1",
  112. MergeIf: lint.MergeIfAny,
  113. },
  114. "S1010": {
  115. Title: `Omit default slice index`,
  116. Text: `When slicing, the second index defaults to the length of the value,
  117. making \'s[n:len(s)]\' and \'s[n:]\' equivalent.`,
  118. Since: "2017.1",
  119. MergeIf: lint.MergeIfAny,
  120. },
  121. "S1011": {
  122. Title: `Use a single \'append\' to concatenate two slices`,
  123. Before: `
  124. for _, e := range y {
  125. x = append(x, e)
  126. }`,
  127. After: `x = append(x, y...)`,
  128. Since: "2017.1",
  129. // MergeIfAll because y might not be a slice under all build tags.
  130. MergeIf: lint.MergeIfAll,
  131. },
  132. "S1012": {
  133. Title: `Replace \'time.Now().Sub(x)\' with \'time.Since(x)\'`,
  134. Text: `The \'time.Since\' helper has the same effect as using \'time.Now().Sub(x)\'
  135. but is easier to read.`,
  136. Before: `time.Now().Sub(x)`,
  137. After: `time.Since(x)`,
  138. Since: "2017.1",
  139. MergeIf: lint.MergeIfAny,
  140. },
  141. "S1016": {
  142. Title: `Use a type conversion instead of manually copying struct fields`,
  143. Text: `Two struct types with identical fields can be converted between each
  144. other. In older versions of Go, the fields had to have identical
  145. struct tags. Since Go 1.8, however, struct tags are ignored during
  146. conversions. It is thus not necessary to manually copy every field
  147. individually.`,
  148. Before: `
  149. var x T1
  150. y := T2{
  151. Field1: x.Field1,
  152. Field2: x.Field2,
  153. }`,
  154. After: `
  155. var x T1
  156. y := T2(x)`,
  157. Since: "2017.1",
  158. MergeIf: lint.MergeIfAll,
  159. },
  160. "S1017": {
  161. Title: `Replace manual trimming with \'strings.TrimPrefix\'`,
  162. Text: `Instead of using \'strings.HasPrefix\' and manual slicing, use the
  163. \'strings.TrimPrefix\' function. If the string doesn't start with the
  164. prefix, the original string will be returned. Using \'strings.TrimPrefix\'
  165. reduces complexity, and avoids common bugs, such as off-by-one
  166. mistakes.`,
  167. Before: `
  168. if strings.HasPrefix(str, prefix) {
  169. str = str[len(prefix):]
  170. }`,
  171. After: `str = strings.TrimPrefix(str, prefix)`,
  172. Since: "2017.1",
  173. MergeIf: lint.MergeIfAny,
  174. },
  175. "S1018": {
  176. Title: `Use \"copy\" for sliding elements`,
  177. Text: `\'copy()\' permits using the same source and destination slice, even with
  178. overlapping ranges. This makes it ideal for sliding elements in a
  179. slice.`,
  180. Before: `
  181. for i := 0; i < n; i++ {
  182. bs[i] = bs[offset+i]
  183. }`,
  184. After: `copy(bs[:n], bs[offset:])`,
  185. Since: "2017.1",
  186. MergeIf: lint.MergeIfAny,
  187. },
  188. "S1019": {
  189. Title: `Simplify \"make\" call by omitting redundant arguments`,
  190. Text: `The \"make\" function has default values for the length and capacity
  191. arguments. For channels, the length defaults to zero, and for slices,
  192. the capacity defaults to the length.`,
  193. Since: "2017.1",
  194. // MergeIfAll because the type might be different under different build tags.
  195. // You shouldn't write code like that…
  196. MergeIf: lint.MergeIfAll,
  197. },
  198. "S1020": {
  199. Title: `Omit redundant nil check in type assertion`,
  200. Before: `if _, ok := i.(T); ok && i != nil {}`,
  201. After: `if _, ok := i.(T); ok {}`,
  202. Since: "2017.1",
  203. MergeIf: lint.MergeIfAny,
  204. },
  205. "S1021": {
  206. Title: `Merge variable declaration and assignment`,
  207. Before: `
  208. var x uint
  209. x = 1`,
  210. After: `var x uint = 1`,
  211. Since: "2017.1",
  212. MergeIf: lint.MergeIfAny,
  213. },
  214. "S1023": {
  215. Title: `Omit redundant control flow`,
  216. Text: `Functions that have no return value do not need a return statement as
  217. the final statement of the function.
  218. Switches in Go do not have automatic fallthrough, unlike languages
  219. like C. It is not necessary to have a break statement as the final
  220. statement in a case block.`,
  221. Since: "2017.1",
  222. MergeIf: lint.MergeIfAny,
  223. },
  224. "S1024": {
  225. Title: `Replace \'x.Sub(time.Now())\' with \'time.Until(x)\'`,
  226. Text: `The \'time.Until\' helper has the same effect as using \'x.Sub(time.Now())\'
  227. but is easier to read.`,
  228. Before: `x.Sub(time.Now())`,
  229. After: `time.Until(x)`,
  230. Since: "2017.1",
  231. MergeIf: lint.MergeIfAny,
  232. },
  233. "S1025": {
  234. Title: `Don't use \'fmt.Sprintf("%s", x)\' unnecessarily`,
  235. Text: `In many instances, there are easier and more efficient ways of getting
  236. a value's string representation. Whenever a value's underlying type is
  237. a string already, or the type has a String method, they should be used
  238. directly.
  239. Given the following shared definitions
  240. type T1 string
  241. type T2 int
  242. func (T2) String() string { return "Hello, world" }
  243. var x string
  244. var y T1
  245. var z T2
  246. we can simplify
  247. fmt.Sprintf("%s", x)
  248. fmt.Sprintf("%s", y)
  249. fmt.Sprintf("%s", z)
  250. to
  251. x
  252. string(y)
  253. z.String()
  254. `,
  255. Since: "2017.1",
  256. MergeIf: lint.MergeIfAll,
  257. },
  258. "S1028": {
  259. Title: `Simplify error construction with \'fmt.Errorf\'`,
  260. Before: `errors.New(fmt.Sprintf(...))`,
  261. After: `fmt.Errorf(...)`,
  262. Since: "2017.1",
  263. MergeIf: lint.MergeIfAny,
  264. },
  265. "S1029": {
  266. Title: `Range over the string directly`,
  267. Text: `Ranging over a string will yield byte offsets and runes. If the offset
  268. isn't used, this is functionally equivalent to converting the string
  269. to a slice of runes and ranging over that. Ranging directly over the
  270. string will be more performant, however, as it avoids allocating a new
  271. slice, the size of which depends on the length of the string.`,
  272. Before: `for _, r := range []rune(s) {}`,
  273. After: `for _, r := range s {}`,
  274. Since: "2017.1",
  275. MergeIf: lint.MergeIfAny,
  276. },
  277. "S1030": {
  278. Title: `Use \'bytes.Buffer.String\' or \'bytes.Buffer.Bytes\'`,
  279. Text: `\'bytes.Buffer\' has both a \'String\' and a \'Bytes\' method. It is almost never
  280. necessary to use \'string(buf.Bytes())\' or \'[]byte(buf.String())\' – simply
  281. use the other method.
  282. The only exception to this are map lookups. Due to a compiler optimization,
  283. \'m[string(buf.Bytes())]\' is more efficient than \'m[buf.String()]\'.
  284. `,
  285. Since: "2017.1",
  286. MergeIf: lint.MergeIfAny,
  287. },
  288. "S1031": {
  289. Title: `Omit redundant nil check around loop`,
  290. Text: `You can use range on nil slices and maps, the loop will simply never
  291. execute. This makes an additional nil check around the loop
  292. unnecessary.`,
  293. Before: `
  294. if s != nil {
  295. for _, x := range s {
  296. ...
  297. }
  298. }`,
  299. After: `
  300. for _, x := range s {
  301. ...
  302. }`,
  303. Since: "2017.1",
  304. // MergeIfAll because x might be a channel under some build tags.
  305. // you shouldn't write code like that…
  306. MergeIf: lint.MergeIfAll,
  307. },
  308. "S1032": {
  309. Title: `Use \'sort.Ints(x)\', \'sort.Float64s(x)\', and \'sort.Strings(x)\'`,
  310. Text: `The \'sort.Ints\', \'sort.Float64s\' and \'sort.Strings\' functions are easier to
  311. read than \'sort.Sort(sort.IntSlice(x))\', \'sort.Sort(sort.Float64Slice(x))\'
  312. and \'sort.Sort(sort.StringSlice(x))\'.`,
  313. Before: `sort.Sort(sort.StringSlice(x))`,
  314. After: `sort.Strings(x)`,
  315. Since: "2019.1",
  316. MergeIf: lint.MergeIfAny,
  317. },
  318. "S1033": {
  319. Title: `Unnecessary guard around call to \"delete\"`,
  320. Text: `Calling \'delete\' on a nil map is a no-op.`,
  321. Since: "2019.2",
  322. MergeIf: lint.MergeIfAny,
  323. },
  324. "S1034": {
  325. Title: `Use result of type assertion to simplify cases`,
  326. Since: "2019.2",
  327. MergeIf: lint.MergeIfAny,
  328. },
  329. "S1035": {
  330. Title: `Redundant call to \'net/http.CanonicalHeaderKey\' in method call on \'net/http.Header\'`,
  331. Text: `
  332. The methods on \'net/http.Header\', namely \'Add\', \'Del\', \'Get\'
  333. and \'Set\', already canonicalize the given header name.`,
  334. Since: "2020.1",
  335. MergeIf: lint.MergeIfAny,
  336. },
  337. "S1036": {
  338. Title: `Unnecessary guard around map access`,
  339. Text: `
  340. When accessing a map key that doesn't exist yet, one receives a zero
  341. value. Often, the zero value is a suitable value, for example when
  342. using append or doing integer math.
  343. The following
  344. if _, ok := m["foo"]; ok {
  345. m["foo"] = append(m["foo"], "bar")
  346. } else {
  347. m["foo"] = []string{"bar"}
  348. }
  349. can be simplified to
  350. m["foo"] = append(m["foo"], "bar")
  351. and
  352. if _, ok := m2["k"]; ok {
  353. m2["k"] += 4
  354. } else {
  355. m2["k"] = 4
  356. }
  357. can be simplified to
  358. m["k"] += 4
  359. `,
  360. Since: "2020.1",
  361. MergeIf: lint.MergeIfAny,
  362. },
  363. "S1037": {
  364. Title: `Elaborate way of sleeping`,
  365. Text: `Using a select statement with a single case receiving
  366. from the result of \'time.After\' is a very elaborate way of sleeping that
  367. can much simpler be expressed with a simple call to time.Sleep.`,
  368. Since: "2020.1",
  369. MergeIf: lint.MergeIfAny,
  370. },
  371. "S1038": {
  372. Title: "Unnecessarily complex way of printing formatted string",
  373. Text: `Instead of using \'fmt.Print(fmt.Sprintf(...))\', one can use \'fmt.Printf(...)\'.`,
  374. Since: "2020.1",
  375. MergeIf: lint.MergeIfAny,
  376. },
  377. "S1039": {
  378. Title: `Unnecessary use of \'fmt.Sprint\'`,
  379. Text: `
  380. Calling \'fmt.Sprint\' with a single string argument is unnecessary
  381. and identical to using the string directly.`,
  382. Since: "2020.1",
  383. // MergeIfAll because s might not be a string under all build tags.
  384. // you shouldn't write code like that…
  385. MergeIf: lint.MergeIfAll,
  386. },
  387. "S1040": {
  388. Title: "Type assertion to current type",
  389. Text: `The type assertion \'x.(SomeInterface)\', when \'x\' already has type
  390. \'SomeInterface\', can only fail if \'x\' is nil. Usually, this is
  391. left-over code from when \'x\' had a different type and you can safely
  392. delete the type assertion. If you want to check that \'x\' is not nil,
  393. consider being explicit and using an actual \'if x == nil\' comparison
  394. instead of relying on the type assertion panicking.`,
  395. Since: "2021.1",
  396. // MergeIfAll because x might have different types under different build tags.
  397. // You shouldn't write code like that…
  398. MergeIf: lint.MergeIfAll,
  399. },
  400. })