Merge branch 'master' into fix-missing-comma-fp

This commit is contained in:
Michael Wright 2018-11-06 07:00:54 +02:00
commit 2353f24095
10 changed files with 332 additions and 446 deletions

View File

@ -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

View File

@ -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...

View File

@ -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));
}

View File

@ -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![
format!("[There are {} lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)", 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);
}
}

View File

@ -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,

View File

@ -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")
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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

View File

@ -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())