diff --git a/Cargo.lock b/Cargo.lock index 00351c12410..552b446a1e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5598,6 +5598,7 @@ dependencies = [ "lazy_static", "miropt-test-tools", "regex", + "rustc-hash", "semver", "termcolor", "walkdir", diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 58302b8e63b..96866e74248 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -13,7 +13,9 @@ walkdir = "2" ignore = "0.4.18" semver = "1.0" termcolor = "1.1.3" +rustc-hash = "1.1.0" [[bin]] name = "rust-tidy" path = "src/main.rs" +test = false diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 28d70b4454c..a1445ce5896 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -19,8 +19,12 @@ use crate::walk::{filter_dirs, walk}; use regex::{Regex, RegexSet}; +use rustc_hash::FxHashMap; use std::{ffi::OsStr, path::Path}; +#[cfg(test)] +mod tests; + /// Error code markdown is restricted to 80 columns because they can be /// displayed on the console with --example. const ERROR_CODE_COLS: usize = 80; @@ -65,12 +69,56 @@ const ANNOTATIONS_TO_IGNORE: &[&str] = &[ "//@ normalize-stderr-test", ]; +fn generate_problems<'a>( + consts: &'a [u32], + letter_digit: &'a FxHashMap, +) -> impl Iterator + 'a { + consts.iter().flat_map(move |const_value| { + let problem = + letter_digit.iter().fold(format!("{:X}", const_value), |acc, (key, value)| { + acc.replace(&value.to_string(), &key.to_string()) + }); + let indexes: Vec = problem + .chars() + .enumerate() + .filter_map(|(index, c)| if letter_digit.contains_key(&c) { Some(index) } else { None }) + .collect(); + (0..1 << indexes.len()).map(move |i| { + u32::from_str_radix( + &problem + .chars() + .enumerate() + .map(|(index, c)| { + if let Some(pos) = indexes.iter().position(|&x| x == index) { + if (i >> pos) & 1 == 1 { letter_digit[&c] } else { c } + } else { + c + } + }) + .collect::(), + 0x10, + ) + .unwrap() + }) + }) +} + // Intentionally written in decimal rather than hex -const PROBLEMATIC_CONSTS: &[u32] = &[ +const ROOT_PROBLEMATIC_CONSTS: &[u32] = &[ 184594741, 2880289470, 2881141438, 2965027518, 2976579765, 3203381950, 3405691582, 3405697037, - 3735927486, 3735932941, 4027431614, 4276992702, + 3735927486, 3735932941, 4027431614, 4276992702, 195934910, 252707358, 762133, 179681982, + 173390526, 721077, ]; +fn generate_problematic_strings( + consts: &[u32], + letter_digit: &FxHashMap, +) -> Vec { + generate_problems(consts, letter_digit) + .flat_map(|v| vec![v.to_string(), format!("{:x}", v), format!("{:X}", v)]) + .collect() +} + const INTERNAL_COMPILER_DOCS_LINE: &str = "#### This error code is internal to the compiler and will not be emitted with normal Rust code."; /// Parser states for `line_is_url`. @@ -267,11 +315,10 @@ pub fn check(path: &Path, bad: &mut bool) { // We only check CSS files in rustdoc. path.extension().map_or(false, |e| e == "css") && !is_in(path, "src", "librustdoc") } - - let problematic_consts_strings: Vec = (PROBLEMATIC_CONSTS.iter().map(u32::to_string)) - .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:x}", v))) - .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:X}", v))) - .collect(); + let problematic_consts_strings = generate_problematic_strings( + ROOT_PROBLEMATIC_CONSTS, + &[('A', '4'), ('B', '8'), ('E', '3')].iter().cloned().collect(), + ); let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap(); walk(path, skip, &mut |entry, contents| { diff --git a/src/tools/tidy/src/style/tests.rs b/src/tools/tidy/src/style/tests.rs new file mode 100644 index 00000000000..292e23916d2 --- /dev/null +++ b/src/tools/tidy/src/style/tests.rs @@ -0,0 +1,17 @@ +use super::*; + +#[test] +fn test_generate_problematic_strings() { + let problematic_regex = RegexSet::new( + generate_problematic_strings( + ROOT_PROBLEMATIC_CONSTS, + &[('A', '4'), ('B', '8'), ('E', '3'), ('0', 'F')].iter().cloned().collect(), // use "futile" F intentionally + ) + .as_slice(), + ) + .unwrap(); + assert!(problematic_regex.is_match("786357")); // check with no "decimal" hex digits - converted to integer + assert!(problematic_regex.is_match("589701")); // check with "decimal" replacements - converted to integer + assert!(problematic_regex.is_match("8FF85")); // check for hex display + assert!(!problematic_regex.is_match("1193046")); // check for non-matching value +}