Auto merge of #8952 - rust-lang:explain, r=xFredNet

add `--explain` subcommand

This closes #8291.

---

changelog: add `cargo clippy -- --explain <lintname>` subcommand
This commit is contained in:
bors 2022-09-02 20:27:42 +00:00
commit 30e4532153
575 changed files with 13817 additions and 28 deletions

View file

@ -3,7 +3,7 @@ use aho_corasick::AhoCorasickBuilder;
use indoc::writedoc; use indoc::writedoc;
use itertools::Itertools; use itertools::Itertools;
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
use std::collections::{HashMap, HashSet}; use std::collections::{BTreeSet, HashMap, HashSet};
use std::ffi::OsStr; use std::ffi::OsStr;
use std::fmt::Write; use std::fmt::Write;
use std::fs::{self, OpenOptions}; use std::fs::{self, OpenOptions};
@ -124,6 +124,8 @@ fn generate_lint_files(
let content = gen_lint_group_list("all", all_group_lints); let content = gen_lint_group_list("all", all_group_lints);
process_file("clippy_lints/src/lib.register_all.rs", update_mode, &content); process_file("clippy_lints/src/lib.register_all.rs", update_mode, &content);
update_docs(update_mode, &usable_lints);
for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) { for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) {
let content = gen_lint_group_list(&lint_group, lints.iter()); let content = gen_lint_group_list(&lint_group, lints.iter());
process_file( process_file(
@ -140,6 +142,62 @@ fn generate_lint_files(
process_file("tests/ui/rename.rs", update_mode, &content); process_file("tests/ui/rename.rs", update_mode, &content);
} }
fn update_docs(update_mode: UpdateMode, usable_lints: &[Lint]) {
replace_region_in_file(update_mode, Path::new("src/docs.rs"), "docs! {\n", "\n}\n", |res| {
for name in usable_lints.iter().map(|lint| lint.name.clone()).sorted() {
writeln!(res, r#" "{name}","#).unwrap();
}
});
if update_mode == UpdateMode::Check {
let mut extra = BTreeSet::new();
let mut lint_names = usable_lints
.iter()
.map(|lint| lint.name.clone())
.collect::<BTreeSet<_>>();
for file in std::fs::read_dir("src/docs").unwrap() {
let filename = file.unwrap().file_name().into_string().unwrap();
if let Some(name) = filename.strip_suffix(".txt") {
if !lint_names.remove(name) {
extra.insert(name.to_string());
}
}
}
let failed = print_lint_names("extra lint docs:", &extra) | print_lint_names("missing lint docs:", &lint_names);
if failed {
exit_with_failure();
}
} else {
if std::fs::remove_dir_all("src/docs").is_err() {
eprintln!("could not remove src/docs directory");
}
if std::fs::create_dir("src/docs").is_err() {
eprintln!("could not recreate src/docs directory");
}
}
for lint in usable_lints {
process_file(
Path::new("src/docs").join(lint.name.clone() + ".txt"),
update_mode,
&lint.documentation,
);
}
}
fn print_lint_names(header: &str, lints: &BTreeSet<String>) -> bool {
if lints.is_empty() {
return false;
}
println!("{}", header);
for lint in lints.iter().sorted() {
println!(" {}", lint);
}
println!();
true
}
pub fn print_lints() { pub fn print_lints() {
let (lint_list, _, _) = gather_all(); let (lint_list, _, _) = gather_all();
let usable_lints = Lint::usable_lints(&lint_list); let usable_lints = Lint::usable_lints(&lint_list);
@ -589,17 +647,26 @@ struct Lint {
desc: String, desc: String,
module: String, module: String,
declaration_range: Range<usize>, declaration_range: Range<usize>,
documentation: String,
} }
impl Lint { impl Lint {
#[must_use] #[must_use]
fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Range<usize>) -> Self { fn new(
name: &str,
group: &str,
desc: &str,
module: &str,
declaration_range: Range<usize>,
documentation: String,
) -> Self {
Self { Self {
name: name.to_lowercase(), name: name.to_lowercase(),
group: group.into(), group: group.into(),
desc: remove_line_splices(desc), desc: remove_line_splices(desc),
module: module.into(), module: module.into(),
declaration_range, declaration_range,
documentation,
} }
} }
@ -852,27 +919,35 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
}| token_kind == &TokenKind::Ident && *content == "declare_clippy_lint", }| token_kind == &TokenKind::Ident && *content == "declare_clippy_lint",
) { ) {
let start = range.start; let start = range.start;
let mut docs = String::with_capacity(128);
let mut iter = iter let mut iter = iter.by_ref().filter(|t| !matches!(t.token_kind, TokenKind::Whitespace));
.by_ref()
.filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
// matches `!{` // matches `!{`
match_tokens!(iter, Bang OpenBrace); match_tokens!(iter, Bang OpenBrace);
match iter.next() { let mut in_code = false;
// #[clippy::version = "version"] pub while let Some(t) = iter.next() {
Some(LintDeclSearchResult { match t.token_kind {
token_kind: TokenKind::Pound, TokenKind::LineComment { .. } => {
.. if let Some(line) = t.content.strip_prefix("/// ").or_else(|| t.content.strip_prefix("///")) {
}) => { if line.starts_with("```") {
match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident); docs += "```\n";
}, in_code = !in_code;
// pub } else if !(in_code && line.starts_with("# ")) {
Some(LintDeclSearchResult { docs += line;
token_kind: TokenKind::Ident, docs.push('\n');
.. }
}) => (), }
_ => continue, },
TokenKind::Pound => {
match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident);
break;
},
TokenKind::Ident => {
break;
},
_ => {},
}
} }
docs.pop(); // remove final newline
let (name, group, desc) = match_tokens!( let (name, group, desc) = match_tokens!(
iter, iter,
@ -890,7 +965,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
.. ..
}) = iter.next() }) = iter.next()
{ {
lints.push(Lint::new(name, group, desc, module, start..range.end)); lints.push(Lint::new(name, group, desc, module, start..range.end, docs));
} }
} }
} }
@ -1120,6 +1195,7 @@ mod tests {
"\"really long text\"", "\"really long text\"",
"module_name", "module_name",
Range::default(), Range::default(),
String::new(),
), ),
Lint::new( Lint::new(
"doc_markdown", "doc_markdown",
@ -1127,6 +1203,7 @@ mod tests {
"\"single line\"", "\"single line\"",
"module_name", "module_name",
Range::default(), Range::default(),
String::new(),
), ),
]; ];
assert_eq!(expected, result); assert_eq!(expected, result);
@ -1166,6 +1243,7 @@ mod tests {
"\"abc\"", "\"abc\"",
"module_name", "module_name",
Range::default(), Range::default(),
String::new(),
), ),
Lint::new( Lint::new(
"should_assert_eq2", "should_assert_eq2",
@ -1173,6 +1251,7 @@ mod tests {
"\"abc\"", "\"abc\"",
"module_name", "module_name",
Range::default(), Range::default(),
String::new(),
), ),
Lint::new( Lint::new(
"should_assert_eq2", "should_assert_eq2",
@ -1180,6 +1259,7 @@ mod tests {
"\"abc\"", "\"abc\"",
"module_name", "module_name",
Range::default(), Range::default(),
String::new(),
), ),
]; ];
let expected = vec![Lint::new( let expected = vec![Lint::new(
@ -1188,6 +1268,7 @@ mod tests {
"\"abc\"", "\"abc\"",
"module_name", "module_name",
Range::default(), Range::default(),
String::new(),
)]; )];
assert_eq!(expected, Lint::usable_lints(&lints)); assert_eq!(expected, Lint::usable_lints(&lints));
} }
@ -1195,22 +1276,51 @@ mod tests {
#[test] #[test]
fn test_by_lint_group() { fn test_by_lint_group() {
let lints = vec![ let lints = vec![
Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), Lint::new(
"should_assert_eq",
"group1",
"\"abc\"",
"module_name",
Range::default(),
String::new(),
),
Lint::new( Lint::new(
"should_assert_eq2", "should_assert_eq2",
"group2", "group2",
"\"abc\"", "\"abc\"",
"module_name", "module_name",
Range::default(), Range::default(),
String::new(),
),
Lint::new(
"incorrect_match",
"group1",
"\"abc\"",
"module_name",
Range::default(),
String::new(),
), ),
Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
]; ];
let mut expected: HashMap<String, Vec<Lint>> = HashMap::new(); let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
expected.insert( expected.insert(
"group1".to_string(), "group1".to_string(),
vec![ vec![
Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), Lint::new(
Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), "should_assert_eq",
"group1",
"\"abc\"",
"module_name",
Range::default(),
String::new(),
),
Lint::new(
"incorrect_match",
"group1",
"\"abc\"",
"module_name",
Range::default(),
String::new(),
),
], ],
); );
expected.insert( expected.insert(
@ -1221,6 +1331,7 @@ mod tests {
"\"abc\"", "\"abc\"",
"module_name", "module_name",
Range::default(), Range::default(),
String::new(),
)], )],
); );
assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
@ -1259,9 +1370,30 @@ mod tests {
#[test] #[test]
fn test_gen_lint_group_list() { fn test_gen_lint_group_list() {
let lints = vec![ let lints = vec![
Lint::new("abc", "group1", "\"abc\"", "module_name", Range::default()), Lint::new(
Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), "abc",
Lint::new("internal", "internal_style", "\"abc\"", "module_name", Range::default()), "group1",
"\"abc\"",
"module_name",
Range::default(),
String::new(),
),
Lint::new(
"should_assert_eq",
"group1",
"\"abc\"",
"module_name",
Range::default(),
String::new(),
),
Lint::new(
"internal",
"internal_style",
"\"abc\"",
"module_name",
Range::default(),
String::new(),
),
]; ];
let expected = GENERATED_FILE_COMMENT.to_string() let expected = GENERATED_FILE_COMMENT.to_string()
+ &[ + &[

596
src/docs.rs Normal file
View file

@ -0,0 +1,596 @@
// autogenerated. Please look at /clippy_dev/src/update_lints.rs
macro_rules! include_lint {
($file_name: expr) => {
include_str!($file_name)
};
}
macro_rules! docs {
($($lint_name: expr,)*) => {
pub fn explain(lint: &str) {
println!("{}", match lint {
$(
$lint_name => include_lint!(concat!("docs/", concat!($lint_name, ".txt"))),
)*
_ => "unknown lint",
})
}
}
}
docs! {
"absurd_extreme_comparisons",
"alloc_instead_of_core",
"allow_attributes_without_reason",
"almost_complete_letter_range",
"almost_swapped",
"approx_constant",
"arithmetic",
"as_conversions",
"as_underscore",
"assertions_on_constants",
"assertions_on_result_states",
"assign_op_pattern",
"async_yields_async",
"await_holding_invalid_type",
"await_holding_lock",
"await_holding_refcell_ref",
"bad_bit_mask",
"bind_instead_of_map",
"blanket_clippy_restriction_lints",
"blocks_in_if_conditions",
"bool_assert_comparison",
"bool_comparison",
"bool_to_int_with_if",
"borrow_as_ptr",
"borrow_deref_ref",
"borrow_interior_mutable_const",
"borrowed_box",
"box_collection",
"boxed_local",
"branches_sharing_code",
"builtin_type_shadow",
"bytes_count_to_len",
"bytes_nth",
"cargo_common_metadata",
"case_sensitive_file_extension_comparisons",
"cast_abs_to_unsigned",
"cast_enum_constructor",
"cast_enum_truncation",
"cast_lossless",
"cast_possible_truncation",
"cast_possible_wrap",
"cast_precision_loss",
"cast_ptr_alignment",
"cast_ref_to_mut",
"cast_sign_loss",
"cast_slice_different_sizes",
"cast_slice_from_raw_parts",
"char_lit_as_u8",
"chars_last_cmp",
"chars_next_cmp",
"checked_conversions",
"clone_double_ref",
"clone_on_copy",
"clone_on_ref_ptr",
"cloned_instead_of_copied",
"cmp_nan",
"cmp_null",
"cmp_owned",
"cognitive_complexity",
"collapsible_else_if",
"collapsible_if",
"collapsible_match",
"collapsible_str_replace",
"comparison_chain",
"comparison_to_empty",
"copy_iterator",
"crate_in_macro_def",
"create_dir",
"crosspointer_transmute",
"dbg_macro",
"debug_assert_with_mut_call",
"decimal_literal_representation",
"declare_interior_mutable_const",
"default_instead_of_iter_empty",
"default_numeric_fallback",
"default_trait_access",
"default_union_representation",
"deprecated_cfg_attr",
"deprecated_semver",
"deref_addrof",
"deref_by_slicing",
"derivable_impls",
"derive_hash_xor_eq",
"derive_ord_xor_partial_ord",
"derive_partial_eq_without_eq",
"disallowed_methods",
"disallowed_names",
"disallowed_script_idents",
"disallowed_types",
"diverging_sub_expression",
"doc_link_with_quotes",
"doc_markdown",
"double_comparisons",
"double_must_use",
"double_neg",
"double_parens",
"drop_copy",
"drop_non_drop",
"drop_ref",
"duplicate_mod",
"duplicate_underscore_argument",
"duration_subsec",
"else_if_without_else",
"empty_drop",
"empty_enum",
"empty_line_after_outer_attr",
"empty_loop",
"empty_structs_with_brackets",
"enum_clike_unportable_variant",
"enum_glob_use",
"enum_variant_names",
"eq_op",
"equatable_if_let",
"erasing_op",
"err_expect",
"excessive_precision",
"exhaustive_enums",
"exhaustive_structs",
"exit",
"expect_fun_call",
"expect_used",
"expl_impl_clone_on_copy",
"explicit_auto_deref",
"explicit_counter_loop",
"explicit_deref_methods",
"explicit_into_iter_loop",
"explicit_iter_loop",
"explicit_write",
"extend_with_drain",
"extra_unused_lifetimes",
"fallible_impl_from",
"field_reassign_with_default",
"filetype_is_file",
"filter_map_identity",
"filter_map_next",
"filter_next",
"flat_map_identity",
"flat_map_option",
"float_arithmetic",
"float_cmp",
"float_cmp_const",
"float_equality_without_abs",
"fn_address_comparisons",
"fn_params_excessive_bools",
"fn_to_numeric_cast",
"fn_to_numeric_cast_any",
"fn_to_numeric_cast_with_truncation",
"for_kv_map",
"for_loops_over_fallibles",
"forget_copy",
"forget_non_drop",
"forget_ref",
"format_in_format_args",
"format_push_string",
"from_iter_instead_of_collect",
"from_over_into",
"from_str_radix_10",
"future_not_send",
"get_first",
"get_last_with_len",
"get_unwrap",
"identity_op",
"if_let_mutex",
"if_not_else",
"if_same_then_else",
"if_then_some_else_none",
"ifs_same_cond",
"implicit_clone",
"implicit_hasher",
"implicit_return",
"implicit_saturating_sub",
"imprecise_flops",
"inconsistent_digit_grouping",
"inconsistent_struct_constructor",
"index_refutable_slice",
"indexing_slicing",
"ineffective_bit_mask",
"inefficient_to_string",
"infallible_destructuring_match",
"infinite_iter",
"inherent_to_string",
"inherent_to_string_shadow_display",
"init_numbered_fields",
"inline_always",
"inline_asm_x86_att_syntax",
"inline_asm_x86_intel_syntax",
"inline_fn_without_body",
"inspect_for_each",
"int_plus_one",
"integer_arithmetic",
"integer_division",
"into_iter_on_ref",
"invalid_null_ptr_usage",
"invalid_regex",
"invalid_upcast_comparisons",
"invalid_utf8_in_unchecked",
"invisible_characters",
"is_digit_ascii_radix",
"items_after_statements",
"iter_cloned_collect",
"iter_count",
"iter_next_loop",
"iter_next_slice",
"iter_not_returning_iterator",
"iter_nth",
"iter_nth_zero",
"iter_on_empty_collections",
"iter_on_single_items",
"iter_overeager_cloned",
"iter_skip_next",
"iter_with_drain",
"iterator_step_by_zero",
"just_underscores_and_digits",
"large_const_arrays",
"large_digit_groups",
"large_enum_variant",
"large_include_file",
"large_stack_arrays",
"large_types_passed_by_value",
"len_without_is_empty",
"len_zero",
"let_and_return",
"let_underscore_drop",
"let_underscore_lock",
"let_underscore_must_use",
"let_unit_value",
"linkedlist",
"lossy_float_literal",
"macro_use_imports",
"main_recursion",
"manual_assert",
"manual_async_fn",
"manual_bits",
"manual_filter_map",
"manual_find",
"manual_find_map",
"manual_flatten",
"manual_instant_elapsed",
"manual_map",
"manual_memcpy",
"manual_non_exhaustive",
"manual_ok_or",
"manual_range_contains",
"manual_rem_euclid",
"manual_retain",
"manual_saturating_arithmetic",
"manual_split_once",
"manual_str_repeat",
"manual_string_new",
"manual_strip",
"manual_swap",
"manual_unwrap_or",
"many_single_char_names",
"map_clone",
"map_collect_result_unit",
"map_entry",
"map_err_ignore",
"map_flatten",
"map_identity",
"map_unwrap_or",
"match_as_ref",
"match_bool",
"match_like_matches_macro",
"match_on_vec_items",
"match_overlapping_arm",
"match_ref_pats",
"match_result_ok",
"match_same_arms",
"match_single_binding",
"match_str_case_mismatch",
"match_wild_err_arm",
"match_wildcard_for_single_variants",
"maybe_infinite_iter",
"mem_forget",
"mem_replace_option_with_none",
"mem_replace_with_default",
"mem_replace_with_uninit",
"min_max",
"mismatched_target_os",
"mismatching_type_param_order",
"misrefactored_assign_op",
"missing_const_for_fn",
"missing_docs_in_private_items",
"missing_enforced_import_renames",
"missing_errors_doc",
"missing_inline_in_public_items",
"missing_panics_doc",
"missing_safety_doc",
"missing_spin_loop",
"mistyped_literal_suffixes",
"mixed_case_hex_literals",
"mixed_read_write_in_expression",
"mod_module_files",
"module_inception",
"module_name_repetitions",
"modulo_arithmetic",
"modulo_one",
"multi_assignments",
"multiple_crate_versions",
"multiple_inherent_impl",
"must_use_candidate",
"must_use_unit",
"mut_from_ref",
"mut_mut",
"mut_mutex_lock",
"mut_range_bound",
"mutable_key_type",
"mutex_atomic",
"mutex_integer",
"naive_bytecount",
"needless_arbitrary_self_type",
"needless_bitwise_bool",
"needless_bool",
"needless_borrow",
"needless_borrowed_reference",
"needless_collect",
"needless_continue",
"needless_doctest_main",
"needless_for_each",
"needless_late_init",
"needless_lifetimes",
"needless_match",
"needless_option_as_deref",
"needless_option_take",
"needless_parens_on_range_literals",
"needless_pass_by_value",
"needless_question_mark",
"needless_range_loop",
"needless_return",
"needless_splitn",
"needless_update",
"neg_cmp_op_on_partial_ord",
"neg_multiply",
"negative_feature_names",
"never_loop",
"new_ret_no_self",
"new_without_default",
"no_effect",
"no_effect_replace",
"no_effect_underscore_binding",
"non_ascii_literal",
"non_octal_unix_permissions",
"non_send_fields_in_send_ty",
"nonminimal_bool",
"nonsensical_open_options",
"nonstandard_macro_braces",
"not_unsafe_ptr_arg_deref",
"obfuscated_if_else",
"octal_escapes",
"ok_expect",
"only_used_in_recursion",
"op_ref",
"option_as_ref_deref",
"option_env_unwrap",
"option_filter_map",
"option_if_let_else",
"option_map_or_none",
"option_map_unit_fn",
"option_option",
"or_fun_call",
"or_then_unwrap",
"out_of_bounds_indexing",
"overflow_check_conditional",
"overly_complex_bool_expr",
"panic",
"panic_in_result_fn",
"panicking_unwrap",
"partialeq_ne_impl",
"partialeq_to_none",
"path_buf_push_overwrite",
"pattern_type_mismatch",
"positional_named_format_parameters",
"possible_missing_comma",
"precedence",
"print_in_format_impl",
"print_literal",
"print_stderr",
"print_stdout",
"print_with_newline",
"println_empty_string",
"ptr_arg",
"ptr_as_ptr",
"ptr_eq",
"ptr_offset_with_cast",
"pub_use",
"question_mark",
"range_minus_one",
"range_plus_one",
"range_zip_with_len",
"rc_buffer",
"rc_clone_in_vec_init",
"rc_mutex",
"read_zero_byte_vec",
"recursive_format_impl",
"redundant_allocation",
"redundant_clone",
"redundant_closure",
"redundant_closure_call",
"redundant_closure_for_method_calls",
"redundant_else",
"redundant_feature_names",
"redundant_field_names",
"redundant_pattern",
"redundant_pattern_matching",
"redundant_pub_crate",
"redundant_slicing",
"redundant_static_lifetimes",
"ref_binding_to_reference",
"ref_option_ref",
"repeat_once",
"rest_pat_in_fully_bound_structs",
"result_large_err",
"result_map_or_into_option",
"result_map_unit_fn",
"result_unit_err",
"return_self_not_must_use",
"reversed_empty_ranges",
"same_functions_in_if_condition",
"same_item_push",
"same_name_method",
"search_is_some",
"self_assignment",
"self_named_constructors",
"self_named_module_files",
"semicolon_if_nothing_returned",
"separated_literal_suffix",
"serde_api_misuse",
"shadow_reuse",
"shadow_same",
"shadow_unrelated",
"short_circuit_statement",
"should_implement_trait",
"significant_drop_in_scrutinee",
"similar_names",
"single_char_add_str",
"single_char_lifetime_names",
"single_char_pattern",
"single_component_path_imports",
"single_element_loop",
"single_match",
"single_match_else",
"size_of_in_element_count",
"skip_while_next",
"slow_vector_initialization",
"stable_sort_primitive",
"std_instead_of_alloc",
"std_instead_of_core",
"str_to_string",
"string_add",
"string_add_assign",
"string_extend_chars",
"string_from_utf8_as_bytes",
"string_lit_as_bytes",
"string_slice",
"string_to_string",
"strlen_on_c_strings",
"struct_excessive_bools",
"suboptimal_flops",
"suspicious_arithmetic_impl",
"suspicious_assignment_formatting",
"suspicious_else_formatting",
"suspicious_map",
"suspicious_op_assign_impl",
"suspicious_operation_groupings",
"suspicious_splitn",
"suspicious_to_owned",
"suspicious_unary_op_formatting",
"swap_ptr_to_ref",
"tabs_in_doc_comments",
"temporary_assignment",
"to_digit_is_some",
"to_string_in_format_args",
"todo",
"too_many_arguments",
"too_many_lines",
"toplevel_ref_arg",
"trailing_empty_array",
"trait_duplication_in_bounds",
"transmute_bytes_to_str",
"transmute_float_to_int",
"transmute_int_to_bool",
"transmute_int_to_char",
"transmute_int_to_float",
"transmute_num_to_bytes",
"transmute_ptr_to_ptr",
"transmute_ptr_to_ref",
"transmute_undefined_repr",
"transmutes_expressible_as_ptr_casts",
"transmuting_null",
"trim_split_whitespace",
"trivial_regex",
"trivially_copy_pass_by_ref",
"try_err",
"type_complexity",
"type_repetition_in_bounds",
"undocumented_unsafe_blocks",
"undropped_manually_drops",
"unicode_not_nfc",
"unimplemented",
"uninit_assumed_init",
"uninit_vec",
"unit_arg",
"unit_cmp",
"unit_hash",
"unit_return_expecting_ord",
"unnecessary_cast",
"unnecessary_filter_map",
"unnecessary_find_map",
"unnecessary_fold",
"unnecessary_join",
"unnecessary_lazy_evaluations",
"unnecessary_mut_passed",
"unnecessary_operation",
"unnecessary_owned_empty_strings",
"unnecessary_self_imports",
"unnecessary_sort_by",
"unnecessary_to_owned",
"unnecessary_unwrap",
"unnecessary_wraps",
"unneeded_field_pattern",
"unneeded_wildcard_pattern",
"unnested_or_patterns",
"unreachable",
"unreadable_literal",
"unsafe_derive_deserialize",
"unsafe_removed_from_name",
"unseparated_literal_suffix",
"unsound_collection_transmute",
"unused_async",
"unused_io_amount",
"unused_peekable",
"unused_rounding",
"unused_self",
"unused_unit",
"unusual_byte_groupings",
"unwrap_in_result",
"unwrap_or_else_default",
"unwrap_used",
"upper_case_acronyms",
"use_debug",
"use_self",
"used_underscore_binding",
"useless_asref",
"useless_attribute",
"useless_conversion",
"useless_format",
"useless_let_if_seq",
"useless_transmute",
"useless_vec",
"vec_box",
"vec_init_then_push",
"vec_resize_to_zero",
"verbose_bit_mask",
"verbose_file_reads",
"vtable_address_comparisons",
"while_immutable_condition",
"while_let_loop",
"while_let_on_iterator",
"wildcard_dependencies",
"wildcard_enum_match_arm",
"wildcard_imports",
"wildcard_in_or_patterns",
"write_literal",
"write_with_newline",
"writeln_empty_string",
"wrong_self_convention",
"wrong_transmute",
"zero_divided_by_zero",
"zero_prefixed_literal",
"zero_ptr",
"zero_sized_map_values",
"zst_offset",
}

View file

@ -0,0 +1,25 @@
### What it does
Checks for comparisons where one side of the relation is
either the minimum or maximum value for its type and warns if it involves a
case that is always true or always false. Only integer and boolean types are
checked.
### Why is this bad?
An expression like `min <= x` may misleadingly imply
that it is possible for `x` to be less than the minimum. Expressions like
`max < x` are probably mistakes.
### Known problems
For `usize` the size of the current compile target will
be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
a comparison to detect target pointer width will trigger this lint. One can
use `mem::sizeof` and compare its value or conditional compilation
attributes
like `#[cfg(target_pointer_width = "64")] ..` instead.
### Example
```
let vec: Vec<isize> = Vec::new();
if vec.len() <= 0 {}
if 100 > i32::MAX {}
```

View file

@ -0,0 +1,18 @@
### What it does
Finds items imported through `alloc` when available through `core`.
### Why is this bad?
Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are
imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint
is also useful for crates migrating to become `no_std` compatible.
### Example
```
use alloc::slice::from_ref;
```
Use instead:
```
use core::slice::from_ref;
```

View file

@ -0,0 +1,22 @@
### What it does
Checks for attributes that allow lints without a reason.
(This requires the `lint_reasons` feature)
### Why is this bad?
Allowing a lint should always have a reason. This reason should be documented to
ensure that others understand the reasoning
### Example
```
#![feature(lint_reasons)]
#![allow(clippy::some_lint)]
```
Use instead:
```
#![feature(lint_reasons)]
#![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")]
```

View file

@ -0,0 +1,15 @@
### What it does
Checks for ranges which almost include the entire range of letters from 'a' to 'z', but
don't because they're a half open range.
### Why is this bad?
This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
### Example
```
let _ = 'a'..'z';
```
Use instead:
```
let _ = 'a'..='z';
```

View file

@ -0,0 +1,15 @@
### What it does
Checks for `foo = bar; bar = foo` sequences.
### Why is this bad?
This looks like a failed attempt to swap.
### Example
```
a = b;
b = a;
```
If swapping is intended, use `swap()` instead:
```
std::mem::swap(&mut a, &mut b);
```

View file

@ -0,0 +1,24 @@
### What it does
Checks for floating point literals that approximate
constants which are defined in
[`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants)
or
[`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants),
respectively, suggesting to use the predefined constant.
### Why is this bad?
Usually, the definition in the standard library is more
precise than what people come up with. If you find that your definition is
actually more precise, please [file a Rust
issue](https://github.com/rust-lang/rust/issues).
### Example
```
let x = 3.14;
let y = 1_f64 / x;
```
Use instead:
```
let x = std::f32::consts::PI;
let y = std::f64::consts::FRAC_1_PI;
```

28
src/docs/arithmetic.txt Normal file
View file

@ -0,0 +1,28 @@
### What it does
Checks for any kind of arithmetic operation of any type.
Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered
away.
### Why is this bad?
Integer overflow will trigger a panic in debug builds or will wrap in
release mode. Division by zero will cause a panic in either mode. In some applications one
wants explicitly checked, wrapping or saturating arithmetic.
#### Example
```
a + 1;
```
Third-party types also tend to overflow.
#### Example
```
use rust_decimal::Decimal;
let _n = Decimal::MAX + Decimal::MAX;
```
### Allowed types
Custom allowed types can be specified through the "arithmetic-allowed" filter.

View file

@ -0,0 +1,32 @@
### What it does
Checks for usage of `as` conversions.
Note that this lint is specialized in linting *every single* use of `as`
regardless of whether good alternatives exist or not.
If you want more precise lints for `as`, please consider using these separate lints:
`unnecessary_cast`, `cast_lossless/cast_possible_truncation/cast_possible_wrap/cast_precision_loss/cast_sign_loss`,
`fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`.
There is a good explanation the reason why this lint should work in this way and how it is useful
[in this issue](https://github.com/rust-lang/rust-clippy/issues/5122).
### Why is this bad?
`as` conversions will perform many kinds of
conversions, including silently lossy conversions and dangerous coercions.
There are cases when it makes sense to use `as`, so the lint is
Allow by default.
### Example
```
let a: u32;
...
f(a as u16);
```
Use instead:
```
f(a.try_into()?);
// or
f(a.try_into().expect("Unexpected u16 overflow in f"));
```

View file

@ -0,0 +1,21 @@
### What it does
Check for the usage of `as _` conversion using inferred type.
### Why is this bad?
The conversion might include lossy conversion and dangerous cast that might go
undetected due to the type being inferred.
The lint is allowed by default as using `_` is less wordy than always specifying the type.
### Example
```
fn foo(n: usize) {}
let n: u16 = 256;
foo(n as _);
```
Use instead:
```
fn foo(n: usize) {}
let n: u16 = 256;
foo(n as usize);
```

View file

@ -0,0 +1,14 @@
### What it does
Checks for `assert!(true)` and `assert!(false)` calls.
### Why is this bad?
Will be optimized out by the compiler or should probably be replaced by a
`panic!()` or `unreachable!()`
### Example
```
assert!(false)
assert!(true)
const B: bool = false;
assert!(B)
```

View file

@ -0,0 +1,14 @@
### What it does
Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls.
### Why is this bad?
An assertion failure cannot output an useful message of the error.
### Known problems
The suggested replacement decreases the readability of code and log output.
### Example
```
assert!(r.is_ok());
assert!(r.is_err());
```

View file

@ -0,0 +1,28 @@
### What it does
Checks for `a = a op b` or `a = b commutative_op a`
patterns.
### Why is this bad?
These can be written as the shorter `a op= b`.
### Known problems
While forbidden by the spec, `OpAssign` traits may have
implementations that differ from the regular `Op` impl.
### Example
```
let mut a = 5;
let b = 0;
// ...
a = a + b;
```
Use instead:
```
let mut a = 5;
let b = 0;
// ...
a += b;
```

View file

@ -0,0 +1,28 @@
### What it does
Checks for async blocks that yield values of types
that can themselves be awaited.
### Why is this bad?
An await is likely missing.
### Example
```
async fn foo() {}
fn bar() {
let x = async {
foo()
};
}
```
Use instead:
```
async fn foo() {}
fn bar() {
let x = async {
foo().await
};
}
```

View file

@ -0,0 +1,29 @@
### What it does
Allows users to configure types which should not be held across `await`
suspension points.
### Why is this bad?
There are some types which are perfectly "safe" to be used concurrently
from a memory access perspective but will cause bugs at runtime if they
are held in such a way.
### Example
```
await-holding-invalid-types = [
# You can specify a type name
"CustomLockType",
# You can (optionally) specify a reason
{ path = "OtherCustomLockType", reason = "Relies on a thread local" }
]
```
```
struct CustomLockType;
struct OtherCustomLockType;
async fn foo() {
let _x = CustomLockType;
let _y = OtherCustomLockType;
baz().await; // Lint violation
}
```

View file

@ -0,0 +1,51 @@
### What it does
Checks for calls to await while holding a non-async-aware MutexGuard.
### Why is this bad?
The Mutex types found in std::sync and parking_lot
are not designed to operate in an async context across await points.
There are two potential solutions. One is to use an async-aware Mutex
type. Many asynchronous foundation crates provide such a Mutex type. The
other solution is to ensure the mutex is unlocked before calling await,
either by introducing a scope or an explicit call to Drop::drop.
### Known problems
Will report false positive for explicitly dropped guards
([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is
to wrap the `.lock()` call in a block instead of explicitly dropping the guard.
### Example
```
async fn foo(x: &Mutex<u32>) {
let mut guard = x.lock().unwrap();
*guard += 1;
baz().await;
}
async fn bar(x: &Mutex<u32>) {
let mut guard = x.lock().unwrap();
*guard += 1;
drop(guard); // explicit drop
baz().await;
}
```
Use instead:
```
async fn foo(x: &Mutex<u32>) {
{
let mut guard = x.lock().unwrap();
*guard += 1;
}
baz().await;
}
async fn bar(x: &Mutex<u32>) {
{
let mut guard = x.lock().unwrap();
*guard += 1;
} // guard dropped here at end of scope
baz().await;
}
```

View file

@ -0,0 +1,47 @@
### What it does
Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`.
### Why is this bad?
`RefCell` refs only check for exclusive mutable access
at runtime. Holding onto a `RefCell` ref across an `await` suspension point
risks panics from a mutable ref shared while other refs are outstanding.
### Known problems
Will report false positive for explicitly dropped refs
([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)). A workaround for this is
to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref.
### Example
```
async fn foo(x: &RefCell<u32>) {
let mut y = x.borrow_mut();
*y += 1;
baz().await;
}
async fn bar(x: &RefCell<u32>) {
let mut y = x.borrow_mut();
*y += 1;
drop(y); // explicit drop
baz().await;
}
```
Use instead:
```
async fn foo(x: &RefCell<u32>) {
{
let mut y = x.borrow_mut();
*y += 1;
}
baz().await;
}
async fn bar(x: &RefCell<u32>) {
{
let mut y = x.borrow_mut();
*y += 1;
} // y dropped here at end of scope
baz().await;
}
```

30
src/docs/bad_bit_mask.txt Normal file
View file

@ -0,0 +1,30 @@
### What it does
Checks for incompatible bit masks in comparisons.
The formula for detecting if an expression of the type `_ <bit_op> m
<cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
{`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
table:
|Comparison |Bit Op|Example |is always|Formula |
|------------|------|-------------|---------|----------------------|
|`==` or `!=`| `&` |`x & 2 == 3` |`false` |`c & m != c` |
|`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` |
|`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` |
|`==` or `!=`| `\|` |`x \| 1 == 0`|`false` |`c \| m != c` |
|`<` or `>=`| `\|` |`x \| 1 < 1` |`false` |`m >= c` |
|`<=` or `>` | `\|` |`x \| 1 > 0` |`true` |`m > c` |
### Why is this bad?
If the bits that the comparison cares about are always
set to zero or one by the bit mask, the comparison is constant `true` or
`false` (depending on mask, compared value, and operators).
So the code is actively misleading, and the only reason someone would write
this intentionally is to win an underhanded Rust contest or create a
test-case for this lint.
### Example
```
if (x & 1 == 2) { }
```

View file

@ -0,0 +1,22 @@
### What it does
Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
`_.or_else(|x| Err(y))`.
### Why is this bad?
Readability, this can be written more concisely as
`_.map(|x| y)` or `_.map_err(|x| y)`.
### Example
```
let _ = opt().and_then(|s| Some(s.len()));
let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) });
let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) });
```
The correct use would be:
```
let _ = opt().map(|s| s.len());
let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 });
let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 });
```

View file

@ -0,0 +1,16 @@
### What it does
Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
### Why is this bad?
Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust.
These lints should only be enabled on a lint-by-lint basis and with careful consideration.
### Example
```
#![deny(clippy::restriction)]
```
Use instead:
```
#![deny(clippy::as_conversions)]
```

View file

@ -0,0 +1,21 @@
### What it does
Checks for `if` conditions that use blocks containing an
expression, statements or conditions that use closures with blocks.
### Why is this bad?
Style, using blocks in the condition makes it hard to read.
### Examples
```
if { true } { /* ... */ }
if { let x = somefunc(); x } { /* ... */ }
```
Use instead:
```
if true { /* ... */ }
let res = { let x = somefunc(); x };
if res { /* ... */ }
```

View file

@ -0,0 +1,16 @@
### What it does
This lint warns about boolean comparisons in assert-like macros.
### Why is this bad?
It is shorter to use the equivalent.
### Example
```
assert_eq!("a".is_empty(), false);
assert_ne!("a".is_empty(), true);
```
Use instead:
```
assert!(!"a".is_empty());
```

View file

@ -0,0 +1,18 @@
### What it does
Checks for expressions of the form `x == true`,
`x != true` and order comparisons such as `x < true` (or vice versa) and
suggest using the variable directly.
### Why is this bad?
Unnecessary code.
### Example
```
if x == true {}
if y == false {}
```
use `x` directly:
```
if x {}
if !y {}
```

View file

@ -0,0 +1,26 @@
### What it does
Instead of using an if statement to convert a bool to an int,
this lint suggests using a `from()` function or an `as` coercion.
### Why is this bad?
Coercion or `from()` is idiomatic way to convert bool to a number.
Both methods are guaranteed to return 1 for true, and 0 for false.
See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
### Example
```
if condition {
1_i64
} else {
0
};
```
Use instead:
```
i64::from(condition);
```
or
```
condition as i64;
```

View file

@ -0,0 +1,26 @@
### What it does
Checks for the usage of `&expr as *const T` or
`&mut expr as *mut T`, and suggest using `ptr::addr_of` or
`ptr::addr_of_mut` instead.
### Why is this bad?
This would improve readability and avoid creating a reference
that points to an uninitialized value or unaligned place.
Read the `ptr::addr_of` docs for more information.
### Example
```
let val = 1;
let p = &val as *const i32;
let mut val_mut = 1;
let p_mut = &mut val_mut as *mut i32;
```
Use instead:
```
let val = 1;
let p = std::ptr::addr_of!(val);
let mut val_mut = 1;
let p_mut = std::ptr::addr_of_mut!(val_mut);
```

View file

@ -0,0 +1,27 @@
### What it does
Checks for `&*(&T)`.
### Why is this bad?
Dereferencing and then borrowing a reference value has no effect in most cases.
### Known problems
False negative on such code:
```
let x = &12;
let addr_x = &x as *const _ as usize;
let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggered.
// But if we fix it, assert will fail.
assert_ne!(addr_x, addr_y);
```
### Example
```
let s = &String::new();
let a: &String = &* s;
```
Use instead:
```
let a: &String = s;
```

View file

@ -0,0 +1,40 @@
### What it does
Checks if `const` items which is interior mutable (e.g.,
contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
### Why is this bad?
Consts are copied everywhere they are referenced, i.e.,
every time you refer to the const a fresh instance of the `Cell` or `Mutex`
or `AtomicXxxx` will be created, which defeats the whole purpose of using
these types in the first place.
The `const` value should be stored inside a `static` item.
### Known problems
When an enum has variants with interior mutability, use of its non
interior mutable variants can generate false positives. See issue
[#3962](https://github.com/rust-lang/rust-clippy/issues/3962)
Types that have underlying or potential interior mutability trigger the lint whether
the interior mutable field is used or not. See issues
[#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
[#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
### Example
```
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
```
Use instead:
```
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
static STATIC_ATOM: AtomicUsize = CONST_ATOM;
STATIC_ATOM.store(9, SeqCst);
assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
```

19
src/docs/borrowed_box.txt Normal file
View file

@ -0,0 +1,19 @@
### What it does
Checks for use of `&Box<T>` anywhere in the code.
Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
### Why is this bad?
A `&Box<T>` parameter requires the function caller to box `T` first before passing it to a function.
Using `&T` defines a concrete type for the parameter and generalizes the function, this would also
auto-deref to `&T` at the function call site if passed a `&Box<T>`.
### Example
```
fn foo(bar: &Box<T>) { ... }
```
Better:
```
fn foo(bar: &T) { ... }
```

View file

@ -0,0 +1,23 @@
### What it does
Checks for use of `Box<T>` where T is a collection such as Vec anywhere in the code.
Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
### Why is this bad?
Collections already keeps their contents in a separate area on
the heap. So if you `Box` them, you just add another level of indirection
without any benefit whatsoever.
### Example
```
struct X {
values: Box<Vec<Foo>>,
}
```
Better:
```
struct X {
values: Vec<Foo>,
}
```

18
src/docs/boxed_local.txt Normal file
View file

@ -0,0 +1,18 @@
### What it does
Checks for usage of `Box<T>` where an unboxed `T` would
work fine.
### Why is this bad?
This is an unnecessary allocation, and bad for
performance. It is only necessary to allocate if you wish to move the box
into something.
### Example
```
fn foo(x: Box<u32>) {}
```
Use instead:
```
fn foo(x: u32) {}
```

View file

@ -0,0 +1,32 @@
### What it does
Checks if the `if` and `else` block contain shared code that can be
moved out of the blocks.
### Why is this bad?
Duplicate code is less maintainable.
### Known problems
* The lint doesn't check if the moved expressions modify values that are being used in
the if condition. The suggestion can in that case modify the behavior of the program.
See [rust-clippy#7452](https://github.com/rust-lang/rust-clippy/issues/7452)
### Example
```
let foo = if … {
println!("Hello World");
13
} else {
println!("Hello World");
42
};
```
Use instead:
```
println!("Hello World");
let foo = if … {
13
} else {
42
};
```

View file

@ -0,0 +1,15 @@
### What it does
Warns if a generic shadows a built-in type.
### Why is this bad?
This gives surprising type errors.
### Example
```
impl<u32> Foo<u32> {
fn impl_func(&self) -> u32 {
42
}
}
```

View file

@ -0,0 +1,18 @@
### What it does
It checks for `str::bytes().count()` and suggests replacing it with
`str::len()`.
### Why is this bad?
`str::bytes().count()` is longer and may not be as performant as using
`str::len()`.
### Example
```
"hello".bytes().count();
String::from("hello").bytes().count();
```
Use instead:
```
"hello".len();
String::from("hello").len();
```

16
src/docs/bytes_nth.txt Normal file
View file

@ -0,0 +1,16 @@
### What it does
Checks for the use of `.bytes().nth()`.
### Why is this bad?
`.as_bytes().get()` is more efficient and more
readable.
### Example
```
"Hello".bytes().nth(3);
```
Use instead:
```
"Hello".as_bytes().get(3);
```

View file

@ -0,0 +1,33 @@
### What it does
Checks to see if all common metadata is defined in
`Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata
### Why is this bad?
It will be more difficult for users to discover the
purpose of the crate, and key information related to it.
### Example
```
[package]
name = "clippy"
version = "0.0.212"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
license = "MIT OR Apache-2.0"
keywords = ["clippy", "lint", "plugin"]
categories = ["development-tools", "development-tools::cargo-plugins"]
```
Should include a description field like:
```
[package]
name = "clippy"
version = "0.0.212"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
license = "MIT OR Apache-2.0"
keywords = ["clippy", "lint", "plugin"]
categories = ["development-tools", "development-tools::cargo-plugins"]
```

View file

@ -0,0 +1,21 @@
### What it does
Checks for calls to `ends_with` with possible file extensions
and suggests to use a case-insensitive approach instead.
### Why is this bad?
`ends_with` is case-sensitive and may not detect files with a valid extension.
### Example
```
fn is_rust_file(filename: &str) -> bool {
filename.ends_with(".rs")
}
```
Use instead:
```
fn is_rust_file(filename: &str) -> bool {
let filename = std::path::Path::new(filename);
filename.extension()
.map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
}
```

View file

@ -0,0 +1,16 @@
### What it does
Checks for uses of the `abs()` method that cast the result to unsigned.
### Why is this bad?
The `unsigned_abs()` method avoids panic when called on the MIN value.
### Example
```
let x: i32 = -42;
let y: u32 = x.abs() as u32;
```
Use instead:
```
let x: i32 = -42;
let y: u32 = x.unsigned_abs();
```

View file

@ -0,0 +1,11 @@
### What it does
Checks for casts from an enum tuple constructor to an integer.
### Why is this bad?
The cast is easily confused with casting a c-like enum value to an integer.
### Example
```
enum E { X(i32) };
let _ = E::X as usize;
```

View file

@ -0,0 +1,12 @@
### What it does
Checks for casts from an enum type to an integral type which will definitely truncate the
value.
### Why is this bad?
The resulting integral value will not match the value of the variant it came from.
### Example
```
enum E { X = 256 };
let _ = E::X as u8;
```

View file

@ -0,0 +1,26 @@
### What it does
Checks for casts between numerical types that may
be replaced by safe conversion functions.
### Why is this bad?
Rust's `as` keyword will perform many kinds of
conversions, including silently lossy conversions. Conversion functions such
as `i32::from` will only perform lossless conversions. Using the conversion
functions prevents conversions from turning into silent lossy conversions if
the types of the input expressions ever change, and make it easier for
people reading the code to know that the conversion is lossless.
### Example
```
fn as_u64(x: u8) -> u64 {
x as u64
}
```
Using `::from` would look like this:
```
fn as_u64(x: u8) -> u64 {
u64::from(x)
}
```

View file

@ -0,0 +1,16 @@
### What it does
Checks for casts between numerical types that may
truncate large values. This is expected behavior, so the cast is `Allow` by
default.
### Why is this bad?
In some problem domains, it is good practice to avoid
truncation. This lint can be activated to help assess where additional
checks could be beneficial.
### Example
```
fn as_u8(x: u64) -> u8 {
x as u8
}
```

View file

@ -0,0 +1,17 @@
### What it does
Checks for casts from an unsigned type to a signed type of
the same size. Performing such a cast is a 'no-op' for the compiler,
i.e., nothing is changed at the bit level, and the binary representation of
the value is reinterpreted. This can cause wrapping if the value is too big
for the target signed type. However, the cast works as defined, so this lint
is `Allow` by default.
### Why is this bad?
While such a cast is not bad in itself, the results can
be surprising when this is not the intended behavior, as demonstrated by the
example below.
### Example
```
u32::MAX as i32; // will yield a value of `-1`
```

View file

@ -0,0 +1,19 @@
### What it does
Checks for casts from any numerical to a float type where
the receiving type cannot store all values from the original type without
rounding errors. This possible rounding is to be expected, so this lint is
`Allow` by default.
Basically, this warns on casting any integer with 32 or more bits to `f32`
or any 64-bit integer to `f64`.
### Why is this bad?
It's not bad at all. But in some applications it can be
helpful to know where precision loss can take place. This lint can help find
those places in the code.
### Example
```
let x = u64::MAX;
x as f64;
```

View file

@ -0,0 +1,21 @@
### What it does
Checks for casts, using `as` or `pointer::cast`,
from a less-strictly-aligned pointer to a more-strictly-aligned pointer
### Why is this bad?
Dereferencing the resulting pointer may be undefined
behavior.
### Known problems
Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
### Example
```
let _ = (&1u8 as *const u8) as *const u16;
let _ = (&mut 1u8 as *mut u8) as *mut u16;
(&1u8 as *const u8).cast::<u16>();
(&mut 1u8 as *mut u8).cast::<u16>();
```

View file

@ -0,0 +1,28 @@
### What it does
Checks for casts of `&T` to `&mut T` anywhere in the code.
### Why is this bad?
Its basically guaranteed to be undefined behavior.
`UnsafeCell` is the only way to obtain aliasable data that is considered
mutable.
### Example
```
fn x(r: &i32) {
unsafe {
*(r as *const _ as *mut _) += 1;
}
}
```
Instead consider using interior mutability types.
```
use std::cell::UnsafeCell;
fn x(r: &UnsafeCell<i32>) {
unsafe {
*r.get() += 1;
}
}
```

View file

@ -0,0 +1,15 @@
### What it does
Checks for casts from a signed to an unsigned numerical
type. In this case, negative values wrap around to large positive values,
which can be quite surprising in practice. However, as the cast works as
defined, this lint is `Allow` by default.
### Why is this bad?
Possibly surprising results. You can activate this lint
as a one-time check to see where numerical wrapping can arise.
### Example
```
let y: i8 = -1;
y as u128; // will return 18446744073709551615
```

View file

@ -0,0 +1,38 @@
### What it does
Checks for `as` casts between raw pointers to slices with differently sized elements.
### Why is this bad?
The produced raw pointer to a slice does not update its length metadata. The produced
pointer will point to a different number of bytes than the original pointer because the
length metadata of a raw slice pointer is in elements rather than bytes.
Producing a slice reference from the raw pointer will either create a slice with
less data (which can be surprising) or create a slice with more data and cause Undefined Behavior.
### Example
// Missing data
```
let a = [1_i32, 2, 3, 4];
let p = &a as *const [i32] as *const [u8];
unsafe {
println!("{:?}", &*p);
}
```
// Undefined Behavior (note: also potential alignment issues)
```
let a = [1_u8, 2, 3, 4];
let p = &a as *const [u8] as *const [u32];
unsafe {
println!("{:?}", &*p);
}
```
Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length
```
let a = [1_i32, 2, 3, 4];
let old_ptr = &a as *const [i32];
// The data pointer is cast to a pointer to the target `u8` not `[u8]`
// The length comes from the known length of 4 i32s times the 4 bytes per i32
let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16);
unsafe {
println!("{:?}", &*new_ptr);
}
```

View file

@ -0,0 +1,20 @@
### What it does
Checks for a raw slice being cast to a slice pointer
### Why is this bad?
This can result in multiple `&mut` references to the same location when only a pointer is
required.
`ptr::slice_from_raw_parts` is a safe alternative that doesn't require
the same [safety requirements] to be upheld.
### Example
```
let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _;
let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _;
```
Use instead:
```
let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len);
let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
```
[safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety

View file

@ -0,0 +1,21 @@
### What it does
Checks for expressions where a character literal is cast
to `u8` and suggests using a byte literal instead.
### Why is this bad?
In general, casting values to smaller types is
error-prone and should be avoided where possible. In the particular case of
converting a character literal to u8, it is easy to avoid by just using a
byte literal instead. As an added bonus, `b'a'` is even slightly shorter
than `'a' as u8`.
### Example
```
'x' as u8
```
A better version, using the byte literal:
```
b'x'
```

View file

@ -0,0 +1,17 @@
### What it does
Checks for usage of `_.chars().last()` or
`_.chars().next_back()` on a `str` to check if it ends with a given char.
### Why is this bad?
Readability, this can be written more concisely as
`_.ends_with(_)`.
### Example
```
name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
```
Use instead:
```
name.ends_with('_') || name.ends_with('-');
```

View file

@ -0,0 +1,19 @@
### What it does
Checks for usage of `.chars().next()` on a `str` to check
if it starts with a given char.
### Why is this bad?
Readability, this can be written more concisely as
`_.starts_with(_)`.
### Example
```
let name = "foo";
if name.chars().next() == Some('_') {};
```
Use instead:
```
let name = "foo";
if name.starts_with('_') {};
```

View file

@ -0,0 +1,15 @@
### What it does
Checks for explicit bounds checking when casting.
### Why is this bad?
Reduces the readability of statements & is error prone.
### Example
```
foo <= i32::MAX as u32;
```
Use instead:
```
i32::try_from(foo).is_ok();
```

View file

@ -0,0 +1,16 @@
### What it does
Checks for usage of `.clone()` on an `&&T`.
### Why is this bad?
Cloning an `&&T` copies the inner `&T`, instead of
cloning the underlying `T`.
### Example
```
fn main() {
let x = vec![1];
let y = &&x;
let z = y.clone();
println!("{:p} {:p}", *y, z); // prints out the same pointer
}
```

View file

@ -0,0 +1,11 @@
### What it does
Checks for usage of `.clone()` on a `Copy` type.
### Why is this bad?
The only reason `Copy` types implement `Clone` is for
generics, not for using the `clone` method on a concrete type.
### Example
```
42u64.clone();
```

View file

@ -0,0 +1,21 @@
### What it does
Checks for usage of `.clone()` on a ref-counted pointer,
(`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
function syntax instead (e.g., `Rc::clone(foo)`).
### Why is this bad?
Calling '.clone()' on an Rc, Arc, or Weak
can obscure the fact that only the pointer is being cloned, not the underlying
data.
### Example
```
let x = Rc::new(1);
x.clone();
```
Use instead:
```
Rc::clone(&x);
```

View file

@ -0,0 +1,16 @@
### What it does
Checks for usages of `cloned()` on an `Iterator` or `Option` where
`copied()` could be used instead.
### Why is this bad?
`copied()` is better because it guarantees that the type being cloned
implements `Copy`.
### Example
```
[1, 2, 3].iter().cloned();
```
Use instead:
```
[1, 2, 3].iter().copied();
```

16
src/docs/cmp_nan.txt Normal file
View file

@ -0,0 +1,16 @@
### What it does
Checks for comparisons to NaN.
### Why is this bad?
NaN does not compare meaningfully to anything not
even itself so those comparisons are simply wrong.
### Example
```
if x == f32::NAN { }
```
Use instead:
```
if x.is_nan() { }
```

23
src/docs/cmp_null.txt Normal file
View file

@ -0,0 +1,23 @@
### What it does
This lint checks for equality comparisons with `ptr::null`
### Why is this bad?
It's easier and more readable to use the inherent
`.is_null()`
method instead
### Example
```
use std::ptr;
if x == ptr::null {
// ..
}
```
Use instead:
```
if x.is_null() {
// ..
}
```

18
src/docs/cmp_owned.txt Normal file
View file

@ -0,0 +1,18 @@
### What it does
Checks for conversions to owned values just for the sake
of a comparison.
### Why is this bad?
The comparison can operate on a reference, so creating
an owned value effectively throws it away directly afterwards, which is
needlessly consuming code and heap space.
### Example
```
if x.to_owned() == y {}
```
Use instead:
```
if x == y {}
```

View file

@ -0,0 +1,13 @@
### What it does
Checks for methods with high cognitive complexity.
### Why is this bad?
Methods of high cognitive complexity tend to be hard to
both read and maintain. Also LLVM will tend to optimize small methods better.
### Known problems
Sometimes it's hard to find a way to reduce the
complexity.
### Example
You'll see it when you get the warning.

View file

@ -0,0 +1,29 @@
### What it does
Checks for collapsible `else { if ... }` expressions
that can be collapsed to `else if ...`.
### Why is this bad?
Each `if`-statement adds one level of nesting, which
makes code look more complex than it really is.
### Example
```
if x {
} else {
if y {
}
}
```
Should be written:
```
if x {
} else if y {
}
```

View file

@ -0,0 +1,23 @@
### What it does
Checks for nested `if` statements which can be collapsed
by `&&`-combining their conditions.
### Why is this bad?
Each `if`-statement adds one level of nesting, which
makes code look more complex than it really is.
### Example
```
if x {
if y {
// …
}
}
```
Use instead:
```
if x && y {
// …
}
```

View file

@ -0,0 +1,31 @@
### What it does
Finds nested `match` or `if let` expressions where the patterns may be "collapsed" together
without adding any branches.
Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only
cases where merging would most likely make the code more readable.
### Why is this bad?
It is unnecessarily verbose and complex.
### Example
```
fn func(opt: Option<Result<u64, String>>) {
let n = match opt {
Some(n) => match n {
Ok(n) => n,
_ => return,
}
None => return,
};
}
```
Use instead:
```
fn func(opt: Option<Result<u64, String>>) {
let n = match opt {
Some(Ok(n)) => n,
_ => return,
};
}
```

View file

@ -0,0 +1,19 @@
### What it does
Checks for consecutive calls to `str::replace` (2 or more)
that can be collapsed into a single call.
### Why is this bad?
Consecutive `str::replace` calls scan the string multiple times
with repetitive code.
### Example
```
let hello = "hesuo worpd"
.replace('s', "l")
.replace("u", "l")
.replace('p', "l");
```
Use instead:
```
let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l");
```

View file

@ -0,0 +1,36 @@
### What it does
Checks comparison chains written with `if` that can be
rewritten with `match` and `cmp`.
### Why is this bad?
`if` is not guaranteed to be exhaustive and conditionals can get
repetitive
### Known problems
The match statement may be slower due to the compiler
not inlining the call to cmp. See issue [#5354](https://github.com/rust-lang/rust-clippy/issues/5354)
### Example
```
fn f(x: u8, y: u8) {
if x > y {
a()
} else if x < y {
b()
} else {
c()
}
}
```
Use instead:
```
use std::cmp::Ordering;
fn f(x: u8, y: u8) {
match x.cmp(&y) {
Ordering::Greater => a(),
Ordering::Less => b(),
Ordering::Equal => c()
}
}
```

View file

@ -0,0 +1,31 @@
### What it does
Checks for comparing to an empty slice such as `""` or `[]`,
and suggests using `.is_empty()` where applicable.
### Why is this bad?
Some structures can answer `.is_empty()` much faster
than checking for equality. So it is good to get into the habit of using
`.is_empty()`, and having it is cheap.
Besides, it makes the intent clearer than a manual comparison in some contexts.
### Example
```
if s == "" {
..
}
if arr == [] {
..
}
```
Use instead:
```
if s.is_empty() {
..
}
if arr.is_empty() {
..
}
```

View file

@ -0,0 +1,20 @@
### What it does
Checks for types that implement `Copy` as well as
`Iterator`.
### Why is this bad?
Implicit copies can be confusing when working with
iterator combinators.
### Example
```
#[derive(Copy, Clone)]
struct Countdown(u8);
impl Iterator for Countdown {
// ...
}
let a: Vec<_> = my_iterator.take(1).collect();
let b: Vec<_> = my_iterator.collect();
```

View file

@ -0,0 +1,35 @@
### What it does
Checks for use of `crate` as opposed to `$crate` in a macro definition.
### Why is this bad?
`crate` refers to the macro call's crate, whereas `$crate` refers to the macro definition's
crate. Rarely is the former intended. See:
https://doc.rust-lang.org/reference/macros-by-example.html#hygiene
### Example
```
#[macro_export]
macro_rules! print_message {
() => {
println!("{}", crate::MESSAGE);
};
}
pub const MESSAGE: &str = "Hello!";
```
Use instead:
```
#[macro_export]
macro_rules! print_message {
() => {
println!("{}", $crate::MESSAGE);
};
}
pub const MESSAGE: &str = "Hello!";
```
Note that if the use of `crate` is intentional, an `allow` attribute can be applied to the
macro definition, e.g.:
```
#[allow(clippy::crate_in_macro_def)]
macro_rules! ok { ... crate::foo ... }
```

15
src/docs/create_dir.txt Normal file
View file

@ -0,0 +1,15 @@
### What it does
Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead.
### Why is this bad?
Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`.
### Example
```
std::fs::create_dir("foo");
```
Use instead:
```
std::fs::create_dir_all("foo");
```

View file

@ -0,0 +1,12 @@
### What it does
Checks for transmutes between a type `T` and `*T`.
### Why is this bad?
It's easy to mistakenly transmute between a type and a
pointer to that type.
### Example
```
core::intrinsics::transmute(t) // where the result type is the same as
// `*t` or `&t`'s
```

16
src/docs/dbg_macro.txt Normal file
View file

@ -0,0 +1,16 @@
### What it does
Checks for usage of dbg!() macro.
### Why is this bad?
`dbg!` macro is intended as a debugging tool. It
should not be in version control.
### Example
```
dbg!(true)
```
Use instead:
```
true
```

View file

@ -0,0 +1,18 @@
### What it does
Checks for function/method calls with a mutable
parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros.
### Why is this bad?
In release builds `debug_assert!` macros are optimized out by the
compiler.
Therefore mutating something in a `debug_assert!` macro results in different behavior
between a release and debug build.
### Example
```
debug_assert_eq!(vec![3].pop(), Some(3));
// or
debug_assert!(takes_a_mut_parameter(&mut x));
```

View file

@ -0,0 +1,13 @@
### What it does
Warns if there is a better representation for a numeric literal.
### Why is this bad?
Especially for big powers of 2 a hexadecimal representation is more
readable than a decimal representation.
### Example
```
`255` => `0xFF`
`65_535` => `0xFFFF`
`4_042_322_160` => `0xF0F0_F0F0`
```

View file

@ -0,0 +1,46 @@
### What it does
Checks for declaration of `const` items which is interior
mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
### Why is this bad?
Consts are copied everywhere they are referenced, i.e.,
every time you refer to the const a fresh instance of the `Cell` or `Mutex`
or `AtomicXxxx` will be created, which defeats the whole purpose of using
these types in the first place.
The `const` should better be replaced by a `static` item if a global
variable is wanted, or replaced by a `const fn` if a constructor is wanted.
### Known problems
A "non-constant" const item is a legacy way to supply an
initialized value to downstream `static` items (e.g., the
`std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
and this lint should be suppressed.
Even though the lint avoids triggering on a constant whose type has enums that have variants
with interior mutability, and its value uses non interior mutable variants (see
[#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and
[#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples);
it complains about associated constants without default values only based on its types;
which might not be preferable.
There're other enums plus associated constants cases that the lint cannot handle.
Types that have underlying or potential interior mutability trigger the lint whether
the interior mutable field is used or not. See issues
[#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
### Example
```
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
```
Use instead:
```
static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15);
STATIC_ATOM.store(9, SeqCst);
assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
```

View file

@ -0,0 +1,15 @@
### What it does
It checks for `std::iter::Empty::default()` and suggests replacing it with
`std::iter::empty()`.
### Why is this bad?
`std::iter::empty()` is the more idiomatic way.
### Example
```
let _ = std::iter::Empty::<usize>::default();
let iter: std::iter::Empty<usize> = std::iter::Empty::default();
```
Use instead:
```
let _ = std::iter::empty::<usize>();
let iter: std::iter::Empty<usize> = std::iter::empty();
```

View file

@ -0,0 +1,28 @@
### What it does
Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type
inference.
Default numeric fallback means that if numeric types have not yet been bound to concrete
types at the end of type inference, then integer type is bound to `i32`, and similarly
floating type is bound to `f64`.
See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback.
### Why is this bad?
For those who are very careful about types, default numeric fallback
can be a pitfall that cause unexpected runtime behavior.
### Known problems
This lint can only be allowed at the function level or above.
### Example
```
let i = 10;
let f = 1.23;
```
Use instead:
```
let i = 10i32;
let f = 1.23f64;
```

View file

@ -0,0 +1,16 @@
### What it does
Checks for literal calls to `Default::default()`.
### Why is this bad?
It's easier for the reader if the name of the type is used, rather than the
generic `Default`.
### Example
```
let s: String = Default::default();
```
Use instead:
```
let s = String::default();
```

View file

@ -0,0 +1,36 @@
### What it does
Displays a warning when a union is declared with the default representation (without a `#[repr(C)]` attribute).
### Why is this bad?
Unions in Rust have unspecified layout by default, despite many people thinking that they
lay out each field at the start of the union (like C does). That is, there are no guarantees
about the offset of the fields for unions with multiple non-ZST fields without an explicitly
specified layout. These cases may lead to undefined behavior in unsafe blocks.
### Example
```
union Foo {
a: i32,
b: u32,
}
fn main() {
let _x: u32 = unsafe {
Foo { a: 0_i32 }.b // Undefined behavior: `b` is allowed to be padding
};
}
```
Use instead:
```
#[repr(C)]
union Foo {
a: i32,
b: u32,
}
fn main() {
let _x: u32 = unsafe {
Foo { a: 0_i32 }.b // Now defined behavior, this is just an i32 -> u32 transmute
};
}
```

View file

@ -0,0 +1,24 @@
### What it does
Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it
with `#[rustfmt::skip]`.
### Why is this bad?
Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690))
are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes.
### Known problems
This lint doesn't detect crate level inner attributes, because they get
processed before the PreExpansionPass lints get executed. See
[#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765)
### Example
```
#[cfg_attr(rustfmt, rustfmt_skip)]
fn main() { }
```
Use instead:
```
#[rustfmt::skip]
fn main() { }
```

View file

@ -0,0 +1,13 @@
### What it does
Checks for `#[deprecated]` annotations with a `since`
field that is not a valid semantic version.
### Why is this bad?
For checking the version of the deprecation, it must be
a valid semver. Failing that, the contained information is useless.
### Example
```
#[deprecated(since = "forever")]
fn something_else() { /* ... */ }
```

22
src/docs/deref_addrof.txt Normal file
View file

@ -0,0 +1,22 @@
### What it does
Checks for usage of `*&` and `*&mut` in expressions.
### Why is this bad?
Immediately dereferencing a reference is no-op and
makes the code less clear.
### Known problems
Multiple dereference/addrof pairs are not handled so
the suggested fix for `x = **&&y` is `x = *&y`, which is still incorrect.
### Example
```
let a = f(*&mut b);
let c = *&d;
```
Use instead:
```
let a = f(b);
let c = d;
```

View file

@ -0,0 +1,17 @@
### What it does
Checks for slicing expressions which are equivalent to dereferencing the
value.
### Why is this bad?
Some people may prefer to dereference rather than slice.
### Example
```
let vec = vec![1, 2, 3];
let slice = &vec[..];
```
Use instead:
```
let vec = vec![1, 2, 3];
let slice = &*vec;
```

View file

@ -0,0 +1,35 @@
### What it does
Detects manual `std::default::Default` implementations that are identical to a derived implementation.
### Why is this bad?
It is less concise.
### Example
```
struct Foo {
bar: bool
}
impl Default for Foo {
fn default() -> Self {
Self {
bar: false
}
}
}
```
Use instead:
```
#[derive(Default)]
struct Foo {
bar: bool
}
```
### Known problems
Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925)
in generic types and the user defined `impl` maybe is more generalized or
specialized than what derive will produce. This lint can't detect the manual `impl`
has exactly equal bounds, and therefore this lint is disabled for types with
generic parameters.

View file

@ -0,0 +1,23 @@
### What it does
Checks for deriving `Hash` but implementing `PartialEq`
explicitly or vice versa.
### Why is this bad?
The implementation of these traits must agree (for
example for use with `HashMap`) so its probably a bad idea to use a
default-generated `Hash` implementation with an explicitly defined
`PartialEq`. In particular, the following must hold for any type:
```
k1 == k2 ⇒ hash(k1) == hash(k2)
```
### Example
```
#[derive(Hash)]
struct Foo;
impl PartialEq for Foo {
...
}
```

View file

@ -0,0 +1,44 @@
### What it does
Checks for deriving `Ord` but implementing `PartialOrd`
explicitly or vice versa.
### Why is this bad?
The implementation of these traits must agree (for
example for use with `sort`) so its probably a bad idea to use a
default-generated `Ord` implementation with an explicitly defined
`PartialOrd`. In particular, the following must hold for any type
implementing `Ord`:
```
k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
```
### Example
```
#[derive(Ord, PartialEq, Eq)]
struct Foo;
impl PartialOrd for Foo {
...
}
```
Use instead:
```
#[derive(PartialEq, Eq)]
struct Foo;
impl PartialOrd for Foo {
fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Foo {
...
}
```
or, if you don't need a custom ordering:
```
#[derive(Ord, PartialOrd, PartialEq, Eq)]
struct Foo;
```

View file

@ -0,0 +1,25 @@
### What it does
Checks for types that derive `PartialEq` and could implement `Eq`.
### Why is this bad?
If a type `T` derives `PartialEq` and all of its members implement `Eq`,
then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used
in APIs that require `Eq` types. It also allows structs containing `T` to derive
`Eq` themselves.
### Example
```
#[derive(PartialEq)]
struct Foo {
i_am_eq: i32,
i_am_eq_too: Vec<String>,
}
```
Use instead:
```
#[derive(PartialEq, Eq)]
struct Foo {
i_am_eq: i32,
i_am_eq_too: Vec<String>,
}
```

View file

@ -0,0 +1,41 @@
### What it does
Denies the configured methods and functions in clippy.toml
Note: Even though this lint is warn-by-default, it will only trigger if
methods are defined in the clippy.toml file.
### Why is this bad?
Some methods are undesirable in certain contexts, and it's beneficial to
lint for them as needed.
### Example
An example clippy.toml configuration:
```
disallowed-methods = [
# Can use a string as the path of the disallowed method.
"std::boxed::Box::new",
# Can also use an inline table with a `path` key.
{ path = "std::time::Instant::now" },
# When using an inline table, can add a `reason` for why the method
# is disallowed.
{ path = "std::vec::Vec::leak", reason = "no leaking memory" },
]
```
```
// Example code where clippy issues a warning
let xs = vec![1, 2, 3, 4];
xs.leak(); // Vec::leak is disallowed in the config.
// The diagnostic contains the message "no leaking memory".
let _now = Instant::now(); // Instant::now is disallowed in the config.
let _box = Box::new(3); // Box::new is disallowed in the config.
```
Use instead:
```
// Example code which does not raise clippy warning
let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config.
xs.push(123); // Vec::push is _not_ disallowed in the config.
```

View file

@ -0,0 +1,12 @@
### What it does
Checks for usage of disallowed names for variables, such
as `foo`.
### Why is this bad?
These names are usually placeholder names and should be
avoided.
### Example
```
let foo = 3.14;
```

View file

@ -0,0 +1,32 @@
### What it does
Checks for usage of unicode scripts other than those explicitly allowed
by the lint config.
This lint doesn't take into account non-text scripts such as `Unknown` and `Linear_A`.
It also ignores the `Common` script type.
While configuring, be sure to use official script name [aliases] from
[the list of supported scripts][supported_scripts].
See also: [`non_ascii_idents`].
[aliases]: http://www.unicode.org/reports/tr24/tr24-31.html#Script_Value_Aliases
[supported_scripts]: https://www.unicode.org/iso15924/iso15924-codes.html
### Why is this bad?
It may be not desired to have many different scripts for
identifiers in the codebase.
Note that if you only want to allow plain English, you might want to use
built-in [`non_ascii_idents`] lint instead.
[`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents
### Example
```
// Assuming that `clippy.toml` contains the following line:
// allowed-locales = ["Latin", "Cyrillic"]
let counter = 10; // OK, latin is allowed.
let счётчик = 10; // OK, cyrillic is allowed.
let zähler = 10; // OK, it's still latin.
let カウンタ = 10; // Will spawn the lint.
```

View file

@ -0,0 +1,33 @@
### What it does
Denies the configured types in clippy.toml.
Note: Even though this lint is warn-by-default, it will only trigger if
types are defined in the clippy.toml file.
### Why is this bad?
Some types are undesirable in certain contexts.
### Example:
An example clippy.toml configuration:
```
disallowed-types = [
# Can use a string as the path of the disallowed type.
"std::collections::BTreeMap",
# Can also use an inline table with a `path` key.
{ path = "std::net::TcpListener" },
# When using an inline table, can add a `reason` for why the type
# is disallowed.
{ path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
]
```
```
use std::collections::BTreeMap;
// or its use
let x = std::collections::BTreeMap::new();
```
Use instead:
```
// A similar type that is allowed by the config
use std::collections::HashMap;
```

View file

@ -0,0 +1,19 @@
### What it does
Checks for diverging calls that are not match arms or
statements.
### Why is this bad?
It is often confusing to read. In addition, the
sub-expression evaluation order for Rust is not well documented.
### Known problems
Someone might want to use `some_bool || panic!()` as a
shorthand.
### Example
```
let a = b() || panic!() || c();
// `c()` is dead, `panic!()` is only called if `b()` returns `false`
let x = (a, b, c, panic!());
// can simply be replaced by `panic!()`
```

View file

@ -0,0 +1,16 @@
### What it does
Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks)
outside of code blocks
### Why is this bad?
It is likely a typo when defining an intra-doc link
### Example
```
/// See also: ['foo']
fn bar() {}
```
Use instead:
```
/// See also: [`foo`]
fn bar() {}
```

35
src/docs/doc_markdown.txt Normal file
View file

@ -0,0 +1,35 @@
### What it does
Checks for the presence of `_`, `::` or camel-case words
outside ticks in documentation.
### Why is this bad?
*Rustdoc* supports markdown formatting, `_`, `::` and
camel-case probably indicates some code which should be included between
ticks. `_` can also be used for emphasis in markdown, this lint tries to
consider that.
### Known problems
Lots of bad docs wont be fixed, what the lint checks
for is limited, and there are still false positives. HTML elements and their
content are not linted.
In addition, when writing documentation comments, including `[]` brackets
inside a link text would trip the parser. Therefore, documenting link with
`[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec
would fail.
### Examples
```
/// Do something with the foo_bar parameter. See also
/// that::other::module::foo.
// ^ `foo_bar` and `that::other::module::foo` should be ticked.
fn doit(foo_bar: usize) {}
```
```
// Link text with `[]` brackets should be written as following:
/// Consume the array and return the inner
/// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec].
/// [SmallVec]: SmallVec
fn main() {}
```

View file

@ -0,0 +1,17 @@
### What it does
Checks for double comparisons that could be simplified to a single expression.
### Why is this bad?
Readability.
### Example
```
if x == y || x < y {}
```
Use instead:
```
if x <= y {}
```

View file

@ -0,0 +1,17 @@
### What it does
Checks for a `#[must_use]` attribute without
further information on functions and methods that return a type already
marked as `#[must_use]`.
### Why is this bad?
The attribute isn't needed. Not using the result
will already be reported. Alternatively, one can add some text to the
attribute to improve the lint message.
### Examples
```
#[must_use]
fn double_must_use() -> Result<(), ()> {
unimplemented!();
}
```

12
src/docs/double_neg.txt Normal file
View file

@ -0,0 +1,12 @@
### What it does
Detects expressions of the form `--x`.
### Why is this bad?
It can mislead C/C++ programmers to think `x` was
decremented.
### Example
```
let mut x = 3;
--x;
```

View file

@ -0,0 +1,24 @@
### What it does
Checks for unnecessary double parentheses.
### Why is this bad?
This makes code harder to read and might indicate a
mistake.
### Example
```
fn simple_double_parens() -> i32 {
((0))
}
foo((0));
```
Use instead:
```
fn simple_no_parens() -> i32 {
0
}
foo(0);
```

15
src/docs/drop_copy.txt Normal file
View file

@ -0,0 +1,15 @@
### What it does
Checks for calls to `std::mem::drop` with a value
that derives the Copy trait
### Why is this bad?
Calling `std::mem::drop` [does nothing for types that
implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the
value will be copied and moved into the function on invocation.
### Example
```
let x: i32 = 42; // i32 implements Copy
std::mem::drop(x) // A copy of x is passed to the function, leaving the
// original unaffected
```

View file

@ -0,0 +1,13 @@
### What it does
Checks for calls to `std::mem::drop` with a value that does not implement `Drop`.
### Why is this bad?
Calling `std::mem::drop` is no different than dropping such a type. A different value may
have been intended.
### Example
```
struct Foo;
let x = Foo;
std::mem::drop(x);
```

Some files were not shown because too many files have changed in this diff Show more