diff --git a/ci/base-tests.sh b/ci/base-tests.sh index f46c558f24d..0ed1494be82 100755 --- a/ci/base-tests.sh +++ b/ci/base-tests.sh @@ -22,6 +22,7 @@ cargo build --features debugging cargo test --features debugging cd clippy_lints && cargo test && cd .. cd rustc_tools_util && cargo test && cd .. +cd clippy_dev && cargo test && cd .. # check that the lint lists are up-to-date ./util/update_lints.py -c diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 370b8cf630a..2ae8423381d 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -71,6 +71,32 @@ impl Lint { } } +/// Generates the Vec items for `register_lint_group` calls in `clippy_lints/src/lib.rs`. +pub fn gen_lint_group_list(lints: Vec) -> Vec { + lints.into_iter() + .filter_map(|l| { + if l.is_internal() || l.deprecation.is_some() { + None + } else { + Some(format!(" {}::{},", l.module, l.name.to_uppercase())) + } + }) + .sorted() +} + +/// Generates the `pub mod module_name` list in `clippy_lints/src/lib.rs`. +pub fn gen_modules_list(lints: Vec) -> Vec { + lints.into_iter() + .filter_map(|l| { + if l.is_internal() || l.deprecation.is_some() { None } else { Some(l.module) } + }) + .unique() + .map(|module| { + format!("pub mod {};", module) + }) + .sorted() +} + /// Generates the list of lint links at the bottom of the README pub fn gen_changelog_lint_list(lints: Vec) -> Vec { let mut lint_list_sorted: Vec = lints; @@ -112,7 +138,13 @@ fn gather_from_file(dir_entry: &walkdir::DirEntry) -> impl Iterator { let mut file = fs::File::open(dir_entry.path()).unwrap(); let mut content = String::new(); file.read_to_string(&mut content).unwrap(); - parse_contents(&content, dir_entry.path().file_stem().unwrap().to_str().unwrap()) + let mut filename = dir_entry.path().file_stem().unwrap().to_str().unwrap(); + // If the lints are stored in mod.rs, we get the module name from + // the containing directory: + if filename == "mod" { + filename = dir_entry.path().parent().unwrap().file_stem().unwrap().to_str().unwrap() + } + parse_contents(&content, filename) } fn parse_contents(content: &str, filename: &str) -> impl Iterator { @@ -214,7 +246,7 @@ pub fn replace_region_in_text(text: &str, start: &str, end: &str, replace_sta // This happens if the provided regex in `clippy_dev/src/main.rs` is not found in the // given text or file. Most likely this is an error on the programmer's side and the Regex // is incorrect. - println!("regex {:?} not found. You may have to update it.", start); + eprintln!("error: regex `{:?}` not found. You may have to update it.", start); } new_lines.join("\n") } @@ -355,3 +387,33 @@ fn test_gen_deprecated() { ]; assert_eq!(expected, gen_deprecated(&lints)); } + +#[test] +fn test_gen_modules_list() { + let lints = vec![ + Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), + Lint::new("should_assert_eq2", "group2", "abc", Some("abc"), "deprecated"), + Lint::new("incorrect_stuff", "group3", "abc", None, "another_module"), + Lint::new("incorrect_internal", "internal_style", "abc", None, "module_name"), + ]; + let expected = vec![ + "pub mod another_module;".to_string(), + "pub mod module_name;".to_string(), + ]; + assert_eq!(expected, gen_modules_list(lints)); +} + +#[test] +fn test_gen_lint_group_list() { + let lints = vec![ + Lint::new("abc", "group1", "abc", None, "module_name"), + Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), + Lint::new("should_assert_eq2", "group2", "abc", Some("abc"), "deprecated"), + Lint::new("incorrect_internal", "internal_style", "abc", None, "module_name"), + ]; + let expected = vec![ + " module_name::ABC,".to_string(), + " module_name::SHOULD_ASSERT_EQ,".to_string(), + ]; + assert_eq!(expected, gen_lint_group_list(lints)); +} diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 887a4ab9328..288fb7c58b4 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -19,12 +19,17 @@ fn main() { let matches = App::new("Clippy developer tooling") .subcommand( SubCommand::with_name("update_lints") - .about("Update the lint list") + .about("Makes sure that:\n \ + * the lint count in README.md is correct\n \ + * the changelog contains markdown link references at the bottom\n \ + * all lint groups include the correct lints\n \ + * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \ + * all lints are registered in the lint store") .arg( Arg::with_name("print-only") .long("print-only") .short("p") - .help("Print a table of lints to STDOUT. Does not modify any files."), + .help("Print a table of lints to STDOUT. This does not include deprecated and internal lints. (Does not modify any files)"), ) ) .get_matches(); @@ -90,4 +95,42 @@ fn update_lints() { false, || { gen_deprecated(&lint_list) } ); + + replace_region_in_file( + "../clippy_lints/src/lib.rs", + "begin lints modules", + "end lints modules", + false, + || { gen_modules_list(lint_list.clone()) } + ); + + // Generate lists of lints in the clippy::all lint group + replace_region_in_file( + "../clippy_lints/src/lib.rs", + r#"reg.register_lint_group\("clippy::all""#, + r#"\]\);"#, + false, + || { + // clippy::all should only include the following lint groups: + let all_group_lints = usable_lints.clone().into_iter().filter(|l| { + l.group == "correctness" || + l.group == "style" || + l.group == "complexity" || + l.group == "perf" + }).collect(); + + gen_lint_group_list(all_group_lints) + } + ); + + // Generate the list of lints for all other lint groups + for (lint_group, lints) in Lint::by_lint_group(&usable_lints) { + replace_region_in_file( + "../clippy_lints/src/lib.rs", + &format!("reg.register_lint_group\\(\"clippy::{}\"", lint_group), + r#"\]\);"#, + false, + || { gen_lint_group_list(lints.clone()) } + ); + } }