@@ -68,6 +68,13 @@ pub struct LintGroup {
68
68
pub edition_lint_opts : Option < ( Edition , LintLevel ) > ,
69
69
}
70
70
71
+ const TEST_DUMMY_UNSTABLE : LintGroup = LintGroup {
72
+ name : "test_dummy_unstable" ,
73
+ desc : "test_dummy_unstable is meant to only be used in tests" ,
74
+ default_level : LintLevel :: Allow ,
75
+ edition_lint_opts : None ,
76
+ } ;
77
+
71
78
#[ derive( Copy , Clone , Debug ) ]
72
79
pub struct Lint {
73
80
pub name : & ' static str ,
@@ -79,23 +86,37 @@ pub struct Lint {
79
86
80
87
impl Lint {
81
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
+
82
98
let level = self
83
99
. groups
84
100
. iter ( )
85
101
. map ( |g| g. name )
86
102
. chain ( std:: iter:: once ( self . name ) )
87
103
. filter_map ( |n| lints. get ( n) . map ( |l| ( n, l) ) )
88
- . max_by_key ( |( n, l) | ( l. priority ( ) , std:: cmp:: Reverse ( * n) ) ) ;
104
+ . max_by_key ( |( n, l) | {
105
+ (
106
+ l. level ( ) == TomlLintLevel :: Forbid ,
107
+ l. priority ( ) ,
108
+ std:: cmp:: Reverse ( * n) ,
109
+ )
110
+ } ) ;
89
111
90
112
match level {
91
113
Some ( ( _, toml_lint) ) => toml_lint. level ( ) . into ( ) ,
92
114
None => {
93
- if let Some ( ( lint_edition , lint_level ) ) = self . edition_lint_opts {
94
- if edition >= lint_edition {
95
- return lint_level ;
96
- }
115
+ if let Some ( level ) = edition_level {
116
+ level
117
+ } else {
118
+ self . default_level
97
119
}
98
- self . default_level
99
120
}
100
121
}
101
122
}
@@ -123,7 +144,7 @@ impl Display for LintLevel {
123
144
impl LintLevel {
124
145
pub fn to_diagnostic_level ( self ) -> Level {
125
146
match self {
126
- LintLevel :: Allow => Level :: Note ,
147
+ LintLevel :: Allow => unreachable ! ( "allow does not map to a diagnostic level" ) ,
127
148
LintLevel :: Warn => Level :: Warning ,
128
149
LintLevel :: Deny => Level :: Error ,
129
150
LintLevel :: Forbid => Level :: Error ,
@@ -142,6 +163,61 @@ impl From<TomlLintLevel> for LintLevel {
142
163
}
143
164
}
144
165
166
+ const IM_A_TEAPOT : Lint = Lint {
167
+ name : "im_a_teapot" ,
168
+ desc : "`im_a_teapot` is specified" ,
169
+ groups : & [ TEST_DUMMY_UNSTABLE ] ,
170
+ default_level : LintLevel :: Allow ,
171
+ edition_lint_opts : None ,
172
+ } ;
173
+
174
+ pub fn check_im_a_teapot (
175
+ pkg : & Package ,
176
+ path : & Path ,
177
+ lints : & TomlToolLints ,
178
+ error_count : & mut usize ,
179
+ gctx : & GlobalContext ,
180
+ ) -> CargoResult < ( ) > {
181
+ let manifest = pkg. manifest ( ) ;
182
+ let lint_level = IM_A_TEAPOT . level ( lints, manifest. edition ( ) ) ;
183
+ if lint_level == LintLevel :: Allow {
184
+ return Ok ( ( ) ) ;
185
+ }
186
+
187
+ if manifest
188
+ . resolved_toml ( )
189
+ . package ( )
190
+ . is_some_and ( |p| p. im_a_teapot . is_some ( ) )
191
+ {
192
+ if lint_level == LintLevel :: Forbid || lint_level == LintLevel :: Deny {
193
+ * error_count += 1 ;
194
+ }
195
+ let level = lint_level. to_diagnostic_level ( ) ;
196
+ let manifest_path = rel_cwd_manifest_path ( path, gctx) ;
197
+ let emitted_reason = format ! ( "`cargo::{}` is set to `{lint_level}`" , IM_A_TEAPOT . name) ;
198
+
199
+ let key_span = get_span ( manifest. document ( ) , & [ "package" , "im-a-teapot" ] , false ) . unwrap ( ) ;
200
+ let value_span = get_span ( manifest. document ( ) , & [ "package" , "im-a-teapot" ] , true ) . unwrap ( ) ;
201
+ let message = level
202
+ . title ( IM_A_TEAPOT . desc )
203
+ . snippet (
204
+ Snippet :: source ( manifest. contents ( ) )
205
+ . origin ( & manifest_path)
206
+ . annotation ( level. span ( key_span. start ..value_span. end ) )
207
+ . fold ( true ) ,
208
+ )
209
+ . footer ( Level :: Note . title ( & emitted_reason) ) ;
210
+ let renderer = Renderer :: styled ( ) . term_width (
211
+ gctx. shell ( )
212
+ . err_width ( )
213
+ . diagnostic_terminal_width ( )
214
+ . unwrap_or ( annotate_snippets:: renderer:: DEFAULT_TERM_WIDTH ) ,
215
+ ) ;
216
+ writeln ! ( gctx. shell( ) . err( ) , "{}" , renderer. render( message) ) ?;
217
+ }
218
+ Ok ( ( ) )
219
+ }
220
+
145
221
/// By default, cargo will treat any optional dependency as a [feature]. As of
146
222
/// cargo 1.60, these can be disabled by declaring a feature that activates the
147
223
/// optional dependency as `dep:<name>` (see [RFC #3143]).
0 commit comments