From bd778e216d3c58049fe0259ce5c8e8fd45cfcbd6 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 25 Oct 2021 18:14:54 +0100 Subject: [PATCH] Register the generated lints from `cargo dev new_lint` --- clippy_dev/src/new_lint.rs | 40 +++++++++++++++++++++++---------- clippy_lints/src/lib.rs | 2 +- doc/adding_lints.md | 45 ++++++++++++++++++++------------------ 3 files changed, 54 insertions(+), 33 deletions(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 25320907bb4..43a478ee77d 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -42,7 +42,8 @@ pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str }; create_lint(&lint, msrv).context("Unable to create lint implementation")?; - create_test(&lint).context("Unable to create a test for the new lint") + create_test(&lint).context("Unable to create a test for the new lint")?; + add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs") } fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { @@ -80,6 +81,33 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> { } } +fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { + let path = "clippy_lints/src/lib.rs"; + let mut lib_rs = fs::read_to_string(path).context("reading")?; + + let comment_start = lib_rs.find("// add lints here,").expect("Couldn't find comment"); + + let new_lint = if enable_msrv { + format!( + "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n ", + lint_pass = lint.pass, + module_name = lint.name, + camel_name = to_camel_case(lint.name), + ) + } else { + format!( + "store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n ", + lint_pass = lint.pass, + module_name = lint.name, + camel_name = to_camel_case(lint.name), + ) + }; + + lib_rs.insert_str(comment_start, &new_lint); + + fs::write(path, lib_rs).context("writing") +} + fn write_file, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { fn inner(path: &Path, contents: &[u8]) -> io::Result<()> { OpenOptions::new() @@ -151,7 +179,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }; let lint_name = lint.name; - let pass_name = lint.pass; let category = lint.category; let name_camel = to_camel_case(lint.name); let name_upper = lint_name.to_uppercase(); @@ -228,18 +255,14 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { extract_msrv_attr!({context_import}); }} - // TODO: Register the lint pass in `clippy_lints/src/lib.rs`, - // e.g. store.register_{pass_name}_pass(move || Box::new({module_name}::{name_camel}::new(msrv))); // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed. // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`. // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs` "}, pass_type = pass_type, pass_lifetimes = pass_lifetimes, - pass_name = pass_name, name_upper = name_upper, name_camel = name_camel, - module_name = lint_name, context_import = context_import, ) } else { @@ -248,16 +271,11 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { declare_lint_pass!({name_camel} => [{name_upper}]); impl {pass_type}{pass_lifetimes} for {name_camel} {{}} - // - // TODO: Register the lint pass in `clippy_lints/src/lib.rs`, - // e.g. store.register_{pass_name}_pass(|| Box::new({module_name}::{name_camel})); "}, pass_type = pass_type, pass_lifetimes = pass_lifetimes, - pass_name = pass_name, name_upper = name_upper, name_camel = name_camel, - module_name = lint_name, ) }); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ed7e8277023..86f9d75c06f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -777,7 +777,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch)); store.register_late_pass(move || Box::new(format_args::FormatArgs)); store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray)); - + // add lints here, do not remove this comment, it's used in `new_lint` } #[rustfmt::skip] diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 004eb28b446..0e112e37cbc 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -16,6 +16,7 @@ because that's clearly a non-descriptive name. - [Edition 2018 tests](#edition-2018-tests) - [Testing manually](#testing-manually) - [Lint declaration](#lint-declaration) + - [Lint registration](#lint-registration) - [Lint passes](#lint-passes) - [Emitting a lint](#emitting-a-lint) - [Adding the lint logic](#adding-the-lint-logic) @@ -43,9 +44,9 @@ take a look at our [lint naming guidelines][lint_naming]. To get started on this lint you can run `cargo dev new_lint --name=foo_functions --pass=early --category=pedantic` (category will default to nursery if not provided). This command will create two files: `tests/ui/foo_functions.rs` and -`clippy_lints/src/foo_functions.rs`, as well as run `cargo dev update_lints` to -register the new lint. For cargo lints, two project hierarchies (fail/pass) will -be created by default under `tests/ui-cargo`. +`clippy_lints/src/foo_functions.rs`, as well as +[registering the lint](#lint-registration). For cargo lints, two project +hierarchies (fail/pass) will be created by default under `tests/ui-cargo`. Next, we'll open up these files and add our lint! @@ -220,32 +221,34 @@ declare_lint_pass!(FooFunctions => [FOO_FUNCTIONS]); impl EarlyLintPass for FooFunctions {} ``` -Normally after declaring the lint, we have to run `cargo dev update_lints`, -which updates some files, so Clippy knows about the new lint. Since we used -`cargo dev new_lint ...` to generate the lint declaration, this was done -automatically. While `update_lints` automates most of the things, it doesn't -automate everything. We will have to register our lint pass manually in the -`register_plugins` function in `clippy_lints/src/lib.rs`: +[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60 +[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure +[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints +[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110 + +## Lint registration + +When using `cargo dev new_lint`, the lint is automatically registered and +nothing more has to be done. + +When declaring a new lint by hand and `cargo dev update_lints` is used, the lint +pass may have to be registered manually in the `register_plugins` function in +`clippy_lints/src/lib.rs`: ```rust -store.register_early_pass(|| box foo_functions::FooFunctions); +store.register_early_pass(|| Box::new(foo_functions::FooFunctions)); ``` As one may expect, there is a corresponding `register_late_pass` method available as well. Without a call to one of `register_early_pass` or `register_late_pass`, the lint pass in question will not be run. -One reason that `cargo dev` does not automate this step is that multiple lints -can use the same lint pass, so registering the lint pass may already be done -when adding a new lint. Another reason that this step is not automated is that -the order that the passes are registered determines the order the passes -actually run, which in turn affects the order that any emitted lints are output -in. - -[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60 -[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure -[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints -[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110 +One reason that `cargo dev update_lints` does not automate this step is that +multiple lints can use the same lint pass, so registering the lint pass may +already be done when adding a new lint. Another reason that this step is not +automated is that the order that the passes are registered determines the order +the passes actually run, which in turn affects the order that any emitted lints +are output in. ## Lint passes