lints.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // Copyright 2020 The Android Open Source Project
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package config
  15. import (
  16. "fmt"
  17. "strings"
  18. "android/soong/android"
  19. )
  20. // Overarching principles for Rust lints on Android:
  21. // The Android build system tries to avoid reporting warnings during the build.
  22. // Therefore, by default, we upgrade warnings to denials. For some of these
  23. // lints, an allow exception is setup, using the variables below.
  24. //
  25. // The lints are split into two categories. The first one contains the built-in
  26. // lints (https://doc.rust-lang.org/rustc/lints/index.html). The second is
  27. // specific to Clippy lints (https://rust-lang.github.io/rust-clippy/master/).
  28. //
  29. // For both categories, there are 3 levels of linting possible:
  30. // - "android", for the strictest lints that applies to all Android platform code.
  31. // - "vendor", for relaxed rules.
  32. // - "none", to disable the linting.
  33. // There is a fourth option ("default") which automatically selects the linting level
  34. // based on the module's location. See defaultLintSetForPath.
  35. //
  36. // When developing a module, you may set `lints = "none"` and `clippy_lints =
  37. // "none"` to disable all the linting. Expect some questioning during code review
  38. // if you enable one of these options.
  39. var (
  40. // Default Rust lints that applies to Google-authored modules.
  41. defaultRustcLints = []string{
  42. "-A deprecated",
  43. "-D missing-docs",
  44. "-D warnings",
  45. }
  46. // Default Clippy lints. These are applied on top of defaultRustcLints.
  47. // It should be assumed that any warning lint will be promoted to a
  48. // deny.
  49. defaultClippyLints = []string{
  50. "-A clippy::type-complexity",
  51. }
  52. // Rust lints for vendor code.
  53. defaultRustcVendorLints = []string{
  54. "-A deprecated",
  55. "-D warnings",
  56. }
  57. // Clippy lints for vendor source. These are applied on top of
  58. // defaultRustcVendorLints. It should be assumed that any warning lint
  59. // will be promoted to a deny.
  60. defaultClippyVendorLints = []string{
  61. "-A clippy::complexity",
  62. "-A clippy::perf",
  63. "-A clippy::style",
  64. }
  65. // For prebuilts/ and external/, no linting is expected. If a warning
  66. // or a deny is reported, it should be fixed upstream.
  67. allowAllLints = []string{
  68. "--cap-lints allow",
  69. }
  70. )
  71. func init() {
  72. // Default Rust lints. These apply to all Google-authored modules.
  73. pctx.VariableFunc("RustDefaultLints", func(ctx android.PackageVarContext) string {
  74. if override := ctx.Config().Getenv("RUST_DEFAULT_LINTS"); override != "" {
  75. return override
  76. }
  77. return strings.Join(defaultRustcLints, " ")
  78. })
  79. pctx.VariableFunc("ClippyDefaultLints", func(ctx android.PackageVarContext) string {
  80. if override := ctx.Config().Getenv("CLIPPY_DEFAULT_LINTS"); override != "" {
  81. return override
  82. }
  83. return strings.Join(defaultClippyLints, " ")
  84. })
  85. // Rust lints that only applies to external code.
  86. pctx.VariableFunc("RustVendorLints", func(ctx android.PackageVarContext) string {
  87. if override := ctx.Config().Getenv("RUST_VENDOR_LINTS"); override != "" {
  88. return override
  89. }
  90. return strings.Join(defaultRustcVendorLints, " ")
  91. })
  92. pctx.VariableFunc("ClippyVendorLints", func(ctx android.PackageVarContext) string {
  93. if override := ctx.Config().Getenv("CLIPPY_VENDOR_LINTS"); override != "" {
  94. return override
  95. }
  96. return strings.Join(defaultClippyVendorLints, " ")
  97. })
  98. pctx.StaticVariable("RustAllowAllLints", strings.Join(allowAllLints, " "))
  99. }
  100. const noLint = ""
  101. const rustcDefault = "${config.RustDefaultLints}"
  102. const rustcVendor = "${config.RustVendorLints}"
  103. const rustcAllowAll = "${config.RustAllowAllLints}"
  104. const clippyDefault = "${config.ClippyDefaultLints}"
  105. const clippyVendor = "${config.ClippyVendorLints}"
  106. // lintConfig defines a set of lints and clippy configuration.
  107. type lintConfig struct {
  108. rustcConfig string // for the lints to apply to rustc.
  109. clippyEnabled bool // to indicate if clippy should be executed.
  110. clippyConfig string // for the lints to apply to clippy.
  111. }
  112. const (
  113. androidLints = "android"
  114. vendorLints = "vendor"
  115. noneLints = "none"
  116. )
  117. // lintSets defines the categories of linting for Android and their mapping to lintConfigs.
  118. var lintSets = map[string]lintConfig{
  119. androidLints: {rustcDefault, true, clippyDefault},
  120. vendorLints: {rustcVendor, true, clippyVendor},
  121. noneLints: {rustcAllowAll, false, noLint},
  122. }
  123. type pathLintSet struct {
  124. prefix string
  125. set string
  126. }
  127. // This is a map of local path prefixes to a lint set. The first entry
  128. // matching will be used. If no entry matches, androidLints ("android") will be
  129. // used.
  130. var defaultLintSetForPath = []pathLintSet{
  131. {"external", noneLints},
  132. {"hardware", vendorLints},
  133. {"prebuilts", noneLints},
  134. {"vendor/google", androidLints},
  135. {"vendor", vendorLints},
  136. }
  137. // ClippyLintsForDir returns a boolean if Clippy should be executed and if so, the lints to be used.
  138. func ClippyLintsForDir(dir string, clippyLintsProperty *string) (bool, string, error) {
  139. if clippyLintsProperty != nil {
  140. set, ok := lintSets[*clippyLintsProperty]
  141. if ok {
  142. return set.clippyEnabled, set.clippyConfig, nil
  143. }
  144. if *clippyLintsProperty != "default" {
  145. return false, "", fmt.Errorf("unknown value for `clippy_lints`: %v, valid options are: default, android, vendor or none", *clippyLintsProperty)
  146. }
  147. }
  148. for _, p := range defaultLintSetForPath {
  149. if strings.HasPrefix(dir, p.prefix) {
  150. setConfig := lintSets[p.set]
  151. return setConfig.clippyEnabled, setConfig.clippyConfig, nil
  152. }
  153. }
  154. return true, clippyDefault, nil
  155. }
  156. // RustcLintsForDir returns the standard lints to be used for a repository.
  157. func RustcLintsForDir(dir string, lintProperty *string) (string, error) {
  158. if lintProperty != nil {
  159. set, ok := lintSets[*lintProperty]
  160. if ok {
  161. return set.rustcConfig, nil
  162. }
  163. if *lintProperty != "default" {
  164. return "", fmt.Errorf("unknown value for `lints`: %v, valid options are: default, android, vendor or none", *lintProperty)
  165. }
  166. }
  167. for _, p := range defaultLintSetForPath {
  168. if strings.HasPrefix(dir, p.prefix) {
  169. return lintSets[p.set].rustcConfig, nil
  170. }
  171. }
  172. return rustcDefault, nil
  173. }