Skip to content

Commit 7272366

Browse files
committed
Auto merge of #7793 - mikerite:new_lint-msrv-2, r=Manishearth
Add option to `new_lint` to generate MSRV enabled lint changelog: none
2 parents bc9ad84 + 7d9b21b commit 7272366

File tree

3 files changed

+149
-78
lines changed

3 files changed

+149
-78
lines changed

clippy_dev/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2021"
66
[dependencies]
77
bytecount = "0.6"
88
clap = "2.33"
9+
indoc = "1.0"
910
itertools = "0.10"
1011
opener = "0.5"
1112
regex = "1.5"

clippy_dev/src/main.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ fn main() {
2828
matches.value_of("pass"),
2929
matches.value_of("name"),
3030
matches.value_of("category"),
31+
matches.is_present("msrv"),
3132
) {
3233
Ok(_) => update_lints::run(update_lints::UpdateMode::Change),
3334
Err(e) => eprintln!("Unable to create lint: {}", e),
@@ -147,6 +148,11 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
147148
"internal_warn",
148149
])
149150
.takes_value(true),
151+
)
152+
.arg(
153+
Arg::with_name("msrv")
154+
.long("msrv")
155+
.help("Add MSRV config code to the lint"),
150156
),
151157
)
152158
.subcommand(

clippy_dev/src/new_lint.rs

Lines changed: 142 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::clippy_project_root;
2+
use indoc::indoc;
23
use std::fs::{self, OpenOptions};
34
use std::io::prelude::*;
45
use std::io::{self, ErrorKind};
@@ -32,37 +33,20 @@ impl<T> Context for io::Result<T> {
3233
/// # Errors
3334
///
3435
/// 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<()> {
3637
let lint = LintData {
3738
pass: pass.expect("`pass` argument is validated by clap"),
3839
name: lint_name.expect("`name` argument is validated by clap"),
3940
category: category.expect("`category` argument is validated by clap"),
4041
project_root: clippy_project_root(),
4142
};
4243

43-
create_lint(&lint).context("Unable to create lint implementation")?;
44+
create_lint(&lint, msrv).context("Unable to create lint implementation")?;
4445
create_test(&lint).context("Unable to create a test for the new lint")
4546
}
4647

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);
6650

6751
let lint_path = format!("clippy_lints/src/{}.rs", lint.name);
6852
write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())
@@ -122,12 +106,13 @@ fn to_camel_case(name: &str) -> String {
122106

123107
fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
124108
let mut contents = format!(
125-
"#![warn(clippy::{})]
109+
indoc! {"
110+
#![warn(clippy::{})]
126111
127-
fn main() {{
128-
// test code goes here
129-
}}
130-
",
112+
fn main() {{
113+
// test code goes here
114+
}}
115+
"},
131116
lint_name
132117
);
133118

@@ -140,64 +125,143 @@ fn main() {{
140125

141126
fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
142127
format!(
143-
r#"
144-
# {}
128+
indoc! {r#"
129+
# {}
145130
146-
[package]
147-
name = "{}"
148-
version = "0.1.0"
149-
publish = false
131+
[package]
132+
name = "{}"
133+
version = "0.1.0"
134+
publish = false
150135
151-
[workspace]
152-
"#,
136+
[workspace]
137+
"#},
153138
hint, lint_name
154139
)
155140
}
156141

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
201265
}
202266

203267
#[test]

0 commit comments

Comments
 (0)