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:
commit
30e4532153
@ -3,7 +3,7 @@
|
||||
use indoc::writedoc;
|
||||
use itertools::Itertools;
|
||||
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt::Write;
|
||||
use std::fs::{self, OpenOptions};
|
||||
@ -124,6 +124,8 @@ fn generate_lint_files(
|
||||
let content = gen_lint_group_list("all", all_group_lints);
|
||||
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)) {
|
||||
let content = gen_lint_group_list(&lint_group, lints.iter());
|
||||
process_file(
|
||||
@ -140,6 +142,62 @@ fn generate_lint_files(
|
||||
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() {
|
||||
let (lint_list, _, _) = gather_all();
|
||||
let usable_lints = Lint::usable_lints(&lint_list);
|
||||
@ -589,17 +647,26 @@ struct Lint {
|
||||
desc: String,
|
||||
module: String,
|
||||
declaration_range: Range<usize>,
|
||||
documentation: String,
|
||||
}
|
||||
|
||||
impl Lint {
|
||||
#[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 {
|
||||
name: name.to_lowercase(),
|
||||
group: group.into(),
|
||||
desc: remove_line_splices(desc),
|
||||
module: module.into(),
|
||||
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",
|
||||
) {
|
||||
let start = range.start;
|
||||
|
||||
let mut iter = iter
|
||||
.by_ref()
|
||||
.filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
|
||||
let mut docs = String::with_capacity(128);
|
||||
let mut iter = iter.by_ref().filter(|t| !matches!(t.token_kind, TokenKind::Whitespace));
|
||||
// matches `!{`
|
||||
match_tokens!(iter, Bang OpenBrace);
|
||||
match iter.next() {
|
||||
// #[clippy::version = "version"] pub
|
||||
Some(LintDeclSearchResult {
|
||||
token_kind: TokenKind::Pound,
|
||||
..
|
||||
}) => {
|
||||
match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident);
|
||||
},
|
||||
// pub
|
||||
Some(LintDeclSearchResult {
|
||||
token_kind: TokenKind::Ident,
|
||||
..
|
||||
}) => (),
|
||||
_ => continue,
|
||||
let mut in_code = false;
|
||||
while let Some(t) = iter.next() {
|
||||
match t.token_kind {
|
||||
TokenKind::LineComment { .. } => {
|
||||
if let Some(line) = t.content.strip_prefix("/// ").or_else(|| t.content.strip_prefix("///")) {
|
||||
if line.starts_with("```") {
|
||||
docs += "```\n";
|
||||
in_code = !in_code;
|
||||
} else if !(in_code && line.starts_with("# ")) {
|
||||
docs += line;
|
||||
docs.push('\n');
|
||||
}
|
||||
}
|
||||
},
|
||||
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!(
|
||||
iter,
|
||||
@ -890,7 +965,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
|
||||
..
|
||||
}) = 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 @@ fn test_parse_contents() {
|
||||
"\"really long text\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new(
|
||||
"doc_markdown",
|
||||
@ -1127,6 +1203,7 @@ fn test_parse_contents() {
|
||||
"\"single line\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
];
|
||||
assert_eq!(expected, result);
|
||||
@ -1166,6 +1243,7 @@ fn test_usable_lints() {
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new(
|
||||
"should_assert_eq2",
|
||||
@ -1173,6 +1251,7 @@ fn test_usable_lints() {
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new(
|
||||
"should_assert_eq2",
|
||||
@ -1180,6 +1259,7 @@ fn test_usable_lints() {
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
];
|
||||
let expected = vec![Lint::new(
|
||||
@ -1188,6 +1268,7 @@ fn test_usable_lints() {
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
)];
|
||||
assert_eq!(expected, Lint::usable_lints(&lints));
|
||||
}
|
||||
@ -1195,22 +1276,51 @@ fn test_usable_lints() {
|
||||
#[test]
|
||||
fn test_by_lint_group() {
|
||||
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(
|
||||
"should_assert_eq2",
|
||||
"group2",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
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();
|
||||
expected.insert(
|
||||
"group1".to_string(),
|
||||
vec![
|
||||
Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
Lint::new(
|
||||
"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(
|
||||
@ -1221,6 +1331,7 @@ fn test_by_lint_group() {
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
)],
|
||||
);
|
||||
assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
|
||||
@ -1259,9 +1370,30 @@ fn test_gen_deprecated() {
|
||||
#[test]
|
||||
fn test_gen_lint_group_list() {
|
||||
let lints = vec![
|
||||
Lint::new("abc", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
Lint::new("internal", "internal_style", "\"abc\"", "module_name", Range::default()),
|
||||
Lint::new(
|
||||
"abc",
|
||||
"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()
|
||||
+ &[
|
||||
|
596
src/docs.rs
Normal file
596
src/docs.rs
Normal 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",
|
||||
|
||||
}
|
25
src/docs/absurd_extreme_comparisons.txt
Normal file
25
src/docs/absurd_extreme_comparisons.txt
Normal 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 {}
|
||||
```
|
18
src/docs/alloc_instead_of_core.txt
Normal file
18
src/docs/alloc_instead_of_core.txt
Normal 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;
|
||||
```
|
22
src/docs/allow_attributes_without_reason.txt
Normal file
22
src/docs/allow_attributes_without_reason.txt
Normal 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")]
|
||||
```
|
15
src/docs/almost_complete_letter_range.txt
Normal file
15
src/docs/almost_complete_letter_range.txt
Normal 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';
|
||||
```
|
15
src/docs/almost_swapped.txt
Normal file
15
src/docs/almost_swapped.txt
Normal 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);
|
||||
```
|
24
src/docs/approx_constant.txt
Normal file
24
src/docs/approx_constant.txt
Normal 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
28
src/docs/arithmetic.txt
Normal 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.
|
32
src/docs/as_conversions.txt
Normal file
32
src/docs/as_conversions.txt
Normal 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"));
|
||||
```
|
21
src/docs/as_underscore.txt
Normal file
21
src/docs/as_underscore.txt
Normal 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);
|
||||
```
|
14
src/docs/assertions_on_constants.txt
Normal file
14
src/docs/assertions_on_constants.txt
Normal 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)
|
||||
```
|
14
src/docs/assertions_on_result_states.txt
Normal file
14
src/docs/assertions_on_result_states.txt
Normal 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());
|
||||
```
|
28
src/docs/assign_op_pattern.txt
Normal file
28
src/docs/assign_op_pattern.txt
Normal 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;
|
||||
```
|
28
src/docs/async_yields_async.txt
Normal file
28
src/docs/async_yields_async.txt
Normal 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
|
||||
};
|
||||
}
|
||||
```
|
29
src/docs/await_holding_invalid_type.txt
Normal file
29
src/docs/await_holding_invalid_type.txt
Normal 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
|
||||
}
|
||||
```
|
51
src/docs/await_holding_lock.txt
Normal file
51
src/docs/await_holding_lock.txt
Normal 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;
|
||||
}
|
||||
```
|
47
src/docs/await_holding_refcell_ref.txt
Normal file
47
src/docs/await_holding_refcell_ref.txt
Normal 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
30
src/docs/bad_bit_mask.txt
Normal 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) { }
|
||||
```
|
22
src/docs/bind_instead_of_map.txt
Normal file
22
src/docs/bind_instead_of_map.txt
Normal 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 });
|
||||
```
|
16
src/docs/blanket_clippy_restriction_lints.txt
Normal file
16
src/docs/blanket_clippy_restriction_lints.txt
Normal 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)]
|
||||
```
|
21
src/docs/blocks_in_if_conditions.txt
Normal file
21
src/docs/blocks_in_if_conditions.txt
Normal 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 { /* ... */ }
|
||||
```
|
16
src/docs/bool_assert_comparison.txt
Normal file
16
src/docs/bool_assert_comparison.txt
Normal 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());
|
||||
```
|
18
src/docs/bool_comparison.txt
Normal file
18
src/docs/bool_comparison.txt
Normal 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 {}
|
||||
```
|
26
src/docs/bool_to_int_with_if.txt
Normal file
26
src/docs/bool_to_int_with_if.txt
Normal 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;
|
||||
```
|
26
src/docs/borrow_as_ptr.txt
Normal file
26
src/docs/borrow_as_ptr.txt
Normal 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);
|
||||
```
|
27
src/docs/borrow_deref_ref.txt
Normal file
27
src/docs/borrow_deref_ref.txt
Normal 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;
|
||||
```
|
40
src/docs/borrow_interior_mutable_const.txt
Normal file
40
src/docs/borrow_interior_mutable_const.txt
Normal 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
19
src/docs/borrowed_box.txt
Normal 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) { ... }
|
||||
```
|
23
src/docs/box_collection.txt
Normal file
23
src/docs/box_collection.txt
Normal 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
18
src/docs/boxed_local.txt
Normal 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) {}
|
||||
```
|
32
src/docs/branches_sharing_code.txt
Normal file
32
src/docs/branches_sharing_code.txt
Normal 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
|
||||
};
|
||||
```
|
15
src/docs/builtin_type_shadow.txt
Normal file
15
src/docs/builtin_type_shadow.txt
Normal 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
|
||||
}
|
||||
}
|
||||
```
|
18
src/docs/bytes_count_to_len.txt
Normal file
18
src/docs/bytes_count_to_len.txt
Normal 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
16
src/docs/bytes_nth.txt
Normal 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);
|
||||
```
|
33
src/docs/cargo_common_metadata.txt
Normal file
33
src/docs/cargo_common_metadata.txt
Normal 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"]
|
||||
```
|
21
src/docs/case_sensitive_file_extension_comparisons.txt
Normal file
21
src/docs/case_sensitive_file_extension_comparisons.txt
Normal 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"))
|
||||
}
|
||||
```
|
16
src/docs/cast_abs_to_unsigned.txt
Normal file
16
src/docs/cast_abs_to_unsigned.txt
Normal 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();
|
||||
```
|
11
src/docs/cast_enum_constructor.txt
Normal file
11
src/docs/cast_enum_constructor.txt
Normal 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;
|
||||
```
|
12
src/docs/cast_enum_truncation.txt
Normal file
12
src/docs/cast_enum_truncation.txt
Normal 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;
|
||||
```
|
26
src/docs/cast_lossless.txt
Normal file
26
src/docs/cast_lossless.txt
Normal 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)
|
||||
}
|
||||
```
|
16
src/docs/cast_possible_truncation.txt
Normal file
16
src/docs/cast_possible_truncation.txt
Normal 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
|
||||
}
|
||||
```
|
17
src/docs/cast_possible_wrap.txt
Normal file
17
src/docs/cast_possible_wrap.txt
Normal 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`
|
||||
```
|
19
src/docs/cast_precision_loss.txt
Normal file
19
src/docs/cast_precision_loss.txt
Normal 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;
|
||||
```
|
21
src/docs/cast_ptr_alignment.txt
Normal file
21
src/docs/cast_ptr_alignment.txt
Normal 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>();
|
||||
```
|
28
src/docs/cast_ref_to_mut.txt
Normal file
28
src/docs/cast_ref_to_mut.txt
Normal file
@ -0,0 +1,28 @@
|
||||
### What it does
|
||||
Checks for casts of `&T` to `&mut T` anywhere in the code.
|
||||
|
||||
### Why is this bad?
|
||||
It’s 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;
|
||||
}
|
||||
}
|
||||
```
|
15
src/docs/cast_sign_loss.txt
Normal file
15
src/docs/cast_sign_loss.txt
Normal 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
|
||||
```
|
38
src/docs/cast_slice_different_sizes.txt
Normal file
38
src/docs/cast_slice_different_sizes.txt
Normal 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);
|
||||
}
|
||||
```
|
20
src/docs/cast_slice_from_raw_parts.txt
Normal file
20
src/docs/cast_slice_from_raw_parts.txt
Normal 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
|
21
src/docs/char_lit_as_u8.txt
Normal file
21
src/docs/char_lit_as_u8.txt
Normal 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'
|
||||
```
|
17
src/docs/chars_last_cmp.txt
Normal file
17
src/docs/chars_last_cmp.txt
Normal 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('-');
|
||||
```
|
19
src/docs/chars_next_cmp.txt
Normal file
19
src/docs/chars_next_cmp.txt
Normal 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('_') {};
|
||||
```
|
15
src/docs/checked_conversions.txt
Normal file
15
src/docs/checked_conversions.txt
Normal 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();
|
||||
```
|
16
src/docs/clone_double_ref.txt
Normal file
16
src/docs/clone_double_ref.txt
Normal 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
|
||||
}
|
||||
```
|
11
src/docs/clone_on_copy.txt
Normal file
11
src/docs/clone_on_copy.txt
Normal 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();
|
||||
```
|
21
src/docs/clone_on_ref_ptr.txt
Normal file
21
src/docs/clone_on_ref_ptr.txt
Normal 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);
|
||||
```
|
16
src/docs/cloned_instead_of_copied.txt
Normal file
16
src/docs/cloned_instead_of_copied.txt
Normal 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
16
src/docs/cmp_nan.txt
Normal 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
23
src/docs/cmp_null.txt
Normal 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
18
src/docs/cmp_owned.txt
Normal 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 {}
|
||||
```
|
13
src/docs/cognitive_complexity.txt
Normal file
13
src/docs/cognitive_complexity.txt
Normal 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.
|
29
src/docs/collapsible_else_if.txt
Normal file
29
src/docs/collapsible_else_if.txt
Normal 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 {
|
||||
…
|
||||
}
|
||||
```
|
23
src/docs/collapsible_if.txt
Normal file
23
src/docs/collapsible_if.txt
Normal 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 {
|
||||
// …
|
||||
}
|
||||
```
|
31
src/docs/collapsible_match.txt
Normal file
31
src/docs/collapsible_match.txt
Normal 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,
|
||||
};
|
||||
}
|
||||
```
|
19
src/docs/collapsible_str_replace.txt
Normal file
19
src/docs/collapsible_str_replace.txt
Normal 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");
|
||||
```
|
36
src/docs/comparison_chain.txt
Normal file
36
src/docs/comparison_chain.txt
Normal 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()
|
||||
}
|
||||
}
|
||||
```
|
31
src/docs/comparison_to_empty.txt
Normal file
31
src/docs/comparison_to_empty.txt
Normal 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() {
|
||||
..
|
||||
}
|
||||
```
|
20
src/docs/copy_iterator.txt
Normal file
20
src/docs/copy_iterator.txt
Normal 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();
|
||||
```
|
35
src/docs/crate_in_macro_def.txt
Normal file
35
src/docs/crate_in_macro_def.txt
Normal 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
15
src/docs/create_dir.txt
Normal 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");
|
||||
```
|
12
src/docs/crosspointer_transmute.txt
Normal file
12
src/docs/crosspointer_transmute.txt
Normal 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
16
src/docs/dbg_macro.txt
Normal 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
|
||||
```
|
18
src/docs/debug_assert_with_mut_call.txt
Normal file
18
src/docs/debug_assert_with_mut_call.txt
Normal 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));
|
||||
```
|
13
src/docs/decimal_literal_representation.txt
Normal file
13
src/docs/decimal_literal_representation.txt
Normal 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`
|
||||
```
|
46
src/docs/declare_interior_mutable_const.txt
Normal file
46
src/docs/declare_interior_mutable_const.txt
Normal 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
|
||||
```
|
15
src/docs/default_instead_of_iter_empty.txt
Normal file
15
src/docs/default_instead_of_iter_empty.txt
Normal 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();
|
||||
```
|
28
src/docs/default_numeric_fallback.txt
Normal file
28
src/docs/default_numeric_fallback.txt
Normal 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;
|
||||
```
|
16
src/docs/default_trait_access.txt
Normal file
16
src/docs/default_trait_access.txt
Normal 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();
|
||||
```
|
36
src/docs/default_union_representation.txt
Normal file
36
src/docs/default_union_representation.txt
Normal 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
|
||||
};
|
||||
}
|
||||
```
|
24
src/docs/deprecated_cfg_attr.txt
Normal file
24
src/docs/deprecated_cfg_attr.txt
Normal 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() { }
|
||||
```
|
13
src/docs/deprecated_semver.txt
Normal file
13
src/docs/deprecated_semver.txt
Normal 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
22
src/docs/deref_addrof.txt
Normal 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;
|
||||
```
|
17
src/docs/deref_by_slicing.txt
Normal file
17
src/docs/deref_by_slicing.txt
Normal 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;
|
||||
```
|
35
src/docs/derivable_impls.txt
Normal file
35
src/docs/derivable_impls.txt
Normal 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.
|
23
src/docs/derive_hash_xor_eq.txt
Normal file
23
src/docs/derive_hash_xor_eq.txt
Normal 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 it’s 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 {
|
||||
...
|
||||
}
|
||||
```
|
44
src/docs/derive_ord_xor_partial_ord.txt
Normal file
44
src/docs/derive_ord_xor_partial_ord.txt
Normal 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 it’s 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;
|
||||
```
|
25
src/docs/derive_partial_eq_without_eq.txt
Normal file
25
src/docs/derive_partial_eq_without_eq.txt
Normal 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>,
|
||||
}
|
||||
```
|
41
src/docs/disallowed_methods.txt
Normal file
41
src/docs/disallowed_methods.txt
Normal 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.
|
||||
```
|
12
src/docs/disallowed_names.txt
Normal file
12
src/docs/disallowed_names.txt
Normal 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;
|
||||
```
|
32
src/docs/disallowed_script_idents.txt
Normal file
32
src/docs/disallowed_script_idents.txt
Normal 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.
|
||||
```
|
33
src/docs/disallowed_types.txt
Normal file
33
src/docs/disallowed_types.txt
Normal 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;
|
||||
```
|
19
src/docs/diverging_sub_expression.txt
Normal file
19
src/docs/diverging_sub_expression.txt
Normal 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!()`
|
||||
```
|
16
src/docs/doc_link_with_quotes.txt
Normal file
16
src/docs/doc_link_with_quotes.txt
Normal 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
35
src/docs/doc_markdown.txt
Normal 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 won’t 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() {}
|
||||
```
|
17
src/docs/double_comparisons.txt
Normal file
17
src/docs/double_comparisons.txt
Normal 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 {}
|
||||
```
|
17
src/docs/double_must_use.txt
Normal file
17
src/docs/double_must_use.txt
Normal 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
12
src/docs/double_neg.txt
Normal 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;
|
||||
```
|
24
src/docs/double_parens.txt
Normal file
24
src/docs/double_parens.txt
Normal 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
15
src/docs/drop_copy.txt
Normal 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
|
||||
```
|
13
src/docs/drop_non_drop.txt
Normal file
13
src/docs/drop_non_drop.txt
Normal 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
Loading…
Reference in New Issue
Block a user