mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Merge branch 'master' into fix-missing-comma-fp
This commit is contained in:
commit
2353f24095
@ -180,7 +180,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
|
||||
|
||||
The [`rustc_plugin::PluginRegistry`][plugin_registry] provides two methods to register lints: [register_early_lint_pass][reg_early_lint_pass] and [register_late_lint_pass][reg_late_lint_pass].
|
||||
Both take an object that implements an [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass] respectively. This is done in every single lint.
|
||||
It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `util/update_lints.py` and you don't have to add anything by hand. When you are writing your own lint, you can use that script to save you some time.
|
||||
It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `util/dev update_lints` and you don't have to add anything by hand. When you are writing your own lint, you can use that script to save you some time.
|
||||
|
||||
```rust
|
||||
// ./clippy_lints/src/else_if_without_else.rs
|
||||
|
@ -23,8 +23,9 @@ 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
|
||||
|
||||
# Perform various checks for lint registration
|
||||
./util/dev update_lints --check
|
||||
|
||||
CLIPPY="`pwd`/target/debug/cargo-clippy clippy"
|
||||
# run clippy on its own codebase...
|
||||
|
@ -114,19 +114,22 @@ pub fn gen_changelog_lint_list(lints: Vec<Lint>) -> Vec<String> {
|
||||
|
||||
/// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`.
|
||||
pub fn gen_deprecated(lints: &[Lint]) -> Vec<String> {
|
||||
lints.iter()
|
||||
.filter_map(|l| {
|
||||
l.clone().deprecation.and_then(|depr_text| {
|
||||
Some(
|
||||
format!(
|
||||
" store.register_removed(\n \"{}\",\n \"{}\",\n );",
|
||||
l.name,
|
||||
depr_text
|
||||
itertools::flatten(
|
||||
lints
|
||||
.iter()
|
||||
.filter_map(|l| {
|
||||
l.clone().deprecation.and_then(|depr_text| {
|
||||
Some(
|
||||
vec![
|
||||
" store.register_removed(".to_string(),
|
||||
format!(" \"{}\",", l.name),
|
||||
format!(" \"{}\",", depr_text),
|
||||
" );".to_string()
|
||||
]
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
).collect()
|
||||
}
|
||||
|
||||
/// Gathers all files in `src/clippy_lints` and gathers all lints inside
|
||||
@ -168,23 +171,33 @@ fn lint_files() -> impl Iterator<Item=walkdir::DirEntry> {
|
||||
.filter(|f| f.path().extension() == Some(OsStr::new("rs")))
|
||||
}
|
||||
|
||||
/// Whether a file has had its text changed or not
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct FileChange {
|
||||
pub changed: bool,
|
||||
pub new_lines: String,
|
||||
}
|
||||
|
||||
/// Replace a region in a file delimited by two lines matching regexes.
|
||||
///
|
||||
/// `path` is the relative path to the file on which you want to perform the replacement.
|
||||
///
|
||||
/// See `replace_region_in_text` for documentation of the other options.
|
||||
#[allow(clippy::expect_fun_call)]
|
||||
pub fn replace_region_in_file<F>(path: &str, start: &str, end: &str, replace_start: bool, replacements: F) where F: Fn() -> Vec<String> {
|
||||
pub fn replace_region_in_file<F>(path: &str, start: &str, end: &str, replace_start: bool, write_back: bool, replacements: F) -> FileChange where F: Fn() -> Vec<String> {
|
||||
let mut f = fs::File::open(path).expect(&format!("File not found: {}", path));
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents).expect("Something went wrong reading the file");
|
||||
let replaced = replace_region_in_text(&contents, start, end, replace_start, replacements);
|
||||
let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements);
|
||||
|
||||
let mut f = fs::File::create(path).expect(&format!("File not found: {}", path));
|
||||
f.write_all(replaced.as_bytes()).expect("Unable to write file");
|
||||
// Ensure we write the changes with a trailing newline so that
|
||||
// the file has the proper line endings.
|
||||
f.write_all(b"\n").expect("Unable to write file");
|
||||
if write_back {
|
||||
let mut f = fs::File::create(path).expect(&format!("File not found: {}", path));
|
||||
f.write_all(file_change.new_lines.as_bytes()).expect("Unable to write file");
|
||||
// Ensure we write the changes with a trailing newline so that
|
||||
// the file has the proper line endings.
|
||||
f.write_all(b"\n").expect("Unable to write file");
|
||||
}
|
||||
file_change
|
||||
}
|
||||
|
||||
/// Replace a region in a text delimited by two lines matching regexes.
|
||||
@ -213,10 +226,10 @@ pub fn replace_region_in_file<F>(path: &str, start: &str, end: &str, replace_sta
|
||||
/// || {
|
||||
/// vec!["a different".to_string(), "text".to_string()]
|
||||
/// }
|
||||
/// );
|
||||
/// ).new_lines;
|
||||
/// assert_eq!("replace_start\na different\ntext\nreplace_end", result);
|
||||
/// ```
|
||||
pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> String where F: Fn() -> Vec<String> {
|
||||
pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange where F: Fn() -> Vec<String> {
|
||||
let lines = text.lines();
|
||||
let mut in_old_region = false;
|
||||
let mut found = false;
|
||||
@ -224,7 +237,7 @@ pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_sta
|
||||
let start = Regex::new(start).unwrap();
|
||||
let end = Regex::new(end).unwrap();
|
||||
|
||||
for line in lines {
|
||||
for line in lines.clone() {
|
||||
if in_old_region {
|
||||
if end.is_match(&line) {
|
||||
in_old_region = false;
|
||||
@ -248,7 +261,11 @@ pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_sta
|
||||
// is incorrect.
|
||||
eprintln!("error: regex `{:?}` not found. You may have to update it.", start);
|
||||
}
|
||||
new_lines.join("\n")
|
||||
|
||||
FileChange {
|
||||
changed: lines.ne(new_lines.clone()),
|
||||
new_lines: new_lines.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -292,17 +309,11 @@ declare_deprecated_lint! {
|
||||
|
||||
#[test]
|
||||
fn test_replace_region() {
|
||||
let text = r#"
|
||||
abc
|
||||
123
|
||||
789
|
||||
def
|
||||
ghi"#;
|
||||
let expected = r#"
|
||||
abc
|
||||
hello world
|
||||
def
|
||||
ghi"#;
|
||||
let text = "\nabc\n123\n789\ndef\nghi";
|
||||
let expected = FileChange {
|
||||
changed: true,
|
||||
new_lines: "\nabc\nhello world\ndef\nghi".to_string()
|
||||
};
|
||||
let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || {
|
||||
vec!["hello world".to_string()]
|
||||
});
|
||||
@ -311,22 +322,30 @@ ghi"#;
|
||||
|
||||
#[test]
|
||||
fn test_replace_region_with_start() {
|
||||
let text = r#"
|
||||
abc
|
||||
123
|
||||
789
|
||||
def
|
||||
ghi"#;
|
||||
let expected = r#"
|
||||
hello world
|
||||
def
|
||||
ghi"#;
|
||||
let text = "\nabc\n123\n789\ndef\nghi";
|
||||
let expected = FileChange {
|
||||
changed: true,
|
||||
new_lines: "\nhello world\ndef\nghi".to_string()
|
||||
};
|
||||
let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || {
|
||||
vec!["hello world".to_string()]
|
||||
});
|
||||
assert_eq!(expected, result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_replace_region_no_changes() {
|
||||
let text = "123\n456\n789";
|
||||
let expected = FileChange {
|
||||
changed: false,
|
||||
new_lines: "123\n456\n789".to_string()
|
||||
};
|
||||
let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, || {
|
||||
vec![]
|
||||
});
|
||||
assert_eq!(expected, result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_usable_lints() {
|
||||
let lints = vec![
|
||||
@ -377,14 +396,19 @@ fn test_gen_changelog_lint_list() {
|
||||
fn test_gen_deprecated() {
|
||||
let lints = vec![
|
||||
Lint::new("should_assert_eq", "group1", "abc", Some("has been superseeded by should_assert_eq2"), "module_name"),
|
||||
Lint::new("another_deprecated", "group2", "abc", Some("will be removed"), "module_name"),
|
||||
Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")
|
||||
];
|
||||
let expected: Vec<String> = vec![
|
||||
r#" store.register_removed(
|
||||
"should_assert_eq",
|
||||
"has been superseeded by should_assert_eq2",
|
||||
);"#.to_string()
|
||||
];
|
||||
" store.register_removed(",
|
||||
" \"should_assert_eq\",",
|
||||
" \"has been superseeded by should_assert_eq2\",",
|
||||
" );",
|
||||
" store.register_removed(",
|
||||
" \"another_deprecated\",",
|
||||
" \"will be removed\",",
|
||||
" );"
|
||||
].into_iter().map(String::from).collect();
|
||||
assert_eq!(expected, gen_deprecated(&lints));
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,12 @@ extern crate regex;
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use clippy_dev::*;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum UpdateMode {
|
||||
Check,
|
||||
Change
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let matches = App::new("Clippy developer tooling")
|
||||
.subcommand(
|
||||
@ -28,17 +34,23 @@ fn main() {
|
||||
.arg(
|
||||
Arg::with_name("print-only")
|
||||
.long("print-only")
|
||||
.short("p")
|
||||
.help("Print a table of lints to STDOUT. This does not include deprecated and internal lints. (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();
|
||||
.arg(
|
||||
Arg::with_name("check")
|
||||
.long("check")
|
||||
.help("Checks that util/dev update_lints has been run. Used on CI."),
|
||||
)
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("update_lints") {
|
||||
if matches.is_present("print-only") {
|
||||
print_lints();
|
||||
} else if matches.is_present("check") {
|
||||
update_lints(&UpdateMode::Check);
|
||||
} else {
|
||||
update_lints();
|
||||
update_lints(&UpdateMode::Change);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -63,53 +75,58 @@ fn print_lints() {
|
||||
println!("there are {} lints", lint_count);
|
||||
}
|
||||
|
||||
fn update_lints() {
|
||||
fn update_lints(update_mode: &UpdateMode) {
|
||||
let lint_list: Vec<Lint> = gather_all().collect();
|
||||
let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
|
||||
let lint_count = usable_lints.len();
|
||||
|
||||
replace_region_in_file(
|
||||
let mut file_change = replace_region_in_file(
|
||||
"../README.md",
|
||||
r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang-nursery.github.io/rust-clippy/master/index.html\)"#,
|
||||
"",
|
||||
true,
|
||||
update_mode == &UpdateMode::Change,
|
||||
|| {
|
||||
vec", lint_count)
|
||||
]
|
||||
}
|
||||
);
|
||||
).changed;
|
||||
|
||||
replace_region_in_file(
|
||||
file_change |= replace_region_in_file(
|
||||
"../CHANGELOG.md",
|
||||
"<!-- begin autogenerated links to lint list -->",
|
||||
"<!-- end autogenerated links to lint list -->",
|
||||
false,
|
||||
update_mode == &UpdateMode::Change,
|
||||
|| { gen_changelog_lint_list(lint_list.clone()) }
|
||||
);
|
||||
).changed;
|
||||
|
||||
replace_region_in_file(
|
||||
file_change |= replace_region_in_file(
|
||||
"../clippy_lints/src/lib.rs",
|
||||
"begin deprecated lints",
|
||||
"end deprecated lints",
|
||||
false,
|
||||
update_mode == &UpdateMode::Change,
|
||||
|| { gen_deprecated(&lint_list) }
|
||||
);
|
||||
).changed;
|
||||
|
||||
replace_region_in_file(
|
||||
file_change |= replace_region_in_file(
|
||||
"../clippy_lints/src/lib.rs",
|
||||
"begin lints modules",
|
||||
"end lints modules",
|
||||
false,
|
||||
update_mode == &UpdateMode::Change,
|
||||
|| { gen_modules_list(lint_list.clone()) }
|
||||
);
|
||||
).changed;
|
||||
|
||||
// Generate lists of lints in the clippy::all lint group
|
||||
replace_region_in_file(
|
||||
file_change |= replace_region_in_file(
|
||||
"../clippy_lints/src/lib.rs",
|
||||
r#"reg.register_lint_group\("clippy::all""#,
|
||||
r#"\]\);"#,
|
||||
false,
|
||||
update_mode == &UpdateMode::Change,
|
||||
|| {
|
||||
// clippy::all should only include the following lint groups:
|
||||
let all_group_lints = usable_lints.clone().into_iter().filter(|l| {
|
||||
@ -121,16 +138,22 @@ fn update_lints() {
|
||||
|
||||
gen_lint_group_list(all_group_lints)
|
||||
}
|
||||
);
|
||||
).changed;
|
||||
|
||||
// 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(
|
||||
file_change |= replace_region_in_file(
|
||||
"../clippy_lints/src/lib.rs",
|
||||
&format!("reg.register_lint_group\\(\"clippy::{}\"", lint_group),
|
||||
r#"\]\);"#,
|
||||
false,
|
||||
update_mode == &UpdateMode::Change,
|
||||
|| { gen_lint_group_list(lints.clone()) }
|
||||
);
|
||||
).changed;
|
||||
}
|
||||
|
||||
if update_mode == &UpdateMode::Check && file_change {
|
||||
println!("Not all lints defined properly. Please run `util/dev update_lints` to make sure all lints are defined properly.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -548,8 +548,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
|
||||
bytecount::NAIVE_BYTECOUNT,
|
||||
collapsible_if::COLLAPSIBLE_IF,
|
||||
const_static_lifetime::CONST_STATIC_LIFETIME,
|
||||
copies::IF_SAME_THEN_ELSE,
|
||||
copies::IFS_SAME_COND,
|
||||
copies::IF_SAME_THEN_ELSE,
|
||||
cyclomatic_complexity::CYCLOMATIC_COMPLEXITY,
|
||||
derive::DERIVE_HASH_XOR_EQ,
|
||||
double_comparison::DOUBLE_COMPARISONS,
|
||||
@ -743,12 +743,12 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
|
||||
unused_io_amount::UNUSED_IO_AMOUNT,
|
||||
unused_label::UNUSED_LABEL,
|
||||
vec::USELESS_VEC,
|
||||
write::PRINTLN_EMPTY_STRING,
|
||||
write::PRINT_LITERAL,
|
||||
write::PRINT_WITH_NEWLINE,
|
||||
write::PRINTLN_EMPTY_STRING,
|
||||
write::WRITELN_EMPTY_STRING,
|
||||
write::WRITE_LITERAL,
|
||||
write::WRITE_WITH_NEWLINE,
|
||||
write::WRITELN_EMPTY_STRING,
|
||||
zero_div_zero::ZERO_DIVIDED_BY_ZERO,
|
||||
]);
|
||||
|
||||
@ -831,12 +831,12 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
|
||||
types::IMPLICIT_HASHER,
|
||||
types::LET_UNIT_VALUE,
|
||||
unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
|
||||
write::PRINTLN_EMPTY_STRING,
|
||||
write::PRINT_LITERAL,
|
||||
write::PRINT_WITH_NEWLINE,
|
||||
write::PRINTLN_EMPTY_STRING,
|
||||
write::WRITELN_EMPTY_STRING,
|
||||
write::WRITE_LITERAL,
|
||||
write::WRITE_WITH_NEWLINE,
|
||||
write::WRITELN_EMPTY_STRING,
|
||||
]);
|
||||
|
||||
reg.register_lint_group("clippy::complexity", Some("clippy_complexity"), vec![
|
||||
@ -916,8 +916,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
|
||||
bit_mask::BAD_BIT_MASK,
|
||||
bit_mask::INEFFECTIVE_BIT_MASK,
|
||||
booleans::LOGIC_BUG,
|
||||
copies::IF_SAME_THEN_ELSE,
|
||||
copies::IFS_SAME_COND,
|
||||
copies::IF_SAME_THEN_ELSE,
|
||||
derive::DERIVE_HASH_XOR_EQ,
|
||||
drop_forget_ref::DROP_COPY,
|
||||
drop_forget_ref::DROP_REF,
|
||||
|
@ -7,16 +7,15 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! Lints concerned with the grouping of digits with underscores in integral or
|
||||
//! floating-point literal expressions.
|
||||
|
||||
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext};
|
||||
use crate::rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use if_chain::if_chain;
|
||||
use crate::syntax::ast::*;
|
||||
use crate::syntax_pos;
|
||||
use crate::utils::{snippet_opt, span_lint_and_sugg};
|
||||
use if_chain::if_chain;
|
||||
|
||||
/// **What it does:** Warns if a long integral or floating-point constant does
|
||||
/// not contain underscores.
|
||||
@ -41,9 +40,9 @@ declare_clippy_lint! {
|
||||
/// **Why is this bad?** This is most probably a typo
|
||||
///
|
||||
/// **Known problems:**
|
||||
/// - Recommends a signed suffix, even though the number might be too big and an unsigned
|
||||
/// - Recommends a signed suffix, even though the number might be too big and an unsigned
|
||||
/// suffix is required
|
||||
/// - Does not match on `_128` since that is a valid grouping for decimal and octal numbers
|
||||
/// - Does not match on `_128` since that is a valid grouping for decimal and octal numbers
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
@ -168,21 +167,21 @@ impl<'a> DigitInfo<'a> {
|
||||
let len = sans_prefix.len();
|
||||
let mut last_d = '\0';
|
||||
for (d_idx, d) in sans_prefix.char_indices() {
|
||||
let suffix_start = if last_d == '_' {
|
||||
d_idx - 1
|
||||
} else {
|
||||
d_idx
|
||||
};
|
||||
if float && (d == 'f' || d == 'e' || d == 'E') ||
|
||||
!float && (d == 'i' || d == 'u' || is_possible_suffix_index(&sans_prefix, suffix_start, len)) {
|
||||
let (digits, suffix) = sans_prefix.split_at(suffix_start);
|
||||
return Self {
|
||||
digits,
|
||||
radix,
|
||||
prefix,
|
||||
suffix: Some(suffix),
|
||||
float,
|
||||
};
|
||||
let suffix_start = if last_d == '_' { d_idx - 1 } else { d_idx };
|
||||
if float
|
||||
&& (d == 'f'
|
||||
|| is_possible_float_suffix_index(&sans_prefix, suffix_start, len)
|
||||
|| ((d == 'E' || d == 'e') && !has_possible_float_suffix(&sans_prefix)))
|
||||
|| !float && (d == 'i' || d == 'u' || is_possible_suffix_index(&sans_prefix, suffix_start, len))
|
||||
{
|
||||
let (digits, suffix) = sans_prefix.split_at(suffix_start);
|
||||
return Self {
|
||||
digits,
|
||||
radix,
|
||||
prefix,
|
||||
suffix: Some(suffix),
|
||||
float,
|
||||
};
|
||||
}
|
||||
last_d = d
|
||||
}
|
||||
@ -224,18 +223,44 @@ impl<'a> DigitInfo<'a> {
|
||||
.map(|chunk| chunk.iter().collect())
|
||||
.collect::<Vec<String>>()
|
||||
.join("_");
|
||||
let suffix_hint = match self.suffix {
|
||||
Some(suffix) if is_mistyped_float_suffix(suffix) => format!("_f{}", &suffix[1..]),
|
||||
Some(suffix) => suffix.to_string(),
|
||||
None => String::new(),
|
||||
};
|
||||
format!("{}.{}{}", int_part_hint, frac_part_hint, suffix_hint)
|
||||
} else if self.float && (self.digits.contains('E') || self.digits.contains('e')) {
|
||||
let which_e = if self.digits.contains('E') { 'E' } else { 'e' };
|
||||
let parts: Vec<&str> = self.digits.split(which_e).collect();
|
||||
let filtered_digits_vec_0 = parts[0].chars().filter(|&c| c != '_').rev().collect::<Vec<_>>();
|
||||
let filtered_digits_vec_1 = parts[1].chars().filter(|&c| c != '_').rev().collect::<Vec<_>>();
|
||||
let before_e_hint = filtered_digits_vec_0
|
||||
.chunks(group_size)
|
||||
.map(|chunk| chunk.iter().rev().collect())
|
||||
.rev()
|
||||
.collect::<Vec<String>>()
|
||||
.join("_");
|
||||
let after_e_hint = filtered_digits_vec_1
|
||||
.chunks(group_size)
|
||||
.map(|chunk| chunk.iter().rev().collect())
|
||||
.rev()
|
||||
.collect::<Vec<String>>()
|
||||
.join("_");
|
||||
let suffix_hint = match self.suffix {
|
||||
Some(suffix) if is_mistyped_float_suffix(suffix) => format!("_f{}", &suffix[1..]),
|
||||
Some(suffix) => suffix.to_string(),
|
||||
None => String::new(),
|
||||
};
|
||||
format!(
|
||||
"{}.{}{}",
|
||||
int_part_hint,
|
||||
frac_part_hint,
|
||||
self.suffix.unwrap_or("")
|
||||
"{}{}{}{}{}",
|
||||
self.prefix.unwrap_or(""),
|
||||
before_e_hint,
|
||||
which_e,
|
||||
after_e_hint,
|
||||
suffix_hint
|
||||
)
|
||||
} else {
|
||||
let filtered_digits_vec = self.digits
|
||||
.chars()
|
||||
.filter(|&c| c != '_')
|
||||
.rev()
|
||||
.collect::<Vec<_>>();
|
||||
let filtered_digits_vec = self.digits.chars().filter(|&c| c != '_').rev().collect::<Vec<_>>();
|
||||
let mut hint = filtered_digits_vec
|
||||
.chunks(group_size)
|
||||
.map(|chunk| chunk.iter().rev().collect())
|
||||
@ -248,18 +273,11 @@ impl<'a> DigitInfo<'a> {
|
||||
hint = format!("{:0>4}{}", &hint[..nb_digits_to_fill], &hint[nb_digits_to_fill..]);
|
||||
}
|
||||
let suffix_hint = match self.suffix {
|
||||
Some(suffix) if is_mistyped_suffix(suffix) => {
|
||||
format!("_i{}", &suffix[1..])
|
||||
},
|
||||
Some(suffix) if is_mistyped_suffix(suffix) => format!("_i{}", &suffix[1..]),
|
||||
Some(suffix) => suffix.to_string(),
|
||||
None => String::new()
|
||||
None => String::new(),
|
||||
};
|
||||
format!(
|
||||
"{}{}{}",
|
||||
self.prefix.unwrap_or(""),
|
||||
hint,
|
||||
suffix_hint
|
||||
)
|
||||
format!("{}{}{}", self.prefix.unwrap_or(""), hint, suffix_hint)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -269,22 +287,20 @@ enum WarningType {
|
||||
InconsistentDigitGrouping,
|
||||
LargeDigitGroups,
|
||||
DecimalRepresentation,
|
||||
MistypedLiteralSuffix
|
||||
MistypedLiteralSuffix,
|
||||
}
|
||||
|
||||
impl WarningType {
|
||||
crate fn display(&self, grouping_hint: &str, cx: &EarlyContext<'_>, span: syntax_pos::Span) {
|
||||
match self {
|
||||
WarningType::MistypedLiteralSuffix => {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MISTYPED_LITERAL_SUFFIXES,
|
||||
span,
|
||||
"mistyped literal suffix",
|
||||
"did you mean to write",
|
||||
grouping_hint.to_string()
|
||||
)
|
||||
},
|
||||
WarningType::MistypedLiteralSuffix => span_lint_and_sugg(
|
||||
cx,
|
||||
MISTYPED_LITERAL_SUFFIXES,
|
||||
span,
|
||||
"mistyped literal suffix",
|
||||
"did you mean to write",
|
||||
grouping_hint.to_string(),
|
||||
),
|
||||
WarningType::UnreadableLiteral => span_lint_and_sugg(
|
||||
cx,
|
||||
UNREADABLE_LITERAL,
|
||||
@ -380,7 +396,7 @@ impl LiteralDigitGrouping {
|
||||
|
||||
// Lint integral and fractional parts separately, and then check consistency of digit
|
||||
// groups if both pass.
|
||||
let _ = Self::do_lint(parts[0], None)
|
||||
let _ = Self::do_lint(parts[0], digit_info.suffix)
|
||||
.map(|integral_group_size| {
|
||||
if parts.len() > 1 {
|
||||
// Lint the fractional part of literal just like integral part, but reversed.
|
||||
@ -391,11 +407,11 @@ impl LiteralDigitGrouping {
|
||||
fractional_group_size,
|
||||
parts[0].len(),
|
||||
parts[1].len());
|
||||
if !consistent {
|
||||
WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(),
|
||||
cx,
|
||||
lit.span);
|
||||
}
|
||||
if !consistent {
|
||||
WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(),
|
||||
cx,
|
||||
lit.span);
|
||||
}
|
||||
})
|
||||
.map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(),
|
||||
cx,
|
||||
@ -494,9 +510,7 @@ impl EarlyLintPass for LiteralRepresentation {
|
||||
|
||||
impl LiteralRepresentation {
|
||||
pub fn new(threshold: u64) -> Self {
|
||||
Self {
|
||||
threshold,
|
||||
}
|
||||
Self { threshold }
|
||||
}
|
||||
fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
|
||||
// Lint integral literals.
|
||||
@ -529,7 +543,12 @@ impl LiteralRepresentation {
|
||||
fn do_lint(digits: &str) -> Result<(), WarningType> {
|
||||
if digits.len() == 1 {
|
||||
// Lint for 1 digit literals, if someone really sets the threshold that low
|
||||
if digits == "1" || digits == "2" || digits == "4" || digits == "8" || digits == "3" || digits == "7"
|
||||
if digits == "1"
|
||||
|| digits == "2"
|
||||
|| digits == "4"
|
||||
|| digits == "8"
|
||||
|| digits == "3"
|
||||
|| digits == "7"
|
||||
|| digits == "F"
|
||||
{
|
||||
return Err(WarningType::DecimalRepresentation);
|
||||
@ -538,6 +557,7 @@ impl LiteralRepresentation {
|
||||
// Lint for Literals with a hex-representation of 2 or 3 digits
|
||||
let f = &digits[0..1]; // first digit
|
||||
let s = &digits[1..]; // suffix
|
||||
|
||||
// Powers of 2
|
||||
if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && s.chars().all(|c| c == '0'))
|
||||
// Powers of 2 minus 1
|
||||
@ -550,6 +570,7 @@ impl LiteralRepresentation {
|
||||
let f = &digits[0..1]; // first digit
|
||||
let m = &digits[1..digits.len() - 1]; // middle digits, except last
|
||||
let s = &digits[1..]; // suffix
|
||||
|
||||
// Powers of 2 with a margin of +15/-16
|
||||
if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && m.chars().all(|c| c == '0'))
|
||||
|| ((f.eq("1") || f.eq("3") || f.eq("7") || f.eq("F")) && m.chars().all(|c| c == 'F'))
|
||||
@ -570,6 +591,17 @@ fn is_mistyped_suffix(suffix: &str) -> bool {
|
||||
}
|
||||
|
||||
fn is_possible_suffix_index(lit: &str, idx: usize, len: usize) -> bool {
|
||||
((len > 3 && idx == len - 3) || (len > 2 && idx == len - 2)) &&
|
||||
is_mistyped_suffix(lit.split_at(idx).1)
|
||||
((len > 3 && idx == len - 3) || (len > 2 && idx == len - 2)) && is_mistyped_suffix(lit.split_at(idx).1)
|
||||
}
|
||||
|
||||
fn is_mistyped_float_suffix(suffix: &str) -> bool {
|
||||
["_32", "_64"].contains(&suffix)
|
||||
}
|
||||
|
||||
fn is_possible_float_suffix_index(lit: &str, idx: usize, len: usize) -> bool {
|
||||
(len > 3 && idx == len - 3) && is_mistyped_float_suffix(lit.split_at(idx).1)
|
||||
}
|
||||
|
||||
fn has_possible_float_suffix(lit: &str) -> bool {
|
||||
lit.ends_with("_32") || lit.ends_with("_64")
|
||||
}
|
||||
|
@ -1016,7 +1016,7 @@ pub fn get_arg_name(pat: &Pat) -> Option<ast::Name> {
|
||||
}
|
||||
|
||||
pub fn int_bits(tcx: TyCtxt<'_, '_, '_>, ity: ast::IntTy) -> u64 {
|
||||
layout::Integer::from_attr(tcx, attr::IntType::SignedInt(ity)).size().bits()
|
||||
layout::Integer::from_attr(&tcx, attr::IntType::SignedInt(ity)).size().bits()
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
@ -1035,7 +1035,7 @@ pub fn unsext(tcx: TyCtxt<'_, '_, '_>, u: i128, ity: ast::IntTy) -> u128 {
|
||||
|
||||
/// clip unused bytes
|
||||
pub fn clip(tcx: TyCtxt<'_, '_, '_>, u: u128, ity: ast::UintTy) -> u128 {
|
||||
let bits = layout::Integer::from_attr(tcx, attr::IntType::UnsignedInt(ity)).size().bits();
|
||||
let bits = layout::Integer::from_attr(&tcx, attr::IntType::UnsignedInt(ity)).size().bits();
|
||||
let amt = 128 - bits;
|
||||
(u << amt) >> amt
|
||||
}
|
||||
|
@ -7,9 +7,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
|
||||
|
||||
#![warn(clippy::mixed_case_hex_literals)]
|
||||
#![warn(clippy::unseparated_literal_suffix)]
|
||||
#![warn(clippy::zero_prefixed_literal)]
|
||||
@ -64,4 +61,11 @@ fn main() {
|
||||
let fail21 = 4___16;
|
||||
let fail22 = 3__4___23;
|
||||
let fail23 = 3__16___23;
|
||||
|
||||
let fail24 = 12.34_64;
|
||||
let fail25 = 1E2_32;
|
||||
let fail26 = 43E7_64;
|
||||
let fail27 = 243E17_32;
|
||||
let fail28 = 241251235E723_64;
|
||||
let fail29 = 42279.911_32;
|
||||
}
|
||||
|
@ -1,182 +1,218 @@
|
||||
error: inconsistent casing in hexadecimal literal
|
||||
--> $DIR/literals.rs:24:17
|
||||
--> $DIR/literals.rs:21:17
|
||||
|
|
||||
24 | let fail1 = 0xabCD;
|
||||
21 | let fail1 = 0xabCD;
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings`
|
||||
|
||||
error: inconsistent casing in hexadecimal literal
|
||||
--> $DIR/literals.rs:25:17
|
||||
--> $DIR/literals.rs:22:17
|
||||
|
|
||||
25 | let fail2 = 0xabCD_u32;
|
||||
22 | let fail2 = 0xabCD_u32;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: inconsistent casing in hexadecimal literal
|
||||
--> $DIR/literals.rs:26:17
|
||||
--> $DIR/literals.rs:23:17
|
||||
|
|
||||
26 | let fail2 = 0xabCD_isize;
|
||||
23 | let fail2 = 0xabCD_isize;
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: integer type suffix should be separated by an underscore
|
||||
--> $DIR/literals.rs:27:27
|
||||
--> $DIR/literals.rs:24:27
|
||||
|
|
||||
27 | let fail_multi_zero = 000_123usize;
|
||||
24 | let fail_multi_zero = 000_123usize;
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
|
||||
|
||||
error: this is a decimal constant
|
||||
--> $DIR/literals.rs:27:27
|
||||
--> $DIR/literals.rs:24:27
|
||||
|
|
||||
27 | let fail_multi_zero = 000_123usize;
|
||||
24 | let fail_multi_zero = 000_123usize;
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::zero-prefixed-literal` implied by `-D warnings`
|
||||
help: if you mean to use a decimal constant, remove the `0` to remove confusion
|
||||
|
|
||||
27 | let fail_multi_zero = 123usize;
|
||||
24 | let fail_multi_zero = 123usize;
|
||||
| ^^^^^^^^
|
||||
help: if you mean to use an octal constant, use `0o`
|
||||
|
|
||||
27 | let fail_multi_zero = 0o123usize;
|
||||
24 | let fail_multi_zero = 0o123usize;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: integer type suffix should be separated by an underscore
|
||||
--> $DIR/literals.rs:29:17
|
||||
|
|
||||
29 | let fail3 = 1234i32;
|
||||
| ^^^^^^^
|
||||
|
||||
error: integer type suffix should be separated by an underscore
|
||||
--> $DIR/literals.rs:30:17
|
||||
|
|
||||
30 | let fail4 = 1234u32;
|
||||
| ^^^^^^^
|
||||
|
||||
error: integer type suffix should be separated by an underscore
|
||||
--> $DIR/literals.rs:31:17
|
||||
|
|
||||
31 | let fail5 = 1234isize;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: integer type suffix should be separated by an underscore
|
||||
--> $DIR/literals.rs:32:17
|
||||
|
|
||||
32 | let fail3 = 1234i32;
|
||||
| ^^^^^^^
|
||||
|
||||
error: integer type suffix should be separated by an underscore
|
||||
--> $DIR/literals.rs:33:17
|
||||
|
|
||||
33 | let fail4 = 1234u32;
|
||||
| ^^^^^^^
|
||||
|
||||
error: integer type suffix should be separated by an underscore
|
||||
--> $DIR/literals.rs:34:17
|
||||
|
|
||||
34 | let fail5 = 1234isize;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: integer type suffix should be separated by an underscore
|
||||
--> $DIR/literals.rs:35:17
|
||||
|
|
||||
35 | let fail6 = 1234usize;
|
||||
32 | let fail6 = 1234usize;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: float type suffix should be separated by an underscore
|
||||
--> $DIR/literals.rs:36:17
|
||||
--> $DIR/literals.rs:33:17
|
||||
|
|
||||
36 | let fail7 = 1.5f32;
|
||||
33 | let fail7 = 1.5f32;
|
||||
| ^^^^^^
|
||||
|
||||
error: this is a decimal constant
|
||||
--> $DIR/literals.rs:40:17
|
||||
--> $DIR/literals.rs:37:17
|
||||
|
|
||||
40 | let fail8 = 0123;
|
||||
37 | let fail8 = 0123;
|
||||
| ^^^^
|
||||
help: if you mean to use a decimal constant, remove the `0` to remove confusion
|
||||
|
|
||||
40 | let fail8 = 123;
|
||||
37 | let fail8 = 123;
|
||||
| ^^^
|
||||
help: if you mean to use an octal constant, use `0o`
|
||||
|
|
||||
40 | let fail8 = 0o123;
|
||||
37 | let fail8 = 0o123;
|
||||
| ^^^^^
|
||||
|
||||
error: long literal lacking separators
|
||||
--> $DIR/literals.rs:51:17
|
||||
--> $DIR/literals.rs:48:17
|
||||
|
|
||||
51 | let fail9 = 0xabcdef;
|
||||
48 | let fail9 = 0xabcdef;
|
||||
| ^^^^^^^^ help: consider: `0x00ab_cdef`
|
||||
|
|
||||
= note: `-D clippy::unreadable-literal` implied by `-D warnings`
|
||||
|
||||
error: long literal lacking separators
|
||||
--> $DIR/literals.rs:52:18
|
||||
--> $DIR/literals.rs:49:18
|
||||
|
|
||||
52 | let fail10 = 0xBAFEBAFE;
|
||||
49 | let fail10 = 0xBAFEBAFE;
|
||||
| ^^^^^^^^^^ help: consider: `0xBAFE_BAFE`
|
||||
|
||||
error: long literal lacking separators
|
||||
--> $DIR/literals.rs:53:18
|
||||
--> $DIR/literals.rs:50:18
|
||||
|
|
||||
53 | let fail11 = 0xabcdeff;
|
||||
50 | let fail11 = 0xabcdeff;
|
||||
| ^^^^^^^^^ help: consider: `0x0abc_deff`
|
||||
|
||||
error: long literal lacking separators
|
||||
--> $DIR/literals.rs:54:18
|
||||
--> $DIR/literals.rs:51:18
|
||||
|
|
||||
54 | let fail12 = 0xabcabcabcabcabcabc;
|
||||
51 | let fail12 = 0xabcabcabcabcabcabc;
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc`
|
||||
|
||||
error: digit groups should be smaller
|
||||
--> $DIR/literals.rs:55:18
|
||||
--> $DIR/literals.rs:52:18
|
||||
|
|
||||
55 | let fail13 = 0x1_23456_78901_usize;
|
||||
52 | let fail13 = 0x1_23456_78901_usize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize`
|
||||
|
|
||||
= note: `-D clippy::large-digit-groups` implied by `-D warnings`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/literals.rs:57:18
|
||||
--> $DIR/literals.rs:54:18
|
||||
|
|
||||
57 | let fail14 = 2_32;
|
||||
54 | let fail14 = 2_32;
|
||||
| ^^^^ help: did you mean to write: `2_i32`
|
||||
|
|
||||
= note: #[deny(clippy::mistyped_literal_suffixes)] on by default
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/literals.rs:58:18
|
||||
--> $DIR/literals.rs:55:18
|
||||
|
|
||||
58 | let fail15 = 4_64;
|
||||
55 | let fail15 = 4_64;
|
||||
| ^^^^ help: did you mean to write: `4_i64`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/literals.rs:59:18
|
||||
--> $DIR/literals.rs:56:18
|
||||
|
|
||||
59 | let fail16 = 7_8;
|
||||
56 | let fail16 = 7_8;
|
||||
| ^^^ help: did you mean to write: `7_i8`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/literals.rs:60:18
|
||||
--> $DIR/literals.rs:57:18
|
||||
|
|
||||
60 | let fail17 = 23_16;
|
||||
57 | let fail17 = 23_16;
|
||||
| ^^^^^ help: did you mean to write: `23_i16`
|
||||
|
||||
error: digits grouped inconsistently by underscores
|
||||
--> $DIR/literals.rs:62:18
|
||||
--> $DIR/literals.rs:59:18
|
||||
|
|
||||
62 | let fail19 = 12_3456_21;
|
||||
59 | let fail19 = 12_3456_21;
|
||||
| ^^^^^^^^^^ help: consider: `12_345_621`
|
||||
|
|
||||
= note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/literals.rs:63:18
|
||||
--> $DIR/literals.rs:60:18
|
||||
|
|
||||
63 | let fail20 = 2__8;
|
||||
60 | let fail20 = 2__8;
|
||||
| ^^^^ help: did you mean to write: `2_i8`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/literals.rs:64:18
|
||||
--> $DIR/literals.rs:61:18
|
||||
|
|
||||
64 | let fail21 = 4___16;
|
||||
61 | let fail21 = 4___16;
|
||||
| ^^^^^^ help: did you mean to write: `4_i16`
|
||||
|
||||
error: digits grouped inconsistently by underscores
|
||||
--> $DIR/literals.rs:65:18
|
||||
--> $DIR/literals.rs:62:18
|
||||
|
|
||||
65 | let fail22 = 3__4___23;
|
||||
62 | let fail22 = 3__4___23;
|
||||
| ^^^^^^^^^ help: consider: `3_423`
|
||||
|
||||
error: digits grouped inconsistently by underscores
|
||||
--> $DIR/literals.rs:66:18
|
||||
--> $DIR/literals.rs:63:18
|
||||
|
|
||||
66 | let fail23 = 3__16___23;
|
||||
63 | let fail23 = 3__16___23;
|
||||
| ^^^^^^^^^^ help: consider: `31_623`
|
||||
|
||||
error: aborting due to 25 previous errors
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/literals.rs:65:18
|
||||
|
|
||||
65 | let fail24 = 12.34_64;
|
||||
| ^^^^^^^^ help: did you mean to write: `12.34_f64`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/literals.rs:66:18
|
||||
|
|
||||
66 | let fail25 = 1E2_32;
|
||||
| ^^^^^^ help: did you mean to write: `1E2_f32`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/literals.rs:67:18
|
||||
|
|
||||
67 | let fail26 = 43E7_64;
|
||||
| ^^^^^^^ help: did you mean to write: `43E7_f64`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/literals.rs:68:18
|
||||
|
|
||||
68 | let fail27 = 243E17_32;
|
||||
| ^^^^^^^^^ help: did you mean to write: `243E17_f32`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/literals.rs:69:18
|
||||
|
|
||||
69 | let fail28 = 241251235E723_64;
|
||||
| ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/literals.rs:70:18
|
||||
|
|
||||
70 | let fail29 = 42279.911_32;
|
||||
| ^^^^^^^^^^^^ help: did you mean to write: `42_279.911_f32`
|
||||
|
||||
error: aborting due to 31 previous errors
|
||||
|
||||
|
@ -10,245 +10,11 @@
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
|
||||
# Generate a Markdown table of all lints, and put it in README.md.
|
||||
# With -n option, only print the new table to stdout.
|
||||
# With -c option, print a warning and set exit status to 1 if a file would be
|
||||
# changed.
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from subprocess import call
|
||||
|
||||
declare_deprecated_lint_re = re.compile(r'''
|
||||
declare_deprecated_lint! \s* [{(] \s*
|
||||
pub \s+ (?P<name>[A-Z_][A-Z_0-9]*) \s*,\s*
|
||||
" (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})]
|
||||
''', re.VERBOSE | re.DOTALL)
|
||||
|
||||
declare_clippy_lint_re = re.compile(r'''
|
||||
declare_clippy_lint! \s* [{(] \s*
|
||||
pub \s+ (?P<name>[A-Z_][A-Z_0-9]*) \s*,\s*
|
||||
(?P<cat>[a-z_]+) \s*,\s*
|
||||
" (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})]
|
||||
''', re.VERBOSE | re.DOTALL)
|
||||
|
||||
nl_escape_re = re.compile(r'\\\n\s*')
|
||||
|
||||
docs_link = 'https://rust-lang-nursery.github.io/rust-clippy/master/index.html'
|
||||
|
||||
|
||||
def collect(deprecated_lints, clippy_lints, fn):
|
||||
"""Collect all lints from a file.
|
||||
|
||||
Adds entries to the lints list as `(module, name, level, desc)`.
|
||||
"""
|
||||
with open(fn) as fp:
|
||||
code = fp.read()
|
||||
|
||||
for match in declare_deprecated_lint_re.finditer(code):
|
||||
# remove \-newline escapes from description string
|
||||
desc = nl_escape_re.sub('', match.group('desc'))
|
||||
deprecated_lints.append((os.path.splitext(os.path.basename(fn))[0],
|
||||
match.group('name').lower(),
|
||||
desc.replace('\\"', '"')))
|
||||
|
||||
for match in declare_clippy_lint_re.finditer(code):
|
||||
# remove \-newline escapes from description string
|
||||
desc = nl_escape_re.sub('', match.group('desc'))
|
||||
cat = match.group('cat')
|
||||
if cat in ('internal', 'internal_warn'):
|
||||
continue
|
||||
module_name = os.path.splitext(os.path.basename(fn))[0]
|
||||
if module_name == 'mod':
|
||||
module_name = os.path.basename(os.path.dirname(fn))
|
||||
clippy_lints[cat].append((module_name,
|
||||
match.group('name').lower(),
|
||||
"allow",
|
||||
desc.replace('\\"', '"')))
|
||||
|
||||
|
||||
def gen_group(lints):
|
||||
"""Write lint group (list of all lints in the form module::NAME)."""
|
||||
for (module, name, _, _) in sorted(lints):
|
||||
yield ' %s::%s,\n' % (module, name.upper())
|
||||
|
||||
|
||||
def gen_mods(lints):
|
||||
"""Declare modules"""
|
||||
|
||||
for module in sorted(set(lint[0] for lint in lints)):
|
||||
yield 'pub mod %s;\n' % module
|
||||
|
||||
|
||||
def gen_deprecated(lints):
|
||||
"""Declare deprecated lints"""
|
||||
|
||||
for lint in lints:
|
||||
yield ' store.register_removed(\n'
|
||||
yield ' "%s",\n' % lint[1]
|
||||
yield ' "%s",\n' % lint[2]
|
||||
yield ' );\n'
|
||||
|
||||
|
||||
def replace_region(fn, region_start, region_end, callback,
|
||||
replace_start=True, write_back=True):
|
||||
"""Replace a region in a file delimited by two lines matching regexes.
|
||||
|
||||
A callback is called to write the new region. If `replace_start` is true,
|
||||
the start delimiter line is replaced as well. The end delimiter line is
|
||||
never replaced.
|
||||
"""
|
||||
# read current content
|
||||
with open(fn) as fp:
|
||||
lines = list(fp)
|
||||
|
||||
found = False
|
||||
|
||||
# replace old region with new region
|
||||
new_lines = []
|
||||
in_old_region = False
|
||||
for line in lines:
|
||||
if in_old_region:
|
||||
if re.search(region_end, line):
|
||||
in_old_region = False
|
||||
new_lines.extend(callback())
|
||||
new_lines.append(line)
|
||||
elif re.search(region_start, line):
|
||||
if not replace_start:
|
||||
new_lines.append(line)
|
||||
# old region starts here
|
||||
in_old_region = True
|
||||
found = True
|
||||
else:
|
||||
new_lines.append(line)
|
||||
|
||||
if not found:
|
||||
print("regex " + region_start + " not found")
|
||||
|
||||
# write back to file
|
||||
if write_back:
|
||||
with open(fn, 'w') as fp:
|
||||
fp.writelines(new_lines)
|
||||
|
||||
# if something changed, return true
|
||||
return lines != new_lines
|
||||
|
||||
|
||||
def main(print_only=False, check=False):
|
||||
deprecated_lints = []
|
||||
clippy_lints = {
|
||||
"correctness": [],
|
||||
"style": [],
|
||||
"complexity": [],
|
||||
"perf": [],
|
||||
"restriction": [],
|
||||
"pedantic": [],
|
||||
"cargo": [],
|
||||
"nursery": [],
|
||||
}
|
||||
|
||||
# check directory
|
||||
if not os.path.isfile('clippy_lints/src/lib.rs'):
|
||||
print('Error: call this script from clippy checkout directory!')
|
||||
return
|
||||
|
||||
# collect all lints from source files
|
||||
for root, dirs, files in os.walk('clippy_lints/src'):
|
||||
for fn in files:
|
||||
if fn.endswith('.rs'):
|
||||
collect(deprecated_lints, clippy_lints,
|
||||
os.path.join(root, fn))
|
||||
|
||||
# determine version
|
||||
with open('Cargo.toml') as fp:
|
||||
for line in fp:
|
||||
if line.startswith('version ='):
|
||||
clippy_version = line.split()[2].strip('"')
|
||||
break
|
||||
else:
|
||||
print('Error: version not found in Cargo.toml!')
|
||||
return
|
||||
|
||||
all_lints = []
|
||||
clippy_lint_groups = [
|
||||
"correctness",
|
||||
"style",
|
||||
"complexity",
|
||||
"perf",
|
||||
]
|
||||
clippy_lint_list = []
|
||||
for x in clippy_lint_groups:
|
||||
clippy_lint_list += clippy_lints[x]
|
||||
for _, value in clippy_lints.iteritems():
|
||||
all_lints += value
|
||||
|
||||
if print_only:
|
||||
call(["./util/dev", "update_lints", "--print-only"])
|
||||
return
|
||||
|
||||
# update the lint counter in README.md
|
||||
changed = replace_region(
|
||||
'README.md',
|
||||
r'^\[There are \d+ lints included in this crate!\]\(https://rust-lang-nursery.github.io/rust-clippy/master/index.html\)$', "",
|
||||
lambda: ['[There are %d lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)\n' %
|
||||
(len(all_lints))],
|
||||
write_back=not check)
|
||||
|
||||
# update the links in the CHANGELOG
|
||||
changed |= replace_region(
|
||||
'CHANGELOG.md',
|
||||
"<!-- begin autogenerated links to lint list -->",
|
||||
"<!-- end autogenerated links to lint list -->",
|
||||
lambda: ["[`{0}`]: {1}#{0}\n".format(l[1], docs_link) for l in
|
||||
sorted(all_lints + deprecated_lints,
|
||||
key=lambda l: l[1])],
|
||||
replace_start=False, write_back=not check)
|
||||
|
||||
# update version of clippy_lints in Cargo.toml
|
||||
changed |= replace_region(
|
||||
'Cargo.toml', r'# begin automatic update', '# end automatic update',
|
||||
lambda: ['clippy_lints = { version = "%s", path = "clippy_lints" }\n' %
|
||||
clippy_version],
|
||||
replace_start=False, write_back=not check)
|
||||
|
||||
# update version of clippy_lints in Cargo.toml
|
||||
changed |= replace_region(
|
||||
'clippy_lints/Cargo.toml', r'# begin automatic update', '# end automatic update',
|
||||
lambda: ['version = "%s"\n' % clippy_version],
|
||||
replace_start=False, write_back=not check)
|
||||
|
||||
# update the `pub mod` list
|
||||
changed |= replace_region(
|
||||
'clippy_lints/src/lib.rs', r'begin lints modules', r'end lints modules',
|
||||
lambda: gen_mods(all_lints),
|
||||
replace_start=False, write_back=not check)
|
||||
|
||||
# same for "clippy::*" lint collections
|
||||
changed |= replace_region(
|
||||
'clippy_lints/src/lib.rs', r'reg.register_lint_group\("clippy::all"', r'\]\);',
|
||||
lambda: gen_group(clippy_lint_list),
|
||||
replace_start=False, write_back=not check)
|
||||
|
||||
for key, value in clippy_lints.iteritems():
|
||||
# same for "clippy::*" lint collections
|
||||
changed |= replace_region(
|
||||
'clippy_lints/src/lib.rs', r'reg.register_lint_group\("clippy::' + key + r'"', r'\]\);',
|
||||
lambda: gen_group(value),
|
||||
replace_start=False, write_back=not check)
|
||||
|
||||
# same for "deprecated" lint collection
|
||||
changed |= replace_region(
|
||||
'clippy_lints/src/lib.rs', r'begin deprecated lints', r'end deprecated lints',
|
||||
lambda: gen_deprecated(deprecated_lints),
|
||||
replace_start=False,
|
||||
write_back=not check)
|
||||
|
||||
if check and changed:
|
||||
print('Please run util/update_lints.py to regenerate lints lists.')
|
||||
return 1
|
||||
|
||||
def main():
|
||||
print('Error: Please use `util/dev` to update lints')
|
||||
return 1
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(print_only='-n' in sys.argv, check='-c' in sys.argv))
|
||||
sys.exit(main())
|
||||
|
Loading…
Reference in New Issue
Block a user