@@ -85,40 +85,41 @@ pub struct Lint {
85
85
}
86
86
87
87
impl Lint {
88
- pub fn level ( & self , lints : & TomlToolLints , edition : Edition ) -> LintLevel {
89
- let edition_level = self
90
- . edition_lint_opts
91
- . filter ( |( e, _) | edition >= * e)
92
- . map ( |( _, l) | l) ;
93
-
94
- if self . default_level == LintLevel :: Forbid || edition_level == Some ( LintLevel :: Forbid ) {
95
- return LintLevel :: Forbid ;
96
- }
97
-
98
- let level = self
99
- . groups
88
+ pub fn level (
89
+ & self ,
90
+ pkg_lints : & TomlToolLints ,
91
+ ws_lints : & TomlToolLints ,
92
+ edition : Edition ,
93
+ ) -> ( LintLevel , LintLevelReason ) {
94
+ self . groups
100
95
. iter ( )
101
- . map ( |g| g. name )
102
- . chain ( std:: iter:: once ( self . name ) )
103
- . filter_map ( |n| lints. get ( n) . map ( |l| ( n, l) ) )
104
- . max_by_key ( |( n, l) | {
96
+ . map ( |g| {
105
97
(
106
- l. level ( ) == TomlLintLevel :: Forbid ,
107
- l. priority ( ) ,
108
- std:: cmp:: Reverse ( * n) ,
98
+ g. name ,
99
+ level_priority (
100
+ g. name ,
101
+ g. default_level ,
102
+ g. edition_lint_opts ,
103
+ pkg_lints,
104
+ ws_lints,
105
+ edition,
106
+ ) ,
109
107
)
110
- } ) ;
111
-
112
- match level {
113
- Some ( ( _, toml_lint) ) => toml_lint. level ( ) . into ( ) ,
114
- None => {
115
- if let Some ( level) = edition_level {
116
- level
117
- } else {
118
- self . default_level
119
- }
120
- }
121
- }
108
+ } )
109
+ . chain ( std:: iter:: once ( (
110
+ self . name ,
111
+ level_priority (
112
+ self . name ,
113
+ self . default_level ,
114
+ self . edition_lint_opts ,
115
+ pkg_lints,
116
+ ws_lints,
117
+ edition,
118
+ ) ,
119
+ ) ) )
120
+ . max_by_key ( |( n, ( l, _, p) ) | ( l == & LintLevel :: Forbid , * p, std:: cmp:: Reverse ( * n) ) )
121
+ . map ( |( _, ( l, r, _) ) | ( l, r) )
122
+ . unwrap ( )
122
123
}
123
124
}
124
125
@@ -163,6 +164,64 @@ impl From<TomlLintLevel> for LintLevel {
163
164
}
164
165
}
165
166
167
+ #[ derive( Copy , Clone , Debug ) ]
168
+ pub enum LintLevelReason {
169
+ Default ,
170
+ Edition ( Edition ) ,
171
+ Package ,
172
+ Workspace ,
173
+ }
174
+
175
+ impl Display for LintLevelReason {
176
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
177
+ match self {
178
+ LintLevelReason :: Default => write ! ( f, "by default" ) ,
179
+ LintLevelReason :: Edition ( edition) => write ! ( f, "in edition {}" , edition) ,
180
+ LintLevelReason :: Package => write ! ( f, "in `[lints]`" ) ,
181
+ LintLevelReason :: Workspace => write ! ( f, "in `[workspace.lints]`" ) ,
182
+ }
183
+ }
184
+ }
185
+
186
+ fn level_priority (
187
+ name : & str ,
188
+ default_level : LintLevel ,
189
+ edition_lint_opts : Option < ( Edition , LintLevel ) > ,
190
+ pkg_lints : & TomlToolLints ,
191
+ ws_lints : & TomlToolLints ,
192
+ edition : Edition ,
193
+ ) -> ( LintLevel , LintLevelReason , i8 ) {
194
+ let ( unspecified_level, reason) = if let Some ( level) = edition_lint_opts
195
+ . filter ( |( e, _) | edition >= * e)
196
+ . map ( |( _, l) | l)
197
+ {
198
+ ( level, LintLevelReason :: Edition ( edition) )
199
+ } else {
200
+ ( default_level, LintLevelReason :: Default )
201
+ } ;
202
+
203
+ // Don't allow the group to be overridden if the level is `Forbid`
204
+ if unspecified_level == LintLevel :: Forbid {
205
+ return ( unspecified_level, reason, 0 ) ;
206
+ }
207
+
208
+ if let Some ( defined_level) = pkg_lints. get ( name) {
209
+ (
210
+ defined_level. level ( ) . into ( ) ,
211
+ LintLevelReason :: Package ,
212
+ defined_level. priority ( ) ,
213
+ )
214
+ } else if let Some ( defined_level) = ws_lints. get ( name) {
215
+ (
216
+ defined_level. level ( ) . into ( ) ,
217
+ LintLevelReason :: Workspace ,
218
+ defined_level. priority ( ) ,
219
+ )
220
+ } else {
221
+ ( unspecified_level, reason, 0 )
222
+ }
223
+ }
224
+
166
225
const IM_A_TEAPOT : Lint = Lint {
167
226
name : "im_a_teapot" ,
168
227
desc : "`im_a_teapot` is specified" ,
@@ -174,12 +233,13 @@ const IM_A_TEAPOT: Lint = Lint {
174
233
pub fn check_im_a_teapot (
175
234
pkg : & Package ,
176
235
path : & Path ,
177
- lints : & TomlToolLints ,
236
+ pkg_lints : & TomlToolLints ,
237
+ ws_lints : & TomlToolLints ,
178
238
error_count : & mut usize ,
179
239
gctx : & GlobalContext ,
180
240
) -> CargoResult < ( ) > {
181
241
let manifest = pkg. manifest ( ) ;
182
- let lint_level = IM_A_TEAPOT . level ( lints , manifest. edition ( ) ) ;
242
+ let ( lint_level, reason ) = IM_A_TEAPOT . level ( pkg_lints , ws_lints , manifest. edition ( ) ) ;
183
243
if lint_level == LintLevel :: Allow {
184
244
return Ok ( ( ) ) ;
185
245
}
@@ -194,7 +254,10 @@ pub fn check_im_a_teapot(
194
254
}
195
255
let level = lint_level. to_diagnostic_level ( ) ;
196
256
let manifest_path = rel_cwd_manifest_path ( path, gctx) ;
197
- let emitted_reason = format ! ( "`cargo::{}` is set to `{lint_level}`" , IM_A_TEAPOT . name) ;
257
+ let emitted_reason = format ! (
258
+ "`cargo::{}` is set to `{lint_level}` {reason}" ,
259
+ IM_A_TEAPOT . name
260
+ ) ;
198
261
199
262
let key_span = get_span ( manifest. document ( ) , & [ "package" , "im-a-teapot" ] , false ) . unwrap ( ) ;
200
263
let value_span = get_span ( manifest. document ( ) , & [ "package" , "im-a-teapot" ] , true ) . unwrap ( ) ;
@@ -242,7 +305,8 @@ const IMPLICIT_FEATURES: Lint = Lint {
242
305
pub fn check_implicit_features (
243
306
pkg : & Package ,
244
307
path : & Path ,
245
- lints : & TomlToolLints ,
308
+ pkg_lints : & TomlToolLints ,
309
+ ws_lints : & TomlToolLints ,
246
310
error_count : & mut usize ,
247
311
gctx : & GlobalContext ,
248
312
) -> CargoResult < ( ) > {
@@ -253,7 +317,7 @@ pub fn check_implicit_features(
253
317
return Ok ( ( ) ) ;
254
318
}
255
319
256
- let lint_level = IMPLICIT_FEATURES . level ( lints , edition) ;
320
+ let ( lint_level, reason ) = IMPLICIT_FEATURES . level ( pkg_lints , ws_lints , edition) ;
257
321
if lint_level == LintLevel :: Allow {
258
322
return Ok ( ( ) ) ;
259
323
}
@@ -298,7 +362,7 @@ pub fn check_implicit_features(
298
362
) ;
299
363
if emitted_source. is_none ( ) {
300
364
emitted_source = Some ( format ! (
301
- "`cargo::{}` is set to `{lint_level}`" ,
365
+ "`cargo::{}` is set to `{lint_level}` {reason} " ,
302
366
IMPLICIT_FEATURES . name
303
367
) ) ;
304
368
message = message. footer ( Level :: Note . title ( emitted_source. as_ref ( ) . unwrap ( ) ) ) ;
@@ -325,7 +389,8 @@ const UNUSED_OPTIONAL_DEPENDENCY: Lint = Lint {
325
389
pub fn unused_dependencies (
326
390
pkg : & Package ,
327
391
path : & Path ,
328
- lints : & TomlToolLints ,
392
+ pkg_lints : & TomlToolLints ,
393
+ ws_lints : & TomlToolLints ,
329
394
error_count : & mut usize ,
330
395
gctx : & GlobalContext ,
331
396
) -> CargoResult < ( ) > {
@@ -335,7 +400,7 @@ pub fn unused_dependencies(
335
400
return Ok ( ( ) ) ;
336
401
}
337
402
338
- let lint_level = UNUSED_OPTIONAL_DEPENDENCY . level ( lints , edition) ;
403
+ let ( lint_level, reason ) = UNUSED_OPTIONAL_DEPENDENCY . level ( pkg_lints , ws_lints , edition) ;
339
404
if lint_level == LintLevel :: Allow {
340
405
return Ok ( ( ) ) ;
341
406
}
@@ -401,7 +466,7 @@ pub fn unused_dependencies(
401
466
) ;
402
467
if emitted_source. is_none ( ) {
403
468
emitted_source = Some ( format ! (
404
- "`cargo::{}` is set to `{lint_level}`" ,
469
+ "`cargo::{}` is set to `{lint_level}` {reason} " ,
405
470
UNUSED_OPTIONAL_DEPENDENCY . name
406
471
) ) ;
407
472
message =
0 commit comments