| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 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 |  | 
|  | 15 | package config | 
|  | 16 |  | 
|  | 17 | import ( | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 18 | "fmt" | 
| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 19 | "strings" | 
|  | 20 |  | 
|  | 21 | "android/soong/android" | 
|  | 22 | ) | 
|  | 23 |  | 
|  | 24 | // Overarching principles for Rust lints on Android: | 
|  | 25 | // The Android build system tries to avoid reporting warnings during the build. | 
|  | 26 | // Therefore, by default, we upgrade warnings to denials. For some of these | 
|  | 27 | // lints, an allow exception is setup, using the variables below. | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 28 | // | 
| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 29 | // The lints are split into two categories. The first one contains the built-in | 
|  | 30 | // lints (https://doc.rust-lang.org/rustc/lints/index.html). The second is | 
|  | 31 | // specific to Clippy lints (https://rust-lang.github.io/rust-clippy/master/). | 
|  | 32 | // | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 33 | // For both categories, there are 3 levels of linting possible: | 
|  | 34 | // - "android", for the strictest lints that applies to all Android platform code. | 
|  | 35 | // - "vendor", for relaxed rules. | 
|  | 36 | // - "none", to disable the linting. | 
|  | 37 | // There is a fourth option ("default") which automatically selects the linting level | 
|  | 38 | // based on the module's location. See defaultLintSetForPath. | 
|  | 39 | // | 
|  | 40 | // When developing a module, you may set `lints = "none"` and `clippy_lints = | 
|  | 41 | // "none"` to disable all the linting. Expect some questioning during code review | 
|  | 42 | // if you enable one of these options. | 
| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 43 | var ( | 
|  | 44 | // Default Rust lints that applies to Google-authored modules. | 
|  | 45 | defaultRustcLints = []string{ | 
|  | 46 | "-A deprecated", | 
|  | 47 | "-D missing-docs", | 
|  | 48 | "-D warnings", | 
| Andrew Walbran | 7d61fae | 2023-07-06 17:29:23 +0100 | [diff] [blame] | 49 | "-D unsafe_op_in_unsafe_fn", | 
| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 50 | } | 
|  | 51 | // Default Clippy lints. These are applied on top of defaultRustcLints. | 
|  | 52 | // It should be assumed that any warning lint will be promoted to a | 
|  | 53 | // deny. | 
|  | 54 | defaultClippyLints = []string{ | 
|  | 55 | "-A clippy::type-complexity", | 
| Jeff Vander Stoep | 41f8157 | 2021-02-19 16:51:10 +0100 | [diff] [blame] | 56 | "-A clippy::unnecessary-wraps", | 
| Ivan Lozano | b6d0d9c | 2021-02-25 11:24:35 -0500 | [diff] [blame] | 57 | "-A clippy::unusual-byte-groupings", | 
| Jeff Vander Stoep | 0f36d16 | 2021-04-01 19:40:37 +0200 | [diff] [blame] | 58 | "-A clippy::upper-case-acronyms", | 
| Andrew Walbran | 7d61fae | 2023-07-06 17:29:23 +0100 | [diff] [blame] | 59 | "-D clippy::undocumented_unsafe_blocks", | 
| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 60 | } | 
|  | 61 |  | 
|  | 62 | // Rust lints for vendor code. | 
|  | 63 | defaultRustcVendorLints = []string{ | 
|  | 64 | "-A deprecated", | 
|  | 65 | "-D warnings", | 
|  | 66 | } | 
|  | 67 | // Clippy lints for vendor source. These are applied on top of | 
|  | 68 | // defaultRustcVendorLints.  It should be assumed that any warning lint | 
|  | 69 | // will be promoted to a deny. | 
|  | 70 | defaultClippyVendorLints = []string{ | 
|  | 71 | "-A clippy::complexity", | 
|  | 72 | "-A clippy::perf", | 
|  | 73 | "-A clippy::style", | 
|  | 74 | } | 
|  | 75 |  | 
|  | 76 | // For prebuilts/ and external/, no linting is expected. If a warning | 
|  | 77 | // or a deny is reported, it should be fixed upstream. | 
|  | 78 | allowAllLints = []string{ | 
|  | 79 | "--cap-lints allow", | 
|  | 80 | } | 
|  | 81 | ) | 
|  | 82 |  | 
|  | 83 | func init() { | 
|  | 84 | // Default Rust lints. These apply to all Google-authored modules. | 
|  | 85 | pctx.VariableFunc("RustDefaultLints", func(ctx android.PackageVarContext) string { | 
|  | 86 | if override := ctx.Config().Getenv("RUST_DEFAULT_LINTS"); override != "" { | 
|  | 87 | return override | 
|  | 88 | } | 
|  | 89 | return strings.Join(defaultRustcLints, " ") | 
|  | 90 | }) | 
|  | 91 | pctx.VariableFunc("ClippyDefaultLints", func(ctx android.PackageVarContext) string { | 
|  | 92 | if override := ctx.Config().Getenv("CLIPPY_DEFAULT_LINTS"); override != "" { | 
|  | 93 | return override | 
|  | 94 | } | 
|  | 95 | return strings.Join(defaultClippyLints, " ") | 
|  | 96 | }) | 
|  | 97 |  | 
|  | 98 | // Rust lints that only applies to external code. | 
|  | 99 | pctx.VariableFunc("RustVendorLints", func(ctx android.PackageVarContext) string { | 
|  | 100 | if override := ctx.Config().Getenv("RUST_VENDOR_LINTS"); override != "" { | 
|  | 101 | return override | 
|  | 102 | } | 
|  | 103 | return strings.Join(defaultRustcVendorLints, " ") | 
|  | 104 | }) | 
|  | 105 | pctx.VariableFunc("ClippyVendorLints", func(ctx android.PackageVarContext) string { | 
|  | 106 | if override := ctx.Config().Getenv("CLIPPY_VENDOR_LINTS"); override != "" { | 
|  | 107 | return override | 
|  | 108 | } | 
|  | 109 | return strings.Join(defaultClippyVendorLints, " ") | 
|  | 110 | }) | 
|  | 111 | pctx.StaticVariable("RustAllowAllLints", strings.Join(allowAllLints, " ")) | 
|  | 112 | } | 
|  | 113 |  | 
| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 114 | const noLint = "" | 
|  | 115 | const rustcDefault = "${config.RustDefaultLints}" | 
|  | 116 | const rustcVendor = "${config.RustVendorLints}" | 
|  | 117 | const rustcAllowAll = "${config.RustAllowAllLints}" | 
|  | 118 | const clippyDefault = "${config.ClippyDefaultLints}" | 
|  | 119 | const clippyVendor = "${config.ClippyVendorLints}" | 
|  | 120 |  | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 121 | // lintConfig defines a set of lints and clippy configuration. | 
|  | 122 | type lintConfig struct { | 
|  | 123 | rustcConfig   string // for the lints to apply to rustc. | 
|  | 124 | clippyEnabled bool   // to indicate if clippy should be executed. | 
|  | 125 | clippyConfig  string // for the lints to apply to clippy. | 
| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 126 | } | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 127 |  | 
|  | 128 | const ( | 
|  | 129 | androidLints = "android" | 
|  | 130 | vendorLints  = "vendor" | 
|  | 131 | noneLints    = "none" | 
|  | 132 | ) | 
|  | 133 |  | 
|  | 134 | // lintSets defines the categories of linting for Android and their mapping to lintConfigs. | 
|  | 135 | var lintSets = map[string]lintConfig{ | 
|  | 136 | androidLints: {rustcDefault, true, clippyDefault}, | 
|  | 137 | vendorLints:  {rustcVendor, true, clippyVendor}, | 
|  | 138 | noneLints:    {rustcAllowAll, false, noLint}, | 
|  | 139 | } | 
|  | 140 |  | 
|  | 141 | type pathLintSet struct { | 
|  | 142 | prefix string | 
|  | 143 | set    string | 
|  | 144 | } | 
|  | 145 |  | 
|  | 146 | // This is a map of local path prefixes to a lint set.  The first entry | 
|  | 147 | // matching will be used. If no entry matches, androidLints ("android") will be | 
|  | 148 | // used. | 
|  | 149 | var defaultLintSetForPath = []pathLintSet{ | 
|  | 150 | {"external", noneLints}, | 
|  | 151 | {"hardware", vendorLints}, | 
|  | 152 | {"prebuilts", noneLints}, | 
|  | 153 | {"vendor/google", androidLints}, | 
|  | 154 | {"vendor", vendorLints}, | 
|  | 155 | } | 
| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 156 |  | 
|  | 157 | // ClippyLintsForDir returns a boolean if Clippy should be executed and if so, the lints to be used. | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 158 | func ClippyLintsForDir(dir string, clippyLintsProperty *string) (bool, string, error) { | 
|  | 159 | if clippyLintsProperty != nil { | 
|  | 160 | set, ok := lintSets[*clippyLintsProperty] | 
|  | 161 | if ok { | 
|  | 162 | return set.clippyEnabled, set.clippyConfig, nil | 
|  | 163 | } | 
|  | 164 | if *clippyLintsProperty != "default" { | 
|  | 165 | return false, "", fmt.Errorf("unknown value for `clippy_lints`: %v, valid options are: default, android, vendor or none", *clippyLintsProperty) | 
| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 166 | } | 
|  | 167 | } | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 168 | for _, p := range defaultLintSetForPath { | 
|  | 169 | if strings.HasPrefix(dir, p.prefix) { | 
|  | 170 | setConfig := lintSets[p.set] | 
|  | 171 | return setConfig.clippyEnabled, setConfig.clippyConfig, nil | 
|  | 172 | } | 
|  | 173 | } | 
|  | 174 | return true, clippyDefault, nil | 
| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 175 | } | 
|  | 176 |  | 
|  | 177 | // RustcLintsForDir returns the standard lints to be used for a repository. | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 178 | func RustcLintsForDir(dir string, lintProperty *string) (string, error) { | 
|  | 179 | if lintProperty != nil { | 
|  | 180 | set, ok := lintSets[*lintProperty] | 
|  | 181 | if ok { | 
|  | 182 | return set.rustcConfig, nil | 
|  | 183 | } | 
|  | 184 | if *lintProperty != "default" { | 
|  | 185 | return "", fmt.Errorf("unknown value for `lints`: %v, valid options are: default, android, vendor or none", *lintProperty) | 
|  | 186 | } | 
|  | 187 |  | 
|  | 188 | } | 
|  | 189 | for _, p := range defaultLintSetForPath { | 
|  | 190 | if strings.HasPrefix(dir, p.prefix) { | 
|  | 191 | return lintSets[p.set].rustcConfig, nil | 
| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 192 | } | 
|  | 193 | } | 
| Thiébaud Weksteen | 9e8451e | 2020-08-13 12:55:59 +0200 | [diff] [blame] | 194 | return rustcDefault, nil | 
| Thiébaud Weksteen | 8e46efa | 2020-06-30 21:43:35 +0200 | [diff] [blame] | 195 | } |