1
1
use crate :: clippy_project_root;
2
+ use indoc:: indoc;
2
3
use std:: fs:: { self , OpenOptions } ;
3
4
use std:: io:: prelude:: * ;
4
5
use std:: io:: { self , ErrorKind } ;
@@ -32,37 +33,20 @@ impl<T> Context for io::Result<T> {
32
33
/// # Errors
33
34
///
34
35
/// This function errors out if the files couldn't be created or written to.
35
- pub fn create ( pass : Option < & str > , lint_name : Option < & str > , category : Option < & str > ) -> io:: Result < ( ) > {
36
+ pub fn create ( pass : Option < & str > , lint_name : Option < & str > , category : Option < & str > , msrv : bool ) -> io:: Result < ( ) > {
36
37
let lint = LintData {
37
38
pass : pass. expect ( "`pass` argument is validated by clap" ) ,
38
39
name : lint_name. expect ( "`name` argument is validated by clap" ) ,
39
40
category : category. expect ( "`category` argument is validated by clap" ) ,
40
41
project_root : clippy_project_root ( ) ,
41
42
} ;
42
43
43
- create_lint ( & lint) . context ( "Unable to create lint implementation" ) ?;
44
+ create_lint ( & lint, msrv ) . context ( "Unable to create lint implementation" ) ?;
44
45
create_test ( & lint) . context ( "Unable to create a test for the new lint" )
45
46
}
46
47
47
- fn create_lint ( lint : & LintData < ' _ > ) -> io:: Result < ( ) > {
48
- let ( pass_type, pass_lifetimes, pass_import, context_import) = match lint. pass {
49
- "early" => ( "EarlyLintPass" , "" , "use rustc_ast::ast::*;" , "EarlyContext" ) ,
50
- "late" => ( "LateLintPass" , "<'_>" , "use rustc_hir::*;" , "LateContext" ) ,
51
- _ => {
52
- unreachable ! ( "`pass_type` should only ever be `early` or `late`!" ) ;
53
- } ,
54
- } ;
55
-
56
- let camel_case_name = to_camel_case ( lint. name ) ;
57
- let lint_contents = get_lint_file_contents (
58
- pass_type,
59
- pass_lifetimes,
60
- lint. name ,
61
- & camel_case_name,
62
- lint. category ,
63
- pass_import,
64
- context_import,
65
- ) ;
48
+ fn create_lint ( lint : & LintData < ' _ > , enable_msrv : bool ) -> io:: Result < ( ) > {
49
+ let lint_contents = get_lint_file_contents ( lint, enable_msrv) ;
66
50
67
51
let lint_path = format ! ( "clippy_lints/src/{}.rs" , lint. name) ;
68
52
write_file ( lint. project_root . join ( & lint_path) , lint_contents. as_bytes ( ) )
@@ -122,12 +106,13 @@ fn to_camel_case(name: &str) -> String {
122
106
123
107
fn get_test_file_contents ( lint_name : & str , header_commands : Option < & str > ) -> String {
124
108
let mut contents = format ! (
125
- "#![warn(clippy::{})]
109
+ indoc! { "
110
+ #![warn(clippy::{})]
126
111
127
- fn main() {{
128
- // test code goes here
129
- }}
130
- " ,
112
+ fn main() {{
113
+ // test code goes here
114
+ }}
115
+ " } ,
131
116
lint_name
132
117
) ;
133
118
@@ -140,64 +125,143 @@ fn main() {{
140
125
141
126
fn get_manifest_contents ( lint_name : & str , hint : & str ) -> String {
142
127
format ! (
143
- r#"
144
- # {}
128
+ indoc! { r#"
129
+ # {}
145
130
146
- [package]
147
- name = "{}"
148
- version = "0.1.0"
149
- publish = false
131
+ [package]
132
+ name = "{}"
133
+ version = "0.1.0"
134
+ publish = false
150
135
151
- [workspace]
152
- "# ,
136
+ [workspace]
137
+ "# } ,
153
138
hint, lint_name
154
139
)
155
140
}
156
141
157
- fn get_lint_file_contents (
158
- pass_type : & str ,
159
- pass_lifetimes : & str ,
160
- lint_name : & str ,
161
- camel_case_name : & str ,
162
- category : & str ,
163
- pass_import : & str ,
164
- context_import : & str ,
165
- ) -> String {
166
- format ! (
167
- "use rustc_lint::{{{type}, {context_import}}};
168
- use rustc_session::{{declare_lint_pass, declare_tool_lint}};
169
- {pass_import}
170
-
171
- declare_clippy_lint! {{
172
- /// ### What it does
173
- ///
174
- /// ### Why is this bad?
175
- ///
176
- /// ### Example
177
- /// ```rust
178
- /// // example code where clippy issues a warning
179
- /// ```
180
- /// Use instead:
181
- /// ```rust
182
- /// // example code which does not raise clippy warning
183
- /// ```
184
- pub {name_upper},
185
- {category},
186
- \" default lint description\"
187
- }}
188
-
189
- declare_lint_pass!({name_camel} => [{name_upper}]);
190
-
191
- impl {type}{lifetimes} for {name_camel} {{}}
192
- " ,
193
- type =pass_type,
194
- lifetimes=pass_lifetimes,
195
- name_upper=lint_name. to_uppercase( ) ,
196
- name_camel=camel_case_name,
197
- category=category,
198
- pass_import=pass_import,
199
- context_import=context_import
200
- )
142
+ fn get_lint_file_contents ( lint : & LintData < ' _ > , enable_msrv : bool ) -> String {
143
+ let mut result = String :: new ( ) ;
144
+
145
+ let ( pass_type, pass_lifetimes, pass_import, context_import) = match lint. pass {
146
+ "early" => ( "EarlyLintPass" , "" , "use rustc_ast::ast::*;" , "EarlyContext" ) ,
147
+ "late" => ( "LateLintPass" , "<'_>" , "use rustc_hir::*;" , "LateContext" ) ,
148
+ _ => {
149
+ unreachable ! ( "`pass_type` should only ever be `early` or `late`!" ) ;
150
+ } ,
151
+ } ;
152
+
153
+ let lint_name = lint. name ;
154
+ let pass_name = lint. pass ;
155
+ let category = lint. category ;
156
+ let name_camel = to_camel_case ( lint. name ) ;
157
+ let name_upper = lint_name. to_uppercase ( ) ;
158
+
159
+ result. push_str ( & if enable_msrv {
160
+ format ! (
161
+ indoc! { "
162
+ use clippy_utils::msrvs;
163
+ {pass_import}
164
+ use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
165
+ use rustc_semver::RustcVersion;
166
+ use rustc_session::{{declare_tool_lint, impl_lint_pass}};
167
+
168
+ " } ,
169
+ pass_type = pass_type,
170
+ pass_import = pass_import,
171
+ context_import = context_import,
172
+ )
173
+ } else {
174
+ format ! (
175
+ indoc! { "
176
+ {pass_import}
177
+ use rustc_lint::{{{context_import}, {pass_type}}};
178
+ use rustc_session::{{declare_lint_pass, declare_tool_lint}};
179
+
180
+ " } ,
181
+ pass_import = pass_import,
182
+ pass_type = pass_type,
183
+ context_import = context_import
184
+ )
185
+ } ) ;
186
+
187
+ result. push_str ( & format ! (
188
+ indoc! { "
189
+ declare_clippy_lint! {{
190
+ /// ### What it does
191
+ ///
192
+ /// ### Why is this bad?
193
+ ///
194
+ /// ### Example
195
+ /// ```rust
196
+ /// // example code where clippy issues a warning
197
+ /// ```
198
+ /// Use instead:
199
+ /// ```rust
200
+ /// // example code which does not raise clippy warning
201
+ /// ```
202
+ pub {name_upper},
203
+ {category},
204
+ \" default lint description\"
205
+ }}
206
+ " } ,
207
+ name_upper = name_upper,
208
+ category = category,
209
+ ) ) ;
210
+
211
+ result. push_str ( & if enable_msrv {
212
+ format ! (
213
+ indoc! { "
214
+ pub struct {name_camel} {{
215
+ msrv: Option<RustcVersion>,
216
+ }}
217
+
218
+ impl {name_camel} {{
219
+ #[must_use]
220
+ pub fn new(msrv: Option<RustcVersion>) -> Self {{
221
+ Self {{ msrv }}
222
+ }}
223
+ }}
224
+
225
+ impl_lint_pass!({name_camel} => [{name_upper}]);
226
+
227
+ impl {pass_type}{pass_lifetimes} for {name_camel} {{
228
+ extract_msrv_attr!({context_import});
229
+ }}
230
+
231
+ // TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
232
+ // e.g. store.register_{pass_name}_pass(move || Box::new({module_name}::{name_camel}::new(msrv)));
233
+ // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
234
+ // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`.
235
+ // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
236
+ " } ,
237
+ pass_type = pass_type,
238
+ pass_lifetimes = pass_lifetimes,
239
+ pass_name = pass_name,
240
+ name_upper = name_upper,
241
+ name_camel = name_camel,
242
+ module_name = lint_name,
243
+ context_import = context_import,
244
+ )
245
+ } else {
246
+ format ! (
247
+ indoc! { "
248
+ declare_lint_pass!({name_camel} => [{name_upper}]);
249
+
250
+ impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
251
+ //
252
+ // TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
253
+ // e.g. store.register_{pass_name}_pass(|| Box::new({module_name}::{name_camel}));
254
+ " } ,
255
+ pass_type = pass_type,
256
+ pass_lifetimes = pass_lifetimes,
257
+ pass_name = pass_name,
258
+ name_upper = name_upper,
259
+ name_camel = name_camel,
260
+ module_name = lint_name,
261
+ )
262
+ } ) ;
263
+
264
+ result
201
265
}
202
266
203
267
#[ test]
0 commit comments