diff --git a/CHANGELOG.md b/CHANGELOG.md index f99ea73e5a5f..662b5f886f7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3276,6 +3276,7 @@ Released 2018-09-13 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons [`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason +[`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions @@ -3362,6 +3363,7 @@ Released 2018-09-13 [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression +[`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use diff --git a/Cargo.toml b/Cargo.toml index 3c8b758d53dc..d23d681df00c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ filetime = "0.2" rustc-workspace-hack = "1.0" # UI test dependencies +clap = { version = "3.1", features = ["derive"] } clippy_utils = { path = "clippy_utils" } derive-new = "0.5" if_chain = "1.0" diff --git a/clippy_lints/src/almost_complete_letter_range.rs b/clippy_lints/src/almost_complete_letter_range.rs new file mode 100644 index 000000000000..b364a370efab --- /dev/null +++ b/clippy_lints/src/almost_complete_letter_range.rs @@ -0,0 +1,100 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{trim_span, walk_span_to_context}; +use clippy_utils::{meets_msrv, msrvs}; +use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### 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 + /// ```rust + /// let _ = 'a'..'z'; + /// ``` + /// Use instead: + /// ```rust + /// let _ = 'a'..='z'; + /// ``` + #[clippy::version = "1.63.0"] + pub ALMOST_COMPLETE_LETTER_RANGE, + suspicious, + "almost complete letter range" +} +impl_lint_pass!(AlmostCompleteLetterRange => [ALMOST_COMPLETE_LETTER_RANGE]); + +pub struct AlmostCompleteLetterRange { + msrv: Option, +} +impl AlmostCompleteLetterRange { + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} +impl EarlyLintPass for AlmostCompleteLetterRange { + fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { + if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind { + let ctxt = e.span.ctxt(); + let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt) + && let Some(end) = walk_span_to_context(end.span, ctxt) + && meets_msrv(self.msrv, msrvs::RANGE_INCLUSIVE) + { + Some((trim_span(cx.sess().source_map(), start.between(end)), "..=")) + } else { + None + }; + check_range(cx, e.span, start, end, sugg); + } + } + + fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &Pat) { + if let PatKind::Range(Some(start), Some(end), kind) = &p.kind + && matches!(kind.node, RangeEnd::Excluded) + { + let sugg = if meets_msrv(self.msrv, msrvs::RANGE_INCLUSIVE) { + "..=" + } else { + "..." + }; + check_range(cx, p.span, start, end, Some((kind.span, sugg))); + } + } + + extract_msrv_attr!(EarlyContext); +} + +fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) { + if let ExprKind::Lit(start_lit) = &start.peel_parens().kind + && let ExprKind::Lit(end_lit) = &end.peel_parens().kind + && matches!( + (&start_lit.kind, &end_lit.kind), + (LitKind::Byte(b'a') | LitKind::Char('a'), LitKind::Byte(b'z') | LitKind::Char('z')) + | (LitKind::Byte(b'A') | LitKind::Char('A'), LitKind::Byte(b'Z') | LitKind::Char('Z')) + ) + { + span_lint_and_then( + cx, + ALMOST_COMPLETE_LETTER_RANGE, + span, + "almost complete ascii letter range", + |diag| { + if let Some((span, sugg)) = sugg { + diag.span_suggestion( + span, + "use an inclusive range", + sugg.to_owned(), + Applicability::MaybeIncorrect, + ); + } + } + ); + } +} diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 3de91f3d24a9..7105ce4b292a 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -585,15 +585,21 @@ impl EarlyLintPass for EarlyAttributes { } fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { - for attr in &item.attrs { + let mut iter = item.attrs.iter().peekable(); + while let Some(attr) = iter.next() { if matches!(attr.kind, AttrKind::Normal(..)) && attr.style == AttrStyle::Outer && is_present_in_source(cx, attr.span) { let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent()); - let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt(), item.span.parent()); + let end_of_attr_to_next_attr_or_item = Span::new( + attr.span.hi(), + iter.peek().map_or(item.span.lo(), |next_attr| next_attr.span.lo()), + item.span.ctxt(), + item.span.parent(), + ); - if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) { + if let Some(snippet) = snippet_opt(cx, end_of_attr_to_next_attr_or_item) { let lines = snippet.split('\n').collect::>(); let lines = without_block_comments(lines); @@ -623,8 +629,15 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Opti if feature_item.has_name(sym::rustfmt); // check for `rustfmt_skip` and `rustfmt::skip` if let Some(skip_item) = &items[1].meta_item(); - if skip_item.has_name(sym!(rustfmt_skip)) || - skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym::skip; + if skip_item.has_name(sym!(rustfmt_skip)) + || skip_item + .path + .segments + .last() + .expect("empty path in attribute") + .ident + .name + == sym::skip; // Only lint outer attributes, because custom inner attributes are unstable // Tracking issue: https://github.com/rust-lang/rust/issues/54726 if attr.style == AttrStyle::Outer; diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index f99d793c201d..17deccf8c393 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; declare_clippy_lint! { @@ -30,14 +30,27 @@ declare_clippy_lint! { "`dbg!` macro is intended as a debugging tool" } -declare_lint_pass!(DbgMacro => [DBG_MACRO]); +#[derive(Copy, Clone)] +pub struct DbgMacro { + allow_dbg_in_tests: bool, +} + +impl_lint_pass!(DbgMacro => [DBG_MACRO]); + +impl DbgMacro { + pub fn new(allow_dbg_in_tests: bool) -> Self { + DbgMacro { allow_dbg_in_tests } + } +} impl LateLintPass<'_> for DbgMacro { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; if cx.tcx.is_diagnostic_item(sym::dbg_macro, macro_call.def_id) { - // we make an exception for test code - if is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id) { + // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml + if self.allow_dbg_in_tests + && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) + { return; } let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/doc_link_with_quotes.rs b/clippy_lints/src/doc_link_with_quotes.rs new file mode 100644 index 000000000000..cb07f57e8700 --- /dev/null +++ b/clippy_lints/src/doc_link_with_quotes.rs @@ -0,0 +1,60 @@ +use clippy_utils::diagnostics::span_lint; +use itertools::Itertools; +use rustc_ast::{AttrKind, Attribute}; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### 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 + /// ```rust + /// /// See also: ['foo'] + /// fn bar() {} + /// ``` + /// Use instead: + /// ```rust + /// /// See also: [`foo`] + /// fn bar() {} + /// ``` + #[clippy::version = "1.60.0"] + pub DOC_LINK_WITH_QUOTES, + pedantic, + "possible typo for an intra-doc link" +} +declare_lint_pass!(DocLinkWithQuotes => [DOC_LINK_WITH_QUOTES]); + +impl EarlyLintPass for DocLinkWithQuotes { + fn check_attribute(&mut self, ctx: &EarlyContext<'_>, attr: &Attribute) { + if let AttrKind::DocComment(_, symbol) = attr.kind { + if contains_quote_link(symbol.as_str()) { + span_lint( + ctx, + DOC_LINK_WITH_QUOTES, + attr.span, + "possible intra-doc link using quotes instead of backticks", + ); + } + } + } +} + +fn contains_quote_link(s: &str) -> bool { + let mut in_backticks = false; + let mut found_opening = false; + + for c in s.chars().tuple_windows::<(char, char)>() { + match c { + ('`', _) => in_backticks = !in_backticks, + ('[', '\'') if !in_backticks => found_opening = true, + ('\'', ']') if !in_backticks && found_opening => return true, + _ => {}, + } + } + + false +} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index a028b41db774..d4f8d676c22d 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -4,6 +4,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), + LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE), LintId::of(approx_const::APPROX_CONSTANT), LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), LintId::of(assign_ops::ASSIGN_OP_PATTERN), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 61fd11b96b00..5fa1f0753035 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -34,6 +34,7 @@ store.register_lints(&[ #[cfg(feature = "internal")] utils::internal_lints::UNNECESSARY_SYMBOL_STR, absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS, + almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE, approx_const::APPROX_CONSTANT, arithmetic::FLOAT_ARITHMETIC, arithmetic::INTEGER_ARITHMETIC, @@ -124,6 +125,7 @@ store.register_lints(&[ doc::MISSING_PANICS_DOC, doc::MISSING_SAFETY_DOC, doc::NEEDLESS_DOCTEST_MAIN, + doc_link_with_quotes::DOC_LINK_WITH_QUOTES, double_comparison::DOUBLE_COMPARISONS, double_parens::DOUBLE_PARENS, drop_forget_ref::DROP_COPY, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index e29764b8bdbc..b0e11ef05b50 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -26,6 +26,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(doc::DOC_MARKDOWN), LintId::of(doc::MISSING_ERRORS_DOC), LintId::of(doc::MISSING_PANICS_DOC), + LintId::of(doc_link_with_quotes::DOC_LINK_WITH_QUOTES), LintId::of(empty_enum::EMPTY_ENUM), LintId::of(enum_variants::MODULE_NAME_REPETITIONS), LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index 20bf5a245b15..3d6d2d8951c2 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -3,6 +3,7 @@ // Manual edits will be overwritten. store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![ + LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE), LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index d1297e65b4d0..830aa8551719 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -168,6 +168,7 @@ mod renamed_lints; // begin lints modules, do not remove this comment, it’s used in `update_lints` mod absurd_extreme_comparisons; +mod almost_complete_letter_range; mod approx_const; mod arithmetic; mod as_conversions; @@ -208,6 +209,7 @@ mod disallowed_methods; mod disallowed_script_idents; mod disallowed_types; mod doc; +mod doc_link_with_quotes; mod double_comparison; mod double_parens; mod drop_forget_ref; @@ -887,9 +889,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv))); store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv))); store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation)); + store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes)); store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion)); store.register_late_pass(|| Box::new(significant_drop_in_scrutinee::SignificantDropInScrutinee)); - store.register_late_pass(|| Box::new(dbg_macro::DbgMacro)); + let allow_dbg_in_tests = conf.allow_dbg_in_tests; + store.register_late_pass(move || Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests))); let cargo_ignore_publish = conf.cargo_ignore_publish; store.register_late_pass(move || { Box::new(cargo::Cargo { @@ -909,6 +913,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default())); store.register_late_pass(|| Box::new(get_first::GetFirst)); store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding)); + store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); store.register_late_pass(|| Box::new(path_from_format::PathFromFormat)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index b70871b38bea..26c694a71fed 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -194,14 +194,15 @@ fn assignment_suggestions<'tcx>( })) .collect::>>()?; - let applicability = if suggestions.len() > 1 { + match suggestions.len() { + // All of `exprs` are never types + // https://github.com/rust-lang/rust-clippy/issues/8911 + 0 => None, + 1 => Some((Applicability::MachineApplicable, suggestions)), // multiple suggestions don't work with rustfix in multipart_suggest // https://github.com/rust-lang/rustfix/issues/141 - Applicability::Unspecified - } else { - Applicability::MachineApplicable - }; - Some((applicability, suggestions)) + _ => Some((Applicability::Unspecified, suggestions)), + } } struct Usage<'tcx> { diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index 110f58f3734d..8db8c4e9b787 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -2,7 +2,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; use clippy_utils::last_path_segment; use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::paths; use clippy_utils::source::{indent_of, snippet}; +use clippy_utils::ty::match_type; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -11,10 +13,11 @@ use rustc_span::{sym, Span, Symbol}; declare_clippy_lint! { /// ### What it does - /// Checks for `Arc::new` or `Rc::new` in `vec![elem; len]` + /// Checks for reference-counted pointers (`Arc`, `Rc`, `rc::Weak`, and `sync::Weak`) + /// in `vec![elem; len]` /// /// ### Why is this bad? - /// This will create `elem` once and clone it `len` times - doing so with `Arc` or `Rc` + /// This will create `elem` once and clone it `len` times - doing so with `Arc`/`Rc`/`Weak` /// is a bit misleading, as it will create references to the same pointer, rather /// than different instances. /// @@ -26,7 +29,6 @@ declare_clippy_lint! { /// ``` /// Use instead: /// ```rust - /// /// // Initialize each value separately: /// let mut data = Vec::with_capacity(100); /// for _ in 0..100 { @@ -42,7 +44,7 @@ declare_clippy_lint! { #[clippy::version = "1.62.0"] pub RC_CLONE_IN_VEC_INIT, suspicious, - "initializing `Arc` or `Rc` in `vec![elem; len]`" + "initializing reference-counted pointer in `vec![elem; len]`" } declare_lint_pass!(RcCloneInVecInit => [RC_CLONE_IN_VEC_INIT]); @@ -50,26 +52,12 @@ impl LateLintPass<'_> for RcCloneInVecInit { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return; }; let Some(VecArgs::Repeat(elem, len)) = VecArgs::hir(cx, expr) else { return; }; - let Some(symbol) = new_reference_call(cx, elem) else { return; }; + let Some((symbol, func_span)) = ref_init(cx, elem) else { return; }; - emit_lint(cx, symbol, macro_call.span, elem, len); + emit_lint(cx, symbol, macro_call.span, elem, len, func_span); } } -fn elem_snippet(cx: &LateContext<'_>, elem: &Expr<'_>, symbol_name: &str) -> String { - let elem_snippet = snippet(cx, elem.span, "..").to_string(); - if elem_snippet.contains('\n') { - // This string must be found in `elem_snippet`, otherwise we won't be constructing - // the snippet in the first place. - let reference_creation = format!("{symbol_name}::new"); - let (code_until_reference_creation, _right) = elem_snippet.split_once(&reference_creation).unwrap(); - - return format!("{code_until_reference_creation}{reference_creation}(..)"); - } - - elem_snippet -} - fn loop_init_suggestion(elem: &str, len: &str, indent: &str) -> String { format!( r#"{{ @@ -89,17 +77,17 @@ fn extract_suggestion(elem: &str, len: &str, indent: &str) -> String { ) } -fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, elem: &Expr<'_>, len: &Expr<'_>) { +fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, elem: &Expr<'_>, len: &Expr<'_>, func_span: Span) { let symbol_name = symbol.as_str(); span_lint_and_then( cx, RC_CLONE_IN_VEC_INIT, lint_span, - &format!("calling `{symbol_name}::new` in `vec![elem; len]`"), + "initializing a reference-counted pointer in `vec![elem; len]`", |diag| { let len_snippet = snippet(cx, len.span, ".."); - let elem_snippet = elem_snippet(cx, elem, symbol_name); + let elem_snippet = format!("{}(..)", snippet(cx, elem.span.with_hi(func_span.hi()), "..")); let indentation = " ".repeat(indent_of(cx, lint_span).unwrap_or(0)); let loop_init_suggestion = loop_init_suggestion(&elem_snippet, len_snippet.as_ref(), &indentation); let extract_suggestion = extract_suggestion(&elem_snippet, len_snippet.as_ref(), &indentation); @@ -109,7 +97,7 @@ fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, elem: &Expr< lint_span, format!("consider initializing each `{symbol_name}` element individually"), loop_init_suggestion, - Applicability::Unspecified, + Applicability::HasPlaceholders, ); diag.span_suggestion( lint_span, @@ -117,23 +105,33 @@ fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, elem: &Expr< "or if this is intentional, consider extracting the `{symbol_name}` initialization to a variable" ), extract_suggestion, - Applicability::Unspecified, + Applicability::HasPlaceholders, ); }, ); } -/// Checks whether the given `expr` is a call to `Arc::new` or `Rc::new` -fn new_reference_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { +/// Checks whether the given `expr` is a call to `Arc::new`, `Rc::new`, or evaluates to a `Weak` +fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> { if_chain! { if let ExprKind::Call(func, _args) = expr.kind; if let ExprKind::Path(ref func_path @ QPath::TypeRelative(ty, _)) = func.kind; if let TyKind::Path(ref ty_path) = ty.kind; if let Some(def_id) = cx.qpath_res(ty_path, ty.hir_id).opt_def_id(); - if last_path_segment(func_path).ident.name == sym::new; then { - return cx.tcx.get_diagnostic_name(def_id).filter(|symbol| symbol == &sym::Arc || symbol == &sym::Rc); + if last_path_segment(func_path).ident.name == sym::new + && let Some(symbol) = cx + .tcx + .get_diagnostic_name(def_id) + .filter(|symbol| symbol == &sym::Arc || symbol == &sym::Rc) { + return Some((symbol, func.span)); + } + + let ty_path = cx.typeck_results().expr_ty(expr); + if match_type(cx, ty_path, &paths::WEAK_RC) || match_type(cx, ty_path, &paths::WEAK_ARC) { + return Some((Symbol::intern("Weak"), func.span)); + } } } diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 1ab7f52110ce..4f74c1e44c26 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -160,9 +160,13 @@ impl<'tcx> LateLintPass<'tcx> for Shadow { fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second: ItemLocalId) -> bool { let scope_tree = cx.tcx.region_scope_tree(owner.to_def_id()); - let first_scope = scope_tree.var_scope(first).unwrap(); - let second_scope = scope_tree.var_scope(second).unwrap(); - scope_tree.is_subscope_of(second_scope, first_scope) + if let Some(first_scope) = scope_tree.var_scope(first) { + if let Some(second_scope) = scope_tree.var_scope(second) { + return scope_tree.is_subscope_of(second_scope, first_scope); + } + } + + false } fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) { diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 66f7748e9e08..486ea5e5ccfa 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -258,13 +258,21 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { if !pat.span.from_expansion(); if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS); if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); - if let PatKind::Path(QPath::Resolved(_, path)) = pat.kind; - if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _)); + // get the path from the pattern + if let PatKind::Path(QPath::Resolved(_, path)) + | PatKind::TupleStruct(QPath::Resolved(_, path), _, _) + | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind; if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id); - if let [first, ..] = path.segments; - if let Some(hir_id) = first.hir_id; then { - span_lint(cx, cx.tcx.hir().span(hir_id)); + match path.res { + Res::Def(DefKind::Ctor(ctor_of, _), ..) => match ctor_of { + CtorOf::Variant => lint_path_to_variant(cx, path), + CtorOf::Struct => span_lint(cx, path.span), + }, + Res::Def(DefKind::Variant, ..) => lint_path_to_variant(cx, path), + Res::Def(DefKind::Struct, ..) => span_lint(cx, path.span), + _ => () + } } } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index cd4d16fe95f7..b5c5d35135f9 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -340,6 +340,10 @@ define_Conf! { /// /// Whether `unwrap` should be allowed in test functions (allow_unwrap_in_tests: bool = false), + /// Lint: DBG_MACRO. + /// + /// Whether `dbg!` should be allowed in test functions + (allow_dbg_in_tests: bool = false), } /// Search for the configuration file. diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 134fd1ce505a..b9ec2c19fdd3 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -30,6 +30,7 @@ msrv_aliases! { 1,34,0 { TRY_FROM } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,28,0 { FROM_BOOL } + 1,26,0 { RANGE_INCLUSIVE } 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR } 1,16,0 { STR_REPEAT } 1,24,0 { IS_ASCII_DIGIT } diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 04ef2f57447c..f88a92fb11c1 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_span::hygiene; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, Pos, Span, SyntaxContext}; +use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext}; use std::borrow::Cow; /// Checks if the span starts with the given text. This will return false if the span crosses @@ -389,6 +389,27 @@ pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> { without } +/// Trims the whitespace from the start and the end of the span. +pub fn trim_span(sm: &SourceMap, span: Span) -> Span { + let data = span.data(); + let sf: &_ = &sm.lookup_source_file(data.lo); + let Some(src) = sf.src.as_deref() else { + return span; + }; + let Some(snip) = &src.get((data.lo - sf.start_pos).to_usize()..(data.hi - sf.start_pos).to_usize()) else { + return span; + }; + let trim_start = snip.len() - snip.trim_start().len(); + let trim_end = snip.len() - snip.trim_end().len(); + SpanData { + lo: data.lo + BytePos::from_usize(trim_start), + hi: data.hi - BytePos::from_usize(trim_end), + ctxt: data.ctxt, + parent: data.parent, + } + .span() +} + #[cfg(test)] mod test { use super::{reindent_multiline, without_block_comments}; diff --git a/tests/compile-test.rs b/tests/compile-test.rs index c9710e3db8e8..3b599351016d 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -1,5 +1,6 @@ #![feature(test)] // compiletest_rs requires this attribute #![feature(once_cell)] +#![feature(is_sorted)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] @@ -22,6 +23,7 @@ const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal"); /// All crates used in UI tests are listed here static TEST_DEPENDENCIES: &[&str] = &[ + "clap", "clippy_utils", "derive_new", "futures", @@ -40,6 +42,8 @@ static TEST_DEPENDENCIES: &[&str] = &[ // Test dependencies may need an `extern crate` here to ensure that they show up // in the depinfo file (otherwise cargo thinks they are unused) #[allow(unused_extern_crates)] +extern crate clap; +#[allow(unused_extern_crates)] extern crate clippy_utils; #[allow(unused_extern_crates)] extern crate derive_new; @@ -109,8 +113,9 @@ static EXTERN_FLAGS: SyncLazy = SyncLazy::new(|| { not_found.is_empty(), "dependencies not found in depinfo: {:?}\n\ help: Make sure the `-Z binary-dep-depinfo` rust flag is enabled\n\ - help: Try adding to dev-dependencies in Cargo.toml", - not_found + help: Try adding to dev-dependencies in Cargo.toml\n\ + help: Be sure to also add `extern crate ...;` to tests/compile-test.rs", + not_found, ); crates .into_iter() @@ -162,7 +167,8 @@ fn base_config(test_dir: &str) -> compiletest::Config { } fn run_ui() { - let config = base_config("ui"); + let mut config = base_config("ui"); + config.rustfix_coverage = true; // use tests/clippy.toml let _g = VarGuard::set("CARGO_MANIFEST_DIR", fs::canonicalize("tests").unwrap()); let _threads = VarGuard::set( @@ -175,6 +181,7 @@ fn run_ui() { }), ); compiletest::run_tests(&config); + check_rustfix_coverage(); } fn run_internal_tests() { @@ -337,6 +344,87 @@ fn compile_test() { run_internal_tests(); } +const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[ + "assign_ops2.rs", + "cast_size_32bit.rs", + "char_lit_as_u8.rs", + "cmp_owned/without_suggestion.rs", + "dbg_macro.rs", + "deref_addrof_double_trigger.rs", + "doc/unbalanced_ticks.rs", + "eprint_with_newline.rs", + "explicit_counter_loop.rs", + "iter_skip_next_unfixable.rs", + "let_and_return.rs", + "literals.rs", + "map_flatten.rs", + "map_unwrap_or.rs", + "match_bool.rs", + "mem_replace_macro.rs", + "needless_arbitrary_self_type_unfixable.rs", + "needless_borrow_pat.rs", + "needless_for_each_unfixable.rs", + "nonminimal_bool.rs", + "print_literal.rs", + "print_with_newline.rs", + "redundant_static_lifetimes_multiple.rs", + "ref_binding_to_reference.rs", + "repl_uninit.rs", + "result_map_unit_fn_unfixable.rs", + "search_is_some.rs", + "single_component_path_imports_nested_first.rs", + "string_add.rs", + "toplevel_ref_arg_non_rustfix.rs", + "unit_arg.rs", + "unnecessary_clone.rs", + "unnecessary_lazy_eval_unfixable.rs", + "write_literal.rs", + "write_literal_2.rs", + "write_with_newline.rs", +]; + +fn check_rustfix_coverage() { + let missing_coverage_path = Path::new("target/debug/test/ui/rustfix_missing_coverage.txt"); + + if let Ok(missing_coverage_contents) = std::fs::read_to_string(missing_coverage_path) { + assert!(RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS.iter().is_sorted_by_key(Path::new)); + + for rs_path in missing_coverage_contents.lines() { + if Path::new(rs_path).starts_with("tests/ui/crashes") { + continue; + } + let filename = Path::new(rs_path).strip_prefix("tests/ui/").unwrap(); + assert!( + RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS + .binary_search_by_key(&filename, Path::new) + .is_ok(), + "`{}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \ + Please either add `// run-rustfix` at the top of the file or add the file to \ + `RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS` in `tests/compile-test.rs`.", + rs_path, + ); + } + } +} + +#[test] +fn rustfix_coverage_known_exceptions_accuracy() { + for filename in RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS { + let rs_path = Path::new("tests/ui").join(filename); + assert!( + rs_path.exists(), + "`{}` does not exists", + rs_path.strip_prefix(env!("CARGO_MANIFEST_DIR")).unwrap().display() + ); + let fixed_path = rs_path.with_extension("fixed"); + assert!( + !fixed_path.exists(), + "`{}` exists", + fixed_path.strip_prefix(env!("CARGO_MANIFEST_DIR")).unwrap().display() + ); + } +} + /// Restores an env var on drop #[must_use] struct VarGuard { diff --git a/tests/ui-toml/dbg_macro/clippy.toml b/tests/ui-toml/dbg_macro/clippy.toml new file mode 100644 index 000000000000..4296655a040f --- /dev/null +++ b/tests/ui-toml/dbg_macro/clippy.toml @@ -0,0 +1 @@ +allow-dbg-in-tests = true diff --git a/tests/ui-toml/dbg_macro/dbg_macro.rs b/tests/ui-toml/dbg_macro/dbg_macro.rs new file mode 100644 index 000000000000..5d9ce18f631b --- /dev/null +++ b/tests/ui-toml/dbg_macro/dbg_macro.rs @@ -0,0 +1,39 @@ +// compile-flags: --test +#![warn(clippy::dbg_macro)] + +fn foo(n: u32) -> u32 { + if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } +} + +fn factorial(n: u32) -> u32 { + if dbg!(n <= 1) { + dbg!(1) + } else { + dbg!(n * factorial(n - 1)) + } +} + +fn main() { + dbg!(42); + dbg!(dbg!(dbg!(42))); + foo(3) + dbg!(factorial(4)); + dbg!(1, 2, dbg!(3, 4)); + dbg!(1, 2, 3, 4, 5); +} + +#[test] +pub fn issue8481() { + dbg!(1); +} + +#[cfg(test)] +fn foo2() { + dbg!(1); +} + +#[cfg(test)] +mod mod1 { + fn func() { + dbg!(1); + } +} diff --git a/tests/ui-toml/dbg_macro/dbg_macro.stderr b/tests/ui-toml/dbg_macro/dbg_macro.stderr new file mode 100644 index 000000000000..46efb86dcfc5 --- /dev/null +++ b/tests/ui-toml/dbg_macro/dbg_macro.stderr @@ -0,0 +1,102 @@ +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:5:22 + | +LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::dbg-macro` implied by `-D warnings` +help: ensure to avoid having uses of it in version control + | +LL | if let Some(n) = n.checked_sub(4) { n } else { n } + | ~~~~~~~~~~~~~~~~ + +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:9:8 + | +LL | if dbg!(n <= 1) { + | ^^^^^^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | if n <= 1 { + | ~~~~~~ + +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:10:9 + | +LL | dbg!(1) + | ^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | 1 + | + +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:12:9 + | +LL | dbg!(n * factorial(n - 1)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | n * factorial(n - 1) + | + +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:17:5 + | +LL | dbg!(42); + | ^^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | 42; + | ~~ + +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:18:5 + | +LL | dbg!(dbg!(dbg!(42))); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | dbg!(dbg!(42)); + | ~~~~~~~~~~~~~~ + +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:19:14 + | +LL | foo(3) + dbg!(factorial(4)); + | ^^^^^^^^^^^^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | foo(3) + factorial(4); + | ~~~~~~~~~~~~ + +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:20:5 + | +LL | dbg!(1, 2, dbg!(3, 4)); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | (1, 2, dbg!(3, 4)); + | ~~~~~~~~~~~~~~~~~~ + +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:21:5 + | +LL | dbg!(1, 2, 3, 4, 5); + | ^^^^^^^^^^^^^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | (1, 2, 3, 4, 5); + | ~~~~~~~~~~~~~~~ + +error: aborting due to 9 previous errors + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 92838aa57dfd..1d87fd91a253 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,5 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of + allow-dbg-in-tests allow-expect-in-tests allow-unwrap-in-tests allowed-scripts diff --git a/tests/ui/almost_complete_letter_range.fixed b/tests/ui/almost_complete_letter_range.fixed new file mode 100644 index 000000000000..39f8f0c29495 --- /dev/null +++ b/tests/ui/almost_complete_letter_range.fixed @@ -0,0 +1,66 @@ +// run-rustfix +// edition:2018 + +#![feature(custom_inner_attributes)] +#![feature(exclusive_range_pattern)] +#![feature(stmt_expr_attributes)] +#![warn(clippy::almost_complete_letter_range)] +#![allow(ellipsis_inclusive_range_patterns)] + +macro_rules! a { + () => { + 'a' + }; +} + +fn main() { + #[rustfmt::skip] + { + let _ = ('a') ..='z'; + let _ = 'A' ..= ('Z'); + } + + let _ = 'b'..'z'; + let _ = 'B'..'Z'; + + let _ = (b'a')..=(b'z'); + let _ = b'A'..=b'Z'; + + let _ = b'b'..b'z'; + let _ = b'B'..b'Z'; + + let _ = a!()..='z'; + + let _ = match 0u8 { + b'a'..=b'z' if true => 1, + b'A'..=b'Z' if true => 2, + b'b'..b'z' => 3, + b'B'..b'Z' => 4, + _ => 5, + }; + + let _ = match 'x' { + 'a'..='z' if true => 1, + 'A'..='Z' if true => 2, + 'b'..'z' => 3, + 'B'..'Z' => 4, + _ => 5, + }; +} + +fn _under_msrv() { + #![clippy::msrv = "1.25"] + let _ = match 'a' { + 'a'...'z' => 1, + _ => 2, + }; +} + +fn _meets_msrv() { + #![clippy::msrv = "1.26"] + let _ = 'a'..='z'; + let _ = match 'a' { + 'a'..='z' => 1, + _ => 2, + }; +} diff --git a/tests/ui/almost_complete_letter_range.rs b/tests/ui/almost_complete_letter_range.rs new file mode 100644 index 000000000000..3dc021992576 --- /dev/null +++ b/tests/ui/almost_complete_letter_range.rs @@ -0,0 +1,66 @@ +// run-rustfix +// edition:2018 + +#![feature(custom_inner_attributes)] +#![feature(exclusive_range_pattern)] +#![feature(stmt_expr_attributes)] +#![warn(clippy::almost_complete_letter_range)] +#![allow(ellipsis_inclusive_range_patterns)] + +macro_rules! a { + () => { + 'a' + }; +} + +fn main() { + #[rustfmt::skip] + { + let _ = ('a') ..'z'; + let _ = 'A' .. ('Z'); + } + + let _ = 'b'..'z'; + let _ = 'B'..'Z'; + + let _ = (b'a')..(b'z'); + let _ = b'A'..b'Z'; + + let _ = b'b'..b'z'; + let _ = b'B'..b'Z'; + + let _ = a!()..'z'; + + let _ = match 0u8 { + b'a'..b'z' if true => 1, + b'A'..b'Z' if true => 2, + b'b'..b'z' => 3, + b'B'..b'Z' => 4, + _ => 5, + }; + + let _ = match 'x' { + 'a'..'z' if true => 1, + 'A'..'Z' if true => 2, + 'b'..'z' => 3, + 'B'..'Z' => 4, + _ => 5, + }; +} + +fn _under_msrv() { + #![clippy::msrv = "1.25"] + let _ = match 'a' { + 'a'..'z' => 1, + _ => 2, + }; +} + +fn _meets_msrv() { + #![clippy::msrv = "1.26"] + let _ = 'a'..'z'; + let _ = match 'a' { + 'a'..'z' => 1, + _ => 2, + }; +} diff --git a/tests/ui/almost_complete_letter_range.stderr b/tests/ui/almost_complete_letter_range.stderr new file mode 100644 index 000000000000..74980ec1a923 --- /dev/null +++ b/tests/ui/almost_complete_letter_range.stderr @@ -0,0 +1,100 @@ +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:19:17 + | +LL | let _ = ('a') ..'z'; + | ^^^^^^--^^^ + | | + | help: use an inclusive range: `..=` + | + = note: `-D clippy::almost-complete-letter-range` implied by `-D warnings` + +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:20:17 + | +LL | let _ = 'A' .. ('Z'); + | ^^^^--^^^^^^ + | | + | help: use an inclusive range: `..=` + +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:26:13 + | +LL | let _ = (b'a')..(b'z'); + | ^^^^^^--^^^^^^ + | | + | help: use an inclusive range: `..=` + +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:27:13 + | +LL | let _ = b'A'..b'Z'; + | ^^^^--^^^^ + | | + | help: use an inclusive range: `..=` + +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:32:13 + | +LL | let _ = a!()..'z'; + | ^^^^--^^^ + | | + | help: use an inclusive range: `..=` + +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:35:9 + | +LL | b'a'..b'z' if true => 1, + | ^^^^--^^^^ + | | + | help: use an inclusive range: `..=` + +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:36:9 + | +LL | b'A'..b'Z' if true => 2, + | ^^^^--^^^^ + | | + | help: use an inclusive range: `..=` + +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:43:9 + | +LL | 'a'..'z' if true => 1, + | ^^^--^^^ + | | + | help: use an inclusive range: `..=` + +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:44:9 + | +LL | 'A'..'Z' if true => 2, + | ^^^--^^^ + | | + | help: use an inclusive range: `..=` + +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:54:9 + | +LL | 'a'..'z' => 1, + | ^^^--^^^ + | | + | help: use an inclusive range: `...` + +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:61:13 + | +LL | let _ = 'a'..'z'; + | ^^^--^^^ + | | + | help: use an inclusive range: `..=` + +error: almost complete ascii letter range + --> $DIR/almost_complete_letter_range.rs:63:9 + | +LL | 'a'..'z' => 1, + | ^^^--^^^ + | | + | help: use an inclusive range: `..=` + +error: aborting due to 12 previous errors + diff --git a/tests/ui/bind_instead_of_map_multipart.fixed b/tests/ui/bind_instead_of_map_multipart.fixed new file mode 100644 index 000000000000..e1589843226c --- /dev/null +++ b/tests/ui/bind_instead_of_map_multipart.fixed @@ -0,0 +1,62 @@ +// run-rustfix +#![deny(clippy::bind_instead_of_map)] +#![allow(clippy::blocks_in_if_conditions)] + +pub fn main() { + let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() }); + let _ = Some("42").and_then(|s| if s.len() < 42 { None } else { Some(s.len()) }); + + let _ = Ok::<_, ()>("42").map(|s| if s.len() < 42 { 0 } else { s.len() }); + let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Err(()) } else { Ok(s.len()) }); + + let _ = Err::<(), _>("42").map_err(|s| if s.len() < 42 { s.len() + 20 } else { s.len() }); + let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Ok(()) } else { Err(s.len()) }); + + hard_example(); + macro_example(); +} + +fn hard_example() { + Some("42").map(|s| { + if { + if s == "43" { + return 43; + } + s == "42" + } { + return 45; + } + match s.len() { + 10 => 2, + 20 => { + if foo() { + return { + if foo() { + return 20; + } + println!("foo"); + 3 + }; + } + 20 + }, + 40 => 30, + _ => 1, + } + }); +} + +fn foo() -> bool { + true +} + +macro_rules! m { + () => { + Some(10) + }; +} + +fn macro_example() { + let _ = Some("").and_then(|s| if s.len() == 20 { m!() } else { Some(20) }); + let _ = Some("").map(|s| if s.len() == 20 { m!() } else { Some(20) }); +} diff --git a/tests/ui/bind_instead_of_map_multipart.rs b/tests/ui/bind_instead_of_map_multipart.rs index 91d9d11e3c11..49944403f6dd 100644 --- a/tests/ui/bind_instead_of_map_multipart.rs +++ b/tests/ui/bind_instead_of_map_multipart.rs @@ -1,3 +1,4 @@ +// run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::blocks_in_if_conditions)] diff --git a/tests/ui/bind_instead_of_map_multipart.stderr b/tests/ui/bind_instead_of_map_multipart.stderr index e4f605a4de30..f822b6f49fa3 100644 --- a/tests/ui/bind_instead_of_map_multipart.stderr +++ b/tests/ui/bind_instead_of_map_multipart.stderr @@ -1,11 +1,11 @@ error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` - --> $DIR/bind_instead_of_map_multipart.rs:5:13 + --> $DIR/bind_instead_of_map_multipart.rs:6:13 | LL | let _ = Some("42").and_then(|s| if s.len() < 42 { Some(0) } else { Some(s.len()) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/bind_instead_of_map_multipart.rs:1:9 + --> $DIR/bind_instead_of_map_multipart.rs:2:9 | LL | #![deny(clippy::bind_instead_of_map)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() }); | ~~~ ~ ~~~~~~~ error: using `Result.and_then(|x| Ok(y))`, which is more succinctly expressed as `map(|x| y)` - --> $DIR/bind_instead_of_map_multipart.rs:8:13 + --> $DIR/bind_instead_of_map_multipart.rs:9:13 | LL | let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Ok(0) } else { Ok(s.len()) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | let _ = Ok::<_, ()>("42").map(|s| if s.len() < 42 { 0 } else { s.len() | ~~~ ~ ~~~~~~~ error: using `Result.or_else(|x| Err(y))`, which is more succinctly expressed as `map_err(|x| y)` - --> $DIR/bind_instead_of_map_multipart.rs:11:13 + --> $DIR/bind_instead_of_map_multipart.rs:12:13 | LL | let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Err(s.len() + 20) } else { Err(s.len()) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | let _ = Err::<(), _>("42").map_err(|s| if s.len() < 42 { s.len() + 20 } | ~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~ error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` - --> $DIR/bind_instead_of_map_multipart.rs:19:5 + --> $DIR/bind_instead_of_map_multipart.rs:20:5 | LL | / Some("42").and_then(|s| { LL | | if { @@ -59,7 +59,7 @@ LL | s == "42" ... error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` - --> $DIR/bind_instead_of_map_multipart.rs:60:13 + --> $DIR/bind_instead_of_map_multipart.rs:61:13 | LL | let _ = Some("").and_then(|s| if s.len() == 20 { Some(m!()) } else { Some(Some(20)) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/dbg_macro.stderr b/tests/ui/dbg_macro.stderr index a3e7a7162e51..e6a65b46d975 100644 --- a/tests/ui/dbg_macro.stderr +++ b/tests/ui/dbg_macro.stderr @@ -109,5 +109,38 @@ help: ensure to avoid having uses of it in version control LL | 2; | ~ -error: aborting due to 10 previous errors +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:47:5 + | +LL | dbg!(1); + | ^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | 1; + | ~ + +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:52:5 + | +LL | dbg!(1); + | ^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | 1; + | ~ + +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:58:9 + | +LL | dbg!(1); + | ^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | 1; + | ~ + +error: aborting due to 13 previous errors diff --git a/tests/ui/doc_link_with_quotes.rs b/tests/ui/doc_link_with_quotes.rs new file mode 100644 index 000000000000..ab52fb1a4a69 --- /dev/null +++ b/tests/ui/doc_link_with_quotes.rs @@ -0,0 +1,12 @@ +#![warn(clippy::doc_link_with_quotes)] + +fn main() { + foo() +} + +/// Calls ['bar'] +pub fn foo() { + bar() +} + +pub fn bar() {} diff --git a/tests/ui/doc_link_with_quotes.stderr b/tests/ui/doc_link_with_quotes.stderr new file mode 100644 index 000000000000..bf6d57d8afe8 --- /dev/null +++ b/tests/ui/doc_link_with_quotes.stderr @@ -0,0 +1,10 @@ +error: possible intra-doc link using quotes instead of backticks + --> $DIR/doc_link_with_quotes.rs:7:1 + | +LL | /// Calls ['bar'] + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::doc-link-with-quotes` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs index 3e92bca986ab..d15c84d7438a 100644 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ b/tests/ui/empty_line_after_outer_attribute.rs @@ -4,6 +4,9 @@ #![feature(custom_inner_attributes)] #![rustfmt::skip] +#[macro_use] +extern crate clap; + #[macro_use] extern crate proc_macro_attr; @@ -110,4 +113,11 @@ pub trait Bazz { } } +#[derive(clap::Parser)] +#[clap(after_help = "This ia a help message. + +You're welcome. +")] +pub struct Args; + fn main() {} diff --git a/tests/ui/empty_line_after_outer_attribute.stderr b/tests/ui/empty_line_after_outer_attribute.stderr index 594fca44a321..acc3edef9b92 100644 --- a/tests/ui/empty_line_after_outer_attribute.stderr +++ b/tests/ui/empty_line_after_outer_attribute.stderr @@ -1,5 +1,5 @@ error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:11:1 + --> $DIR/empty_line_after_outer_attribute.rs:14:1 | LL | / #[crate_type = "lib"] LL | | @@ -10,7 +10,7 @@ LL | | fn with_one_newline_and_comment() { assert!(true) } = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:23:1 + --> $DIR/empty_line_after_outer_attribute.rs:26:1 | LL | / #[crate_type = "lib"] LL | | @@ -18,7 +18,7 @@ LL | | fn with_one_newline() { assert!(true) } | |_ error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:28:1 + --> $DIR/empty_line_after_outer_attribute.rs:31:1 | LL | / #[crate_type = "lib"] LL | | @@ -27,7 +27,7 @@ LL | | fn with_two_newlines() { assert!(true) } | |_ error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:35:1 + --> $DIR/empty_line_after_outer_attribute.rs:38:1 | LL | / #[crate_type = "lib"] LL | | @@ -35,7 +35,7 @@ LL | | enum Baz { | |_ error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:43:1 + --> $DIR/empty_line_after_outer_attribute.rs:46:1 | LL | / #[crate_type = "lib"] LL | | @@ -43,7 +43,7 @@ LL | | struct Foo { | |_ error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:51:1 + --> $DIR/empty_line_after_outer_attribute.rs:54:1 | LL | / #[crate_type = "lib"] LL | | diff --git a/tests/ui/implicit_clone.fixed b/tests/ui/implicit_clone.fixed new file mode 100644 index 000000000000..33770fc2a2cf --- /dev/null +++ b/tests/ui/implicit_clone.fixed @@ -0,0 +1,118 @@ +// run-rustfix +#![warn(clippy::implicit_clone)] +#![allow(clippy::clone_on_copy, clippy::redundant_clone)] +use std::borrow::Borrow; +use std::ffi::{OsStr, OsString}; +use std::path::PathBuf; + +fn return_owned_from_slice(slice: &[u32]) -> Vec { + slice.to_owned() +} + +pub fn own_same(v: T) -> T +where + T: ToOwned, +{ + v.to_owned() +} + +pub fn own_same_from_ref(v: &T) -> T +where + T: ToOwned, +{ + v.to_owned() +} + +pub fn own_different(v: T) -> U +where + T: ToOwned, +{ + v.to_owned() +} + +#[derive(Copy, Clone)] +struct Kitten; +impl Kitten { + // badly named method + fn to_vec(self) -> Kitten { + Kitten {} + } +} +impl Borrow for Kitten { + fn borrow(&self) -> &BorrowedKitten { + static VALUE: BorrowedKitten = BorrowedKitten {}; + &VALUE + } +} + +struct BorrowedKitten; +impl ToOwned for BorrowedKitten { + type Owned = Kitten; + fn to_owned(&self) -> Kitten { + Kitten {} + } +} + +mod weird { + #[allow(clippy::ptr_arg)] + pub fn to_vec(v: &Vec) -> Vec { + v.clone() + } +} + +fn main() { + let vec = vec![5]; + let _ = return_owned_from_slice(&vec); + let _ = vec.clone(); + let _ = vec.clone(); + + let vec_ref = &vec; + let _ = return_owned_from_slice(vec_ref); + let _ = vec_ref.clone(); + let _ = vec_ref.clone(); + + // we expect no lint for this + let _ = weird::to_vec(&vec); + + // we expect no lints for this + let slice: &[u32] = &[1, 2, 3, 4, 5]; + let _ = return_owned_from_slice(slice); + let _ = slice.to_owned(); + let _ = slice.to_vec(); + + let str = "hello world".to_string(); + let _ = str.clone(); + + // testing w/ an arbitrary type + let kitten = Kitten {}; + let _ = kitten.clone(); + let _ = own_same_from_ref(&kitten); + // this shouln't lint + let _ = kitten.to_vec(); + + // we expect no lints for this + let borrowed = BorrowedKitten {}; + let _ = borrowed.to_owned(); + + let pathbuf = PathBuf::new(); + let _ = pathbuf.clone(); + let _ = pathbuf.clone(); + + let os_string = OsString::from("foo"); + let _ = os_string.clone(); + let _ = os_string.clone(); + + // we expect no lints for this + let os_str = OsStr::new("foo"); + let _ = os_str.to_owned(); + let _ = os_str.to_os_string(); + + // issue #8227 + let pathbuf_ref = &pathbuf; + let pathbuf_ref = &pathbuf_ref; + let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&PathBuf` + let _ = (*pathbuf_ref).clone(); + let pathbuf_ref = &pathbuf_ref; + let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf` + let _ = (**pathbuf_ref).clone(); +} diff --git a/tests/ui/implicit_clone.rs b/tests/ui/implicit_clone.rs index 2549c9f32f90..fc896525bd27 100644 --- a/tests/ui/implicit_clone.rs +++ b/tests/ui/implicit_clone.rs @@ -1,5 +1,6 @@ +// run-rustfix #![warn(clippy::implicit_clone)] -#![allow(clippy::redundant_clone)] +#![allow(clippy::clone_on_copy, clippy::redundant_clone)] use std::borrow::Borrow; use std::ffi::{OsStr, OsString}; use std::path::PathBuf; diff --git a/tests/ui/implicit_clone.stderr b/tests/ui/implicit_clone.stderr index 0f4124241907..92c1aa58affb 100644 --- a/tests/ui/implicit_clone.stderr +++ b/tests/ui/implicit_clone.stderr @@ -1,5 +1,5 @@ error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:65:13 + --> $DIR/implicit_clone.rs:66:13 | LL | let _ = vec.to_owned(); | ^^^^^^^^^^^^^^ help: consider using: `vec.clone()` @@ -7,67 +7,67 @@ LL | let _ = vec.to_owned(); = note: `-D clippy::implicit-clone` implied by `-D warnings` error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type - --> $DIR/implicit_clone.rs:66:13 + --> $DIR/implicit_clone.rs:67:13 | LL | let _ = vec.to_vec(); | ^^^^^^^^^^^^ help: consider using: `vec.clone()` error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:70:13 + --> $DIR/implicit_clone.rs:71:13 | LL | let _ = vec_ref.to_owned(); | ^^^^^^^^^^^^^^^^^^ help: consider using: `vec_ref.clone()` error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type - --> $DIR/implicit_clone.rs:71:13 + --> $DIR/implicit_clone.rs:72:13 | LL | let _ = vec_ref.to_vec(); | ^^^^^^^^^^^^^^^^ help: consider using: `vec_ref.clone()` error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:83:13 + --> $DIR/implicit_clone.rs:84:13 | LL | let _ = str.to_owned(); | ^^^^^^^^^^^^^^ help: consider using: `str.clone()` error: implicitly cloning a `Kitten` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:87:13 + --> $DIR/implicit_clone.rs:88:13 | LL | let _ = kitten.to_owned(); | ^^^^^^^^^^^^^^^^^ help: consider using: `kitten.clone()` error: implicitly cloning a `PathBuf` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:97:13 + --> $DIR/implicit_clone.rs:98:13 | LL | let _ = pathbuf.to_owned(); | ^^^^^^^^^^^^^^^^^^ help: consider using: `pathbuf.clone()` error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type - --> $DIR/implicit_clone.rs:98:13 + --> $DIR/implicit_clone.rs:99:13 | LL | let _ = pathbuf.to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `pathbuf.clone()` error: implicitly cloning a `OsString` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:101:13 + --> $DIR/implicit_clone.rs:102:13 | LL | let _ = os_string.to_owned(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `os_string.clone()` error: implicitly cloning a `OsString` by calling `to_os_string` on its dereferenced type - --> $DIR/implicit_clone.rs:102:13 + --> $DIR/implicit_clone.rs:103:13 | LL | let _ = os_string.to_os_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `os_string.clone()` error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type - --> $DIR/implicit_clone.rs:113:13 + --> $DIR/implicit_clone.rs:114:13 | LL | let _ = pathbuf_ref.to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(*pathbuf_ref).clone()` error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type - --> $DIR/implicit_clone.rs:116:13 + --> $DIR/implicit_clone.rs:117:13 | LL | let _ = pathbuf_ref.to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(**pathbuf_ref).clone()` diff --git a/tests/ui/issue_2356.fixed b/tests/ui/issue_2356.fixed new file mode 100644 index 000000000000..942e99fa8787 --- /dev/null +++ b/tests/ui/issue_2356.fixed @@ -0,0 +1,26 @@ +// run-rustfix +#![deny(clippy::while_let_on_iterator)] +#![allow(unused_mut)] + +use std::iter::Iterator; + +struct Foo; + +impl Foo { + fn foo1>(mut it: I) { + while let Some(_) = it.next() { + println!("{:?}", it.size_hint()); + } + } + + fn foo2>(mut it: I) { + for e in it { + println!("{:?}", e); + } + } +} + +fn main() { + Foo::foo1(vec![].into_iter()); + Foo::foo2(vec![].into_iter()); +} diff --git a/tests/ui/issue_2356.rs b/tests/ui/issue_2356.rs index da580a1839a1..b000234ea596 100644 --- a/tests/ui/issue_2356.rs +++ b/tests/ui/issue_2356.rs @@ -1,4 +1,6 @@ +// run-rustfix #![deny(clippy::while_let_on_iterator)] +#![allow(unused_mut)] use std::iter::Iterator; diff --git a/tests/ui/issue_2356.stderr b/tests/ui/issue_2356.stderr index 51b872e21c08..4e3ff7522e0b 100644 --- a/tests/ui/issue_2356.stderr +++ b/tests/ui/issue_2356.stderr @@ -1,11 +1,11 @@ error: this loop could be written as a `for` loop - --> $DIR/issue_2356.rs:15:9 + --> $DIR/issue_2356.rs:17:9 | LL | while let Some(e) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for e in it` | note: the lint level is defined here - --> $DIR/issue_2356.rs:1:9 + --> $DIR/issue_2356.rs:2:9 | LL | #![deny(clippy::while_let_on_iterator)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/match_ref_pats.fixed b/tests/ui/match_ref_pats.fixed new file mode 100644 index 000000000000..1b6c2d924121 --- /dev/null +++ b/tests/ui/match_ref_pats.fixed @@ -0,0 +1,118 @@ +// run-rustfix +#![warn(clippy::match_ref_pats)] +#![allow(dead_code, unused_variables, clippy::equatable_if_let, clippy::enum_variant_names)] + +fn ref_pats() { + { + let v = &Some(0); + match *v { + Some(v) => println!("{:?}", v), + None => println!("none"), + } + match v { + // This doesn't trigger; we have a different pattern. + &Some(v) => println!("some"), + other => println!("other"), + } + } + let tup = &(1, 2); + match tup { + &(v, 1) => println!("{}", v), + _ => println!("none"), + } + // Special case: using `&` both in expr and pats. + let w = Some(0); + match w { + Some(v) => println!("{:?}", v), + None => println!("none"), + } + // False positive: only wildcard pattern. + let w = Some(0); + #[allow(clippy::match_single_binding)] + match w { + _ => println!("none"), + } + + let a = &Some(0); + if a.is_none() { + println!("none"); + } + + let b = Some(0); + if b.is_none() { + println!("none"); + } +} + +mod ice_3719 { + macro_rules! foo_variant( + ($idx:expr) => (Foo::get($idx).unwrap()) + ); + + enum Foo { + A, + B, + } + + impl Foo { + fn get(idx: u8) -> Option<&'static Self> { + match idx { + 0 => Some(&Foo::A), + 1 => Some(&Foo::B), + _ => None, + } + } + } + + fn ice_3719() { + // ICE #3719 + match foo_variant!(0) { + &Foo::A => println!("A"), + _ => println!("Wild"), + } + } +} + +mod issue_7740 { + macro_rules! foobar_variant( + ($idx:expr) => (FooBar::get($idx).unwrap()) + ); + + enum FooBar { + Foo, + Bar, + FooBar, + BarFoo, + } + + impl FooBar { + fn get(idx: u8) -> Option<&'static Self> { + match idx { + 0 => Some(&FooBar::Foo), + 1 => Some(&FooBar::Bar), + 2 => Some(&FooBar::FooBar), + 3 => Some(&FooBar::BarFoo), + _ => None, + } + } + } + + fn issue_7740() { + // Issue #7740 + match *foobar_variant!(0) { + FooBar::Foo => println!("Foo"), + FooBar::Bar => println!("Bar"), + FooBar::FooBar => println!("FooBar"), + _ => println!("Wild"), + } + + // This shouldn't trigger + if let &FooBar::BarFoo = foobar_variant!(3) { + println!("BarFoo"); + } else { + println!("Wild"); + } + } +} + +fn main() {} diff --git a/tests/ui/match_ref_pats.rs b/tests/ui/match_ref_pats.rs index 7e3674ab8c9f..68dfac4e2e97 100644 --- a/tests/ui/match_ref_pats.rs +++ b/tests/ui/match_ref_pats.rs @@ -1,5 +1,6 @@ +// run-rustfix #![warn(clippy::match_ref_pats)] -#![allow(clippy::equatable_if_let, clippy::enum_variant_names)] +#![allow(dead_code, unused_variables, clippy::equatable_if_let, clippy::enum_variant_names)] fn ref_pats() { { diff --git a/tests/ui/match_ref_pats.stderr b/tests/ui/match_ref_pats.stderr index 901820077e20..353f7399d9c2 100644 --- a/tests/ui/match_ref_pats.stderr +++ b/tests/ui/match_ref_pats.stderr @@ -1,5 +1,5 @@ error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:7:9 + --> $DIR/match_ref_pats.rs:8:9 | LL | / match v { LL | | &Some(v) => println!("{:?}", v), @@ -16,7 +16,7 @@ LL ~ None => println!("none"), | error: you don't need to add `&` to both the expression and the patterns - --> $DIR/match_ref_pats.rs:24:5 + --> $DIR/match_ref_pats.rs:25:5 | LL | / match &w { LL | | &Some(v) => println!("{:?}", v), @@ -32,7 +32,7 @@ LL ~ None => println!("none"), | error: redundant pattern matching, consider using `is_none()` - --> $DIR/match_ref_pats.rs:36:12 + --> $DIR/match_ref_pats.rs:37:12 | LL | if let &None = a { | -------^^^^^---- help: try this: `if a.is_none()` @@ -40,13 +40,13 @@ LL | if let &None = a { = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_none()` - --> $DIR/match_ref_pats.rs:41:12 + --> $DIR/match_ref_pats.rs:42:12 | LL | if let &None = &b { | -------^^^^^----- help: try this: `if b.is_none()` error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:101:9 + --> $DIR/match_ref_pats.rs:102:9 | LL | / match foobar_variant!(0) { LL | | &FooBar::Foo => println!("Foo"), diff --git a/tests/ui/match_str_case_mismatch.fixed b/tests/ui/match_str_case_mismatch.fixed new file mode 100644 index 000000000000..e436bcf495fd --- /dev/null +++ b/tests/ui/match_str_case_mismatch.fixed @@ -0,0 +1,186 @@ +// run-rustfix +#![warn(clippy::match_str_case_mismatch)] +#![allow(dead_code)] + +// Valid + +fn as_str_match() { + let var = "BAR"; + + match var.to_ascii_lowercase().as_str() { + "foo" => {}, + "bar" => {}, + _ => {}, + } +} + +fn non_alphabetic() { + let var = "~!@#$%^&*()-_=+FOO"; + + match var.to_ascii_lowercase().as_str() { + "1234567890" => {}, + "~!@#$%^&*()-_=+foo" => {}, + "\n\r\t\x7F" => {}, + _ => {}, + } +} + +fn unicode_cased() { + let var = "ВОДЫ"; + + match var.to_lowercase().as_str() { + "水" => {}, + "νερό" => {}, + "воды" => {}, + "물" => {}, + _ => {}, + } +} + +fn titlecase() { + let var = "BarDz"; + + match var.to_lowercase().as_str() { + "foolj" => {}, + "bardz" => {}, + _ => {}, + } +} + +fn no_case_equivalent() { + let var = "barʁ"; + + match var.to_uppercase().as_str() { + "FOOɕ" => {}, + "BARʁ" => {}, + _ => {}, + } +} + +fn addrof_unary_match() { + let var = "BAR"; + + match &*var.to_ascii_lowercase() { + "foo" => {}, + "bar" => {}, + _ => {}, + } +} + +fn alternating_chain() { + let var = "BAR"; + + match &*var + .to_ascii_lowercase() + .to_uppercase() + .to_lowercase() + .to_ascii_uppercase() + { + "FOO" => {}, + "BAR" => {}, + _ => {}, + } +} + +fn unrelated_method() { + struct Item { + a: String, + } + + impl Item { + #[allow(clippy::wrong_self_convention)] + fn to_lowercase(self) -> String { + self.a + } + } + + let item = Item { a: String::from("BAR") }; + + match &*item.to_lowercase() { + "FOO" => {}, + "BAR" => {}, + _ => {}, + } +} + +// Invalid + +fn as_str_match_mismatch() { + let var = "BAR"; + + match var.to_ascii_lowercase().as_str() { + "foo" => {}, + "bar" => {}, + _ => {}, + } +} + +fn non_alphabetic_mismatch() { + let var = "~!@#$%^&*()-_=+FOO"; + + match var.to_ascii_lowercase().as_str() { + "1234567890" => {}, + "~!@#$%^&*()-_=+foo" => {}, + "\n\r\t\x7F" => {}, + _ => {}, + } +} + +fn unicode_cased_mismatch() { + let var = "ВОДЫ"; + + match var.to_lowercase().as_str() { + "水" => {}, + "νερό" => {}, + "воды" => {}, + "물" => {}, + _ => {}, + } +} + +fn titlecase_mismatch() { + let var = "BarDz"; + + match var.to_lowercase().as_str() { + "foolj" => {}, + "bardz" => {}, + _ => {}, + } +} + +fn no_case_equivalent_mismatch() { + let var = "barʁ"; + + match var.to_uppercase().as_str() { + "FOOɕ" => {}, + "BARʁ" => {}, + _ => {}, + } +} + +fn addrof_unary_match_mismatch() { + let var = "BAR"; + + match &*var.to_ascii_lowercase() { + "foo" => {}, + "bar" => {}, + _ => {}, + } +} + +fn alternating_chain_mismatch() { + let var = "BAR"; + + match &*var + .to_ascii_lowercase() + .to_uppercase() + .to_lowercase() + .to_ascii_uppercase() + { + "FOO" => {}, + "BAR" => {}, + _ => {}, + } +} + +fn main() {} diff --git a/tests/ui/match_str_case_mismatch.rs b/tests/ui/match_str_case_mismatch.rs index ac555c87d83b..92e2a000ade2 100644 --- a/tests/ui/match_str_case_mismatch.rs +++ b/tests/ui/match_str_case_mismatch.rs @@ -1,4 +1,6 @@ +// run-rustfix #![warn(clippy::match_str_case_mismatch)] +#![allow(dead_code)] // Valid diff --git a/tests/ui/match_str_case_mismatch.stderr b/tests/ui/match_str_case_mismatch.stderr index 92baa40ef28f..197520a3d608 100644 --- a/tests/ui/match_str_case_mismatch.stderr +++ b/tests/ui/match_str_case_mismatch.stderr @@ -1,5 +1,5 @@ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:111:9 + --> $DIR/match_str_case_mismatch.rs:113:9 | LL | "Bar" => {}, | ^^^^^ @@ -11,7 +11,7 @@ LL | "bar" => {}, | ~~~~~ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:121:9 + --> $DIR/match_str_case_mismatch.rs:123:9 | LL | "~!@#$%^&*()-_=+Foo" => {}, | ^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | "~!@#$%^&*()-_=+foo" => {}, | ~~~~~~~~~~~~~~~~~~~~ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:133:9 + --> $DIR/match_str_case_mismatch.rs:135:9 | LL | "Воды" => {}, | ^^^^^^ @@ -33,7 +33,7 @@ LL | "воды" => {}, | ~~~~~~ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:144:9 + --> $DIR/match_str_case_mismatch.rs:146:9 | LL | "barDz" => {}, | ^^^^^^ @@ -44,7 +44,7 @@ LL | "bardz" => {}, | ~~~~~~ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:154:9 + --> $DIR/match_str_case_mismatch.rs:156:9 | LL | "bARʁ" => {}, | ^^^^^^ @@ -55,7 +55,7 @@ LL | "BARʁ" => {}, | ~~~~~~ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:164:9 + --> $DIR/match_str_case_mismatch.rs:166:9 | LL | "Bar" => {}, | ^^^^^ @@ -66,7 +66,7 @@ LL | "bar" => {}, | ~~~~~ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:179:9 + --> $DIR/match_str_case_mismatch.rs:181:9 | LL | "bAR" => {}, | ^^^^^ diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed new file mode 100644 index 000000000000..fee8e3030b80 --- /dev/null +++ b/tests/ui/needless_late_init.fixed @@ -0,0 +1,273 @@ +// run-rustfix +#![feature(let_chains)] +#![allow( + unused, + clippy::assign_op_pattern, + clippy::blocks_in_if_conditions, + clippy::let_and_return, + clippy::let_unit_value, + clippy::nonminimal_bool +)] + +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; +use std::rc::Rc; + +struct SignificantDrop; +impl std::ops::Drop for SignificantDrop { + fn drop(&mut self) { + println!("dropped"); + } +} + +fn simple() { + + let a = "zero"; + + + + let b = 1; + let c = 2; + + + let d: usize = 1; + + + let e = format!("{}", d); +} + +fn main() { + + let n = 1; + let a = match n { + 1 => "one", + _ => { + "two" + }, + }; + + + let b = if n == 3 { + "four" + } else { + "five" + }; + + + let d = if true { + let temp = 5; + temp + } else { + 15 + }; + + + let e = if true { + format!("{} {}", a, b) + } else { + format!("{}", n) + }; + + + let f = match 1 { + 1 => "three", + _ => return, + }; // has semi + + + let g: usize = if true { + 5 + } else { + panic!(); + }; + + // Drop order only matters if both are significant + + let y = SignificantDrop; + let x = 1; + + + let y = 1; + let x = SignificantDrop; + + + // types that should be considered insignificant + let y = 1; + let y = "2"; + let y = String::new(); + let y = vec![3.0]; + let y = HashMap::::new(); + let y = BTreeMap::::new(); + let y = HashSet::::new(); + let y = BTreeSet::::new(); + let y = Box::new(4); + let x = SignificantDrop; +} + +async fn in_async() -> &'static str { + async fn f() -> &'static str { + "one" + } + + + let n = 1; + let a = match n { + 1 => f().await, + _ => { + "two" + }, + }; + + a +} + +const fn in_const() -> &'static str { + const fn f() -> &'static str { + "one" + } + + + let n = 1; + let a = match n { + 1 => f(), + _ => { + "two" + }, + }; + + a +} + +fn does_not_lint() { + let z; + if false { + z = 1; + } + + let x; + let y; + if true { + x = 1; + } else { + y = 1; + } + + let mut x; + if true { + x = 5; + x = 10 / x; + } else { + x = 2; + } + + let x; + let _ = match 1 { + 1 => x = 10, + _ => x = 20, + }; + + // using tuples would be possible, but not always preferable + let x; + let y; + if true { + x = 1; + y = 2; + } else { + x = 3; + y = 4; + } + + // could match with a smarter heuristic to avoid multiple assignments + let x; + if true { + let mut y = 5; + y = 6; + x = y; + } else { + x = 2; + } + + let (x, y); + if true { + x = 1; + } else { + x = 2; + } + y = 3; + + macro_rules! assign { + ($i:ident) => { + $i = 1; + }; + } + let x; + assign!(x); + + let x; + if true { + assign!(x); + } else { + x = 2; + } + + macro_rules! in_macro { + () => { + let x; + x = 1; + + let x; + if true { + x = 1; + } else { + x = 2; + } + }; + } + in_macro!(); + + // ignore if-lets - https://github.com/rust-lang/rust-clippy/issues/8613 + let x; + if let Some(n) = Some("v") { + x = 1; + } else { + x = 2; + } + + let x; + if true && let Some(n) = Some("let chains too") { + x = 1; + } else { + x = 2; + } + + // ignore mut bindings + // https://github.com/shepmaster/twox-hash/blob/b169c16d86eb8ea4a296b0acb9d00ca7e3c3005f/src/sixty_four.rs#L88-L93 + // https://github.com/dtolnay/thiserror/blob/21c26903e29cb92ba1a7ff11e82ae2001646b60d/tests/test_generics.rs#L91-L100 + let mut x: usize; + x = 1; + x = 2; + x = 3; + + // should not move the declaration if `x` has a significant drop, and there + // is another binding with a significant drop between it and the first usage + let x; + let y = SignificantDrop; + x = SignificantDrop; +} + +#[rustfmt::skip] +fn issue8911() -> u32 { + let x; + match 1 { + _ if { x = 1; false } => return 1, + _ => return 2, + } + + let x; + if { x = 1; true } { + return 1; + } else { + return 2; + } + + 3 +} diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs index 54e66b391b8d..402d9f9ef7f8 100644 --- a/tests/ui/needless_late_init.rs +++ b/tests/ui/needless_late_init.rs @@ -1,5 +1,13 @@ +// run-rustfix #![feature(let_chains)] -#![allow(unused, clippy::nonminimal_bool, clippy::let_unit_value)] +#![allow( + unused, + clippy::assign_op_pattern, + clippy::blocks_in_if_conditions, + clippy::let_and_return, + clippy::let_unit_value, + clippy::nonminimal_bool +)] use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::rc::Rc; @@ -11,6 +19,22 @@ impl std::ops::Drop for SignificantDrop { } } +fn simple() { + let a; + a = "zero"; + + let b; + let c; + b = 1; + c = 2; + + let d: usize; + d = 1; + + let e; + e = format!("{}", d); +} + fn main() { let a; let n = 1; @@ -229,3 +253,21 @@ fn does_not_lint() { let y = SignificantDrop; x = SignificantDrop; } + +#[rustfmt::skip] +fn issue8911() -> u32 { + let x; + match 1 { + _ if { x = 1; false } => return 1, + _ => return 2, + } + + let x; + if { x = 1; true } { + return 1; + } else { + return 2; + } + + 3 +} diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr index d33a117b288c..f320b5b9cbb3 100644 --- a/tests/ui/needless_late_init.stderr +++ b/tests/ui/needless_late_init.stderr @@ -1,12 +1,79 @@ error: unneeded late initialization - --> $DIR/needless_late_init.rs:15:5 + --> $DIR/needless_late_init.rs:23:5 | LL | let a; - | ^^^^^^ + | ^^^^^^ created here +LL | a = "zero"; + | ^^^^^^^^^^ initialised here | = note: `-D clippy::needless-late-init` implied by `-D warnings` help: declare `a` here | +LL | let a = "zero"; + | ~~~~~ + +error: unneeded late initialization + --> $DIR/needless_late_init.rs:26:5 + | +LL | let b; + | ^^^^^^ created here +LL | let c; +LL | b = 1; + | ^^^^^ initialised here + | +help: declare `b` here + | +LL | let b = 1; + | ~~~~~ + +error: unneeded late initialization + --> $DIR/needless_late_init.rs:27:5 + | +LL | let c; + | ^^^^^^ created here +LL | b = 1; +LL | c = 2; + | ^^^^^ initialised here + | +help: declare `c` here + | +LL | let c = 2; + | ~~~~~ + +error: unneeded late initialization + --> $DIR/needless_late_init.rs:31:5 + | +LL | let d: usize; + | ^^^^^^^^^^^^^ created here +LL | d = 1; + | ^^^^^ initialised here + | +help: declare `d` here + | +LL | let d: usize = 1; + | ~~~~~~~~~~~~ + +error: unneeded late initialization + --> $DIR/needless_late_init.rs:34:5 + | +LL | let e; + | ^^^^^^ created here +LL | e = format!("{}", d); + | ^^^^^^^^^^^^^^^^^^^^ initialised here + | +help: declare `e` here + | +LL | let e = format!("{}", d); + | ~~~~~ + +error: unneeded late initialization + --> $DIR/needless_late_init.rs:39:5 + | +LL | let a; + | ^^^^^^ + | +help: declare `a` here + | LL | let a = match n { | +++++++ help: remove the assignments from the `match` arms @@ -21,7 +88,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:24:5 + --> $DIR/needless_late_init.rs:48:5 | LL | let b; | ^^^^^^ @@ -42,7 +109,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:31:5 + --> $DIR/needless_late_init.rs:55:5 | LL | let d; | ^^^^^^ @@ -63,7 +130,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:39:5 + --> $DIR/needless_late_init.rs:63:5 | LL | let e; | ^^^^^^ @@ -84,7 +151,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:46:5 + --> $DIR/needless_late_init.rs:70:5 | LL | let f; | ^^^^^^ @@ -100,7 +167,7 @@ LL + 1 => "three", | error: unneeded late initialization - --> $DIR/needless_late_init.rs:52:5 + --> $DIR/needless_late_init.rs:76:5 | LL | let g: usize; | ^^^^^^^^^^^^^ @@ -120,7 +187,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:60:5 + --> $DIR/needless_late_init.rs:84:5 | LL | let x; | ^^^^^^ created here @@ -134,7 +201,7 @@ LL | let x = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:64:5 + --> $DIR/needless_late_init.rs:88:5 | LL | let x; | ^^^^^^ created here @@ -148,7 +215,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:68:5 + --> $DIR/needless_late_init.rs:92:5 | LL | let x; | ^^^^^^ created here @@ -162,7 +229,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:87:5 + --> $DIR/needless_late_init.rs:111:5 | LL | let a; | ^^^^^^ @@ -183,7 +250,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:104:5 + --> $DIR/needless_late_init.rs:128:5 | LL | let a; | ^^^^^^ @@ -203,5 +270,5 @@ help: add a semicolon after the `match` expression LL | }; | + -error: aborting due to 11 previous errors +error: aborting due to 16 previous errors diff --git a/tests/ui/needless_late_init_fixable.fixed b/tests/ui/needless_late_init_fixable.fixed deleted file mode 100644 index 724477e8691d..000000000000 --- a/tests/ui/needless_late_init_fixable.fixed +++ /dev/null @@ -1,19 +0,0 @@ -// run-rustfix - -#![allow(unused, clippy::assign_op_pattern)] - -fn main() { - - let a = "zero"; - - - - let b = 1; - let c = 2; - - - let d: usize = 1; - - - let e = format!("{}", d); -} diff --git a/tests/ui/needless_late_init_fixable.rs b/tests/ui/needless_late_init_fixable.rs deleted file mode 100644 index 3e6bd3636727..000000000000 --- a/tests/ui/needless_late_init_fixable.rs +++ /dev/null @@ -1,19 +0,0 @@ -// run-rustfix - -#![allow(unused, clippy::assign_op_pattern)] - -fn main() { - let a; - a = "zero"; - - let b; - let c; - b = 1; - c = 2; - - let d: usize; - d = 1; - - let e; - e = format!("{}", d); -} diff --git a/tests/ui/needless_late_init_fixable.stderr b/tests/ui/needless_late_init_fixable.stderr deleted file mode 100644 index 8c664309e3e8..000000000000 --- a/tests/ui/needless_late_init_fixable.stderr +++ /dev/null @@ -1,70 +0,0 @@ -error: unneeded late initialization - --> $DIR/needless_late_init_fixable.rs:6:5 - | -LL | let a; - | ^^^^^^ created here -LL | a = "zero"; - | ^^^^^^^^^^ initialised here - | - = note: `-D clippy::needless-late-init` implied by `-D warnings` -help: declare `a` here - | -LL | let a = "zero"; - | ~~~~~ - -error: unneeded late initialization - --> $DIR/needless_late_init_fixable.rs:9:5 - | -LL | let b; - | ^^^^^^ created here -LL | let c; -LL | b = 1; - | ^^^^^ initialised here - | -help: declare `b` here - | -LL | let b = 1; - | ~~~~~ - -error: unneeded late initialization - --> $DIR/needless_late_init_fixable.rs:10:5 - | -LL | let c; - | ^^^^^^ created here -LL | b = 1; -LL | c = 2; - | ^^^^^ initialised here - | -help: declare `c` here - | -LL | let c = 2; - | ~~~~~ - -error: unneeded late initialization - --> $DIR/needless_late_init_fixable.rs:14:5 - | -LL | let d: usize; - | ^^^^^^^^^^^^^ created here -LL | d = 1; - | ^^^^^ initialised here - | -help: declare `d` here - | -LL | let d: usize = 1; - | ~~~~~~~~~~~~ - -error: unneeded late initialization - --> $DIR/needless_late_init_fixable.rs:17:5 - | -LL | let e; - | ^^^^^^ created here -LL | e = format!("{}", d); - | ^^^^^^^^^^^^^^^^^^^^ initialised here - | -help: declare `e` here - | -LL | let e = format!("{}", d); - | ~~~~~ - -error: aborting due to 5 previous errors - diff --git a/tests/ui/nonminimal_bool_methods.fixed b/tests/ui/nonminimal_bool_methods.fixed new file mode 100644 index 000000000000..aad44089de49 --- /dev/null +++ b/tests/ui/nonminimal_bool_methods.fixed @@ -0,0 +1,111 @@ +// run-rustfix +#![allow(unused, clippy::diverging_sub_expression)] +#![warn(clippy::nonminimal_bool)] + +fn methods_with_negation() { + let a: Option = unimplemented!(); + let b: Result = unimplemented!(); + let _ = a.is_some(); + let _ = a.is_none(); + let _ = a.is_none(); + let _ = a.is_some(); + let _ = b.is_err(); + let _ = b.is_ok(); + let _ = b.is_ok(); + let _ = b.is_err(); + let c = false; + let _ = a.is_none() || c; + let _ = a.is_none() && c; + let _ = !(!c ^ c) || a.is_none(); + let _ = (!c ^ c) || a.is_none(); + let _ = !c ^ c || a.is_none(); +} + +// Simplified versions of https://github.com/rust-lang/rust-clippy/issues/2638 +// clippy::nonminimal_bool should only check the built-in Result and Some type, not +// any other types like the following. +enum CustomResultOk { + Ok, + Err(E), +} +enum CustomResultErr { + Ok, + Err(E), +} +enum CustomSomeSome { + Some(T), + None, +} +enum CustomSomeNone { + Some(T), + None, +} + +impl CustomResultOk { + pub fn is_ok(&self) -> bool { + true + } +} + +impl CustomResultErr { + pub fn is_err(&self) -> bool { + true + } +} + +impl CustomSomeSome { + pub fn is_some(&self) -> bool { + true + } +} + +impl CustomSomeNone { + pub fn is_none(&self) -> bool { + true + } +} + +fn dont_warn_for_custom_methods_with_negation() { + let res = CustomResultOk::Err("Error"); + // Should not warn and suggest 'is_err()' because the type does not + // implement is_err(). + if !res.is_ok() {} + + let res = CustomResultErr::Err("Error"); + // Should not warn and suggest 'is_ok()' because the type does not + // implement is_ok(). + if !res.is_err() {} + + let res = CustomSomeSome::Some("thing"); + // Should not warn and suggest 'is_none()' because the type does not + // implement is_none(). + if !res.is_some() {} + + let res = CustomSomeNone::Some("thing"); + // Should not warn and suggest 'is_some()' because the type does not + // implement is_some(). + if !res.is_none() {} +} + +// Only Built-in Result and Some types should suggest the negated alternative +fn warn_for_built_in_methods_with_negation() { + let res: Result = Ok(1); + if res.is_err() {} + if res.is_ok() {} + + let res = Some(1); + if res.is_none() {} + if res.is_some() {} +} + +#[allow(clippy::neg_cmp_op_on_partial_ord)] +fn dont_warn_for_negated_partial_ord_comparison() { + let a: f64 = unimplemented!(); + let b: f64 = unimplemented!(); + let _ = !(a < b); + let _ = !(a <= b); + let _ = !(a > b); + let _ = !(a >= b); +} + +fn main() {} diff --git a/tests/ui/nonminimal_bool_methods.rs b/tests/ui/nonminimal_bool_methods.rs index d0a289b7ea43..b9074da84270 100644 --- a/tests/ui/nonminimal_bool_methods.rs +++ b/tests/ui/nonminimal_bool_methods.rs @@ -1,3 +1,4 @@ +// run-rustfix #![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/nonminimal_bool_methods.stderr b/tests/ui/nonminimal_bool_methods.stderr index a2df889d6230..21b84db85890 100644 --- a/tests/ui/nonminimal_bool_methods.stderr +++ b/tests/ui/nonminimal_bool_methods.stderr @@ -1,5 +1,5 @@ error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:8:13 + --> $DIR/nonminimal_bool_methods.rs:9:13 | LL | let _ = !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` @@ -7,73 +7,73 @@ LL | let _ = !a.is_some(); = note: `-D clippy::nonminimal-bool` implied by `-D warnings` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:10:13 + --> $DIR/nonminimal_bool_methods.rs:11:13 | LL | let _ = !a.is_none(); | ^^^^^^^^^^^^ help: try: `a.is_some()` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:12:13 + --> $DIR/nonminimal_bool_methods.rs:13:13 | LL | let _ = !b.is_err(); | ^^^^^^^^^^^ help: try: `b.is_ok()` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:14:13 + --> $DIR/nonminimal_bool_methods.rs:15:13 | LL | let _ = !b.is_ok(); | ^^^^^^^^^^ help: try: `b.is_err()` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:16:13 + --> $DIR/nonminimal_bool_methods.rs:17:13 | LL | let _ = !(a.is_some() && !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() || c` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:17:13 + --> $DIR/nonminimal_bool_methods.rs:18:13 | LL | let _ = !(a.is_some() || !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() && c` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:18:26 + --> $DIR/nonminimal_bool_methods.rs:19:26 | LL | let _ = !(!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:19:25 + --> $DIR/nonminimal_bool_methods.rs:20:25 | LL | let _ = (!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:20:23 + --> $DIR/nonminimal_bool_methods.rs:21:23 | LL | let _ = !c ^ c || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:92:8 + --> $DIR/nonminimal_bool_methods.rs:93:8 | LL | if !res.is_ok() {} | ^^^^^^^^^^^^ help: try: `res.is_err()` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:93:8 + --> $DIR/nonminimal_bool_methods.rs:94:8 | LL | if !res.is_err() {} | ^^^^^^^^^^^^^ help: try: `res.is_ok()` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:96:8 + --> $DIR/nonminimal_bool_methods.rs:97:8 | LL | if !res.is_some() {} | ^^^^^^^^^^^^^^ help: try: `res.is_none()` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool_methods.rs:97:8 + --> $DIR/nonminimal_bool_methods.rs:98:8 | LL | if !res.is_none() {} | ^^^^^^^^^^^^^^ help: try: `res.is_some()` diff --git a/tests/ui/rc_buffer.fixed b/tests/ui/rc_buffer.fixed new file mode 100644 index 000000000000..8910c01b1fcf --- /dev/null +++ b/tests/ui/rc_buffer.fixed @@ -0,0 +1,28 @@ +// run-rustfix +#![warn(clippy::rc_buffer)] +#![allow(dead_code, unused_imports)] + +use std::cell::RefCell; +use std::ffi::OsString; +use std::path::PathBuf; +use std::rc::Rc; + +struct S { + // triggers lint + bad1: Rc, + bad2: Rc, + bad3: Rc<[u8]>, + bad4: Rc, + // does not trigger lint + good1: Rc>, +} + +// triggers lint +fn func_bad1(_: Rc) {} +fn func_bad2(_: Rc) {} +fn func_bad3(_: Rc<[u8]>) {} +fn func_bad4(_: Rc) {} +// does not trigger lint +fn func_good1(_: Rc>) {} + +fn main() {} diff --git a/tests/ui/rc_buffer.rs b/tests/ui/rc_buffer.rs index 1fa986439368..1e63a43262ec 100644 --- a/tests/ui/rc_buffer.rs +++ b/tests/ui/rc_buffer.rs @@ -1,4 +1,6 @@ +// run-rustfix #![warn(clippy::rc_buffer)] +#![allow(dead_code, unused_imports)] use std::cell::RefCell; use std::ffi::OsString; diff --git a/tests/ui/rc_buffer.stderr b/tests/ui/rc_buffer.stderr index e4cc169af07b..9ed028e3df41 100644 --- a/tests/ui/rc_buffer.stderr +++ b/tests/ui/rc_buffer.stderr @@ -1,5 +1,5 @@ error: usage of `Rc` when T is a buffer type - --> $DIR/rc_buffer.rs:10:11 + --> $DIR/rc_buffer.rs:12:11 | LL | bad1: Rc, | ^^^^^^^^^^ help: try: `Rc` @@ -7,43 +7,43 @@ LL | bad1: Rc, = note: `-D clippy::rc-buffer` implied by `-D warnings` error: usage of `Rc` when T is a buffer type - --> $DIR/rc_buffer.rs:11:11 + --> $DIR/rc_buffer.rs:13:11 | LL | bad2: Rc, | ^^^^^^^^^^^ help: try: `Rc` error: usage of `Rc` when T is a buffer type - --> $DIR/rc_buffer.rs:12:11 + --> $DIR/rc_buffer.rs:14:11 | LL | bad3: Rc>, | ^^^^^^^^^^^ help: try: `Rc<[u8]>` error: usage of `Rc` when T is a buffer type - --> $DIR/rc_buffer.rs:13:11 + --> $DIR/rc_buffer.rs:15:11 | LL | bad4: Rc, | ^^^^^^^^^^^^ help: try: `Rc` error: usage of `Rc` when T is a buffer type - --> $DIR/rc_buffer.rs:19:17 + --> $DIR/rc_buffer.rs:21:17 | LL | fn func_bad1(_: Rc) {} | ^^^^^^^^^^ help: try: `Rc` error: usage of `Rc` when T is a buffer type - --> $DIR/rc_buffer.rs:20:17 + --> $DIR/rc_buffer.rs:22:17 | LL | fn func_bad2(_: Rc) {} | ^^^^^^^^^^^ help: try: `Rc` error: usage of `Rc` when T is a buffer type - --> $DIR/rc_buffer.rs:21:17 + --> $DIR/rc_buffer.rs:23:17 | LL | fn func_bad3(_: Rc>) {} | ^^^^^^^^^^^ help: try: `Rc<[u8]>` error: usage of `Rc` when T is a buffer type - --> $DIR/rc_buffer.rs:22:17 + --> $DIR/rc_buffer.rs:24:17 | LL | fn func_bad4(_: Rc) {} | ^^^^^^^^^^^^ help: try: `Rc` diff --git a/tests/ui/rc_buffer_arc.fixed b/tests/ui/rc_buffer_arc.fixed new file mode 100644 index 000000000000..13dd6f5fcd18 --- /dev/null +++ b/tests/ui/rc_buffer_arc.fixed @@ -0,0 +1,27 @@ +// run-rustfix +#![warn(clippy::rc_buffer)] +#![allow(dead_code, unused_imports)] + +use std::ffi::OsString; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; + +struct S { + // triggers lint + bad1: Arc, + bad2: Arc, + bad3: Arc<[u8]>, + bad4: Arc, + // does not trigger lint + good1: Arc>, +} + +// triggers lint +fn func_bad1(_: Arc) {} +fn func_bad2(_: Arc) {} +fn func_bad3(_: Arc<[u8]>) {} +fn func_bad4(_: Arc) {} +// does not trigger lint +fn func_good1(_: Arc>) {} + +fn main() {} diff --git a/tests/ui/rc_buffer_arc.rs b/tests/ui/rc_buffer_arc.rs index 5d586584817b..1a521bfeb7c8 100644 --- a/tests/ui/rc_buffer_arc.rs +++ b/tests/ui/rc_buffer_arc.rs @@ -1,4 +1,6 @@ +// run-rustfix #![warn(clippy::rc_buffer)] +#![allow(dead_code, unused_imports)] use std::ffi::OsString; use std::path::PathBuf; diff --git a/tests/ui/rc_buffer_arc.stderr b/tests/ui/rc_buffer_arc.stderr index 8252270d2ac7..911feea73529 100644 --- a/tests/ui/rc_buffer_arc.stderr +++ b/tests/ui/rc_buffer_arc.stderr @@ -1,5 +1,5 @@ error: usage of `Arc` when T is a buffer type - --> $DIR/rc_buffer_arc.rs:9:11 + --> $DIR/rc_buffer_arc.rs:11:11 | LL | bad1: Arc, | ^^^^^^^^^^^ help: try: `Arc` @@ -7,43 +7,43 @@ LL | bad1: Arc, = note: `-D clippy::rc-buffer` implied by `-D warnings` error: usage of `Arc` when T is a buffer type - --> $DIR/rc_buffer_arc.rs:10:11 + --> $DIR/rc_buffer_arc.rs:12:11 | LL | bad2: Arc, | ^^^^^^^^^^^^ help: try: `Arc` error: usage of `Arc` when T is a buffer type - --> $DIR/rc_buffer_arc.rs:11:11 + --> $DIR/rc_buffer_arc.rs:13:11 | LL | bad3: Arc>, | ^^^^^^^^^^^^ help: try: `Arc<[u8]>` error: usage of `Arc` when T is a buffer type - --> $DIR/rc_buffer_arc.rs:12:11 + --> $DIR/rc_buffer_arc.rs:14:11 | LL | bad4: Arc, | ^^^^^^^^^^^^^ help: try: `Arc` error: usage of `Arc` when T is a buffer type - --> $DIR/rc_buffer_arc.rs:18:17 + --> $DIR/rc_buffer_arc.rs:20:17 | LL | fn func_bad1(_: Arc) {} | ^^^^^^^^^^^ help: try: `Arc` error: usage of `Arc` when T is a buffer type - --> $DIR/rc_buffer_arc.rs:19:17 + --> $DIR/rc_buffer_arc.rs:21:17 | LL | fn func_bad2(_: Arc) {} | ^^^^^^^^^^^^ help: try: `Arc` error: usage of `Arc` when T is a buffer type - --> $DIR/rc_buffer_arc.rs:20:17 + --> $DIR/rc_buffer_arc.rs:22:17 | LL | fn func_bad3(_: Arc>) {} | ^^^^^^^^^^^^ help: try: `Arc<[u8]>` error: usage of `Arc` when T is a buffer type - --> $DIR/rc_buffer_arc.rs:21:17 + --> $DIR/rc_buffer_arc.rs:23:17 | LL | fn func_bad4(_: Arc) {} | ^^^^^^^^^^^^^ help: try: `Arc` diff --git a/tests/ui/rc_clone_in_vec_init/arc.stderr b/tests/ui/rc_clone_in_vec_init/arc.stderr index ce84186c8e30..cd7d91e12065 100644 --- a/tests/ui/rc_clone_in_vec_init/arc.stderr +++ b/tests/ui/rc_clone_in_vec_init/arc.stderr @@ -1,4 +1,4 @@ -error: calling `Arc::new` in `vec![elem; len]` +error: initializing a reference-counted pointer in `vec![elem; len]` --> $DIR/arc.rs:7:13 | LL | let v = vec![Arc::new("x".to_string()); 2]; @@ -10,19 +10,19 @@ help: consider initializing each `Arc` element individually | LL ~ let v = { LL + let mut v = Vec::with_capacity(2); -LL + (0..2).for_each(|_| v.push(Arc::new("x".to_string()))); +LL + (0..2).for_each(|_| v.push(Arc::new(..))); LL + v LL ~ }; | help: or if this is intentional, consider extracting the `Arc` initialization to a variable | LL ~ let v = { -LL + let data = Arc::new("x".to_string()); +LL + let data = Arc::new(..); LL + vec![data; 2] LL ~ }; | -error: calling `Arc::new` in `vec![elem; len]` +error: initializing a reference-counted pointer in `vec![elem; len]` --> $DIR/arc.rs:15:21 | LL | let v = vec![Arc::new("x".to_string()); 2]; @@ -33,19 +33,19 @@ help: consider initializing each `Arc` element individually | LL ~ let v = { LL + let mut v = Vec::with_capacity(2); -LL + (0..2).for_each(|_| v.push(Arc::new("x".to_string()))); +LL + (0..2).for_each(|_| v.push(Arc::new(..))); LL + v LL ~ }; | help: or if this is intentional, consider extracting the `Arc` initialization to a variable | LL ~ let v = { -LL + let data = Arc::new("x".to_string()); +LL + let data = Arc::new(..); LL + vec![data; 2] LL ~ }; | -error: calling `Arc::new` in `vec![elem; len]` +error: initializing a reference-counted pointer in `vec![elem; len]` --> $DIR/arc.rs:21:13 | LL | let v = vec![ @@ -75,7 +75,7 @@ LL + vec![data; 2] LL ~ }; | -error: calling `Arc::new` in `vec![elem; len]` +error: initializing a reference-counted pointer in `vec![elem; len]` --> $DIR/arc.rs:30:14 | LL | let v1 = vec![ diff --git a/tests/ui/rc_clone_in_vec_init/rc.stderr b/tests/ui/rc_clone_in_vec_init/rc.stderr index 0f5cc0cf98fe..fe861afe0549 100644 --- a/tests/ui/rc_clone_in_vec_init/rc.stderr +++ b/tests/ui/rc_clone_in_vec_init/rc.stderr @@ -1,4 +1,4 @@ -error: calling `Rc::new` in `vec![elem; len]` +error: initializing a reference-counted pointer in `vec![elem; len]` --> $DIR/rc.rs:8:13 | LL | let v = vec![Rc::new("x".to_string()); 2]; @@ -10,19 +10,19 @@ help: consider initializing each `Rc` element individually | LL ~ let v = { LL + let mut v = Vec::with_capacity(2); -LL + (0..2).for_each(|_| v.push(Rc::new("x".to_string()))); +LL + (0..2).for_each(|_| v.push(Rc::new(..))); LL + v LL ~ }; | help: or if this is intentional, consider extracting the `Rc` initialization to a variable | LL ~ let v = { -LL + let data = Rc::new("x".to_string()); +LL + let data = Rc::new(..); LL + vec![data; 2] LL ~ }; | -error: calling `Rc::new` in `vec![elem; len]` +error: initializing a reference-counted pointer in `vec![elem; len]` --> $DIR/rc.rs:16:21 | LL | let v = vec![Rc::new("x".to_string()); 2]; @@ -33,19 +33,19 @@ help: consider initializing each `Rc` element individually | LL ~ let v = { LL + let mut v = Vec::with_capacity(2); -LL + (0..2).for_each(|_| v.push(Rc::new("x".to_string()))); +LL + (0..2).for_each(|_| v.push(Rc::new(..))); LL + v LL ~ }; | help: or if this is intentional, consider extracting the `Rc` initialization to a variable | LL ~ let v = { -LL + let data = Rc::new("x".to_string()); +LL + let data = Rc::new(..); LL + vec![data; 2] LL ~ }; | -error: calling `Rc::new` in `vec![elem; len]` +error: initializing a reference-counted pointer in `vec![elem; len]` --> $DIR/rc.rs:22:13 | LL | let v = vec![ @@ -75,7 +75,7 @@ LL + vec![data; 2] LL ~ }; | -error: calling `Rc::new` in `vec![elem; len]` +error: initializing a reference-counted pointer in `vec![elem; len]` --> $DIR/rc.rs:31:14 | LL | let v1 = vec![ diff --git a/tests/ui/rc_clone_in_vec_init/weak.rs b/tests/ui/rc_clone_in_vec_init/weak.rs new file mode 100644 index 000000000000..693c9b553c56 --- /dev/null +++ b/tests/ui/rc_clone_in_vec_init/weak.rs @@ -0,0 +1,83 @@ +#![warn(clippy::rc_clone_in_vec_init)] +use std::rc::{Rc, Weak as UnSyncWeak}; +use std::sync::{Arc, Mutex, Weak as SyncWeak}; + +fn main() {} + +fn should_warn_simple_case() { + let v = vec![SyncWeak::::new(); 2]; + let v2 = vec![UnSyncWeak::::new(); 2]; + + let v = vec![Rc::downgrade(&Rc::new("x".to_string())); 2]; + let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2]; +} + +fn should_warn_simple_case_with_big_indentation() { + if true { + let k = 1; + dbg!(k); + if true { + let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2]; + let v2 = vec![Rc::downgrade(&Rc::new("x".to_string())); 2]; + } + } +} + +fn should_warn_complex_case() { + let v = vec![ + Arc::downgrade(&Arc::new(Mutex::new({ + let x = 1; + dbg!(x); + x + }))); + 2 + ]; + + let v1 = vec![ + Rc::downgrade(&Rc::new(Mutex::new({ + let x = 1; + dbg!(x); + x + }))); + 2 + ]; +} + +fn should_not_warn_custom_weak() { + #[derive(Clone)] + struct Weak; + + impl Weak { + fn new() -> Self { + Weak + } + } + + let v = vec![Weak::new(); 2]; +} + +fn should_not_warn_vec_from_elem_but_not_weak() { + let v = vec![String::new(); 2]; + let v1 = vec![1; 2]; + let v2 = vec![ + Box::new(Arc::downgrade(&Arc::new({ + let y = 3; + dbg!(y); + y + }))); + 2 + ]; + let v3 = vec![ + Box::new(Rc::downgrade(&Rc::new({ + let y = 3; + dbg!(y); + y + }))); + 2 + ]; +} + +fn should_not_warn_vec_macro_but_not_from_elem() { + let v = vec![Arc::downgrade(&Arc::new("x".to_string()))]; + let v = vec![Rc::downgrade(&Rc::new("x".to_string()))]; +} diff --git a/tests/ui/rc_clone_in_vec_init/weak.stderr b/tests/ui/rc_clone_in_vec_init/weak.stderr new file mode 100644 index 000000000000..4a21946ccdfa --- /dev/null +++ b/tests/ui/rc_clone_in_vec_init/weak.stderr @@ -0,0 +1,201 @@ +error: initializing a reference-counted pointer in `vec![elem; len]` + --> $DIR/weak.rs:8:13 + | +LL | let v = vec![SyncWeak::::new(); 2]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings` + = note: each element will point to the same `Weak` instance +help: consider initializing each `Weak` element individually + | +LL ~ let v = { +LL + let mut v = Vec::with_capacity(2); +LL + (0..2).for_each(|_| v.push(SyncWeak::::new(..))); +LL + v +LL ~ }; + | +help: or if this is intentional, consider extracting the `Weak` initialization to a variable + | +LL ~ let v = { +LL + let data = SyncWeak::::new(..); +LL + vec![data; 2] +LL ~ }; + | + +error: initializing a reference-counted pointer in `vec![elem; len]` + --> $DIR/weak.rs:9:14 + | +LL | let v2 = vec![UnSyncWeak::::new(); 2]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each element will point to the same `Weak` instance +help: consider initializing each `Weak` element individually + | +LL ~ let v2 = { +LL + let mut v = Vec::with_capacity(2); +LL + (0..2).for_each(|_| v.push(UnSyncWeak::::new(..))); +LL + v +LL ~ }; + | +help: or if this is intentional, consider extracting the `Weak` initialization to a variable + | +LL ~ let v2 = { +LL + let data = UnSyncWeak::::new(..); +LL + vec![data; 2] +LL ~ }; + | + +error: initializing a reference-counted pointer in `vec![elem; len]` + --> $DIR/weak.rs:11:13 + | +LL | let v = vec![Rc::downgrade(&Rc::new("x".to_string())); 2]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each element will point to the same `Weak` instance +help: consider initializing each `Weak` element individually + | +LL ~ let v = { +LL + let mut v = Vec::with_capacity(2); +LL + (0..2).for_each(|_| v.push(Rc::downgrade(..))); +LL + v +LL ~ }; + | +help: or if this is intentional, consider extracting the `Weak` initialization to a variable + | +LL ~ let v = { +LL + let data = Rc::downgrade(..); +LL + vec![data; 2] +LL ~ }; + | + +error: initializing a reference-counted pointer in `vec![elem; len]` + --> $DIR/weak.rs:12:13 + | +LL | let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each element will point to the same `Weak` instance +help: consider initializing each `Weak` element individually + | +LL ~ let v = { +LL + let mut v = Vec::with_capacity(2); +LL + (0..2).for_each(|_| v.push(Arc::downgrade(..))); +LL + v +LL ~ }; + | +help: or if this is intentional, consider extracting the `Weak` initialization to a variable + | +LL ~ let v = { +LL + let data = Arc::downgrade(..); +LL + vec![data; 2] +LL ~ }; + | + +error: initializing a reference-counted pointer in `vec![elem; len]` + --> $DIR/weak.rs:20:21 + | +LL | let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each element will point to the same `Weak` instance +help: consider initializing each `Weak` element individually + | +LL ~ let v = { +LL + let mut v = Vec::with_capacity(2); +LL + (0..2).for_each(|_| v.push(Arc::downgrade(..))); +LL + v +LL ~ }; + | +help: or if this is intentional, consider extracting the `Weak` initialization to a variable + | +LL ~ let v = { +LL + let data = Arc::downgrade(..); +LL + vec![data; 2] +LL ~ }; + | + +error: initializing a reference-counted pointer in `vec![elem; len]` + --> $DIR/weak.rs:21:22 + | +LL | let v2 = vec![Rc::downgrade(&Rc::new("x".to_string())); 2]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each element will point to the same `Weak` instance +help: consider initializing each `Weak` element individually + | +LL ~ let v2 = { +LL + let mut v = Vec::with_capacity(2); +LL + (0..2).for_each(|_| v.push(Rc::downgrade(..))); +LL + v +LL ~ }; + | +help: or if this is intentional, consider extracting the `Weak` initialization to a variable + | +LL ~ let v2 = { +LL + let data = Rc::downgrade(..); +LL + vec![data; 2] +LL ~ }; + | + +error: initializing a reference-counted pointer in `vec![elem; len]` + --> $DIR/weak.rs:27:13 + | +LL | let v = vec![ + | _____________^ +LL | | Arc::downgrade(&Arc::new(Mutex::new({ +LL | | let x = 1; +LL | | dbg!(x); +... | +LL | | 2 +LL | | ]; + | |_____^ + | + = note: each element will point to the same `Weak` instance +help: consider initializing each `Weak` element individually + | +LL ~ let v = { +LL + let mut v = Vec::with_capacity(2); +LL + (0..2).for_each(|_| v.push(Arc::downgrade(..))); +LL + v +LL ~ }; + | +help: or if this is intentional, consider extracting the `Weak` initialization to a variable + | +LL ~ let v = { +LL + let data = Arc::downgrade(..); +LL + vec![data; 2] +LL ~ }; + | + +error: initializing a reference-counted pointer in `vec![elem; len]` + --> $DIR/weak.rs:36:14 + | +LL | let v1 = vec![ + | ______________^ +LL | | Rc::downgrade(&Rc::new(Mutex::new({ +LL | | let x = 1; +LL | | dbg!(x); +... | +LL | | 2 +LL | | ]; + | |_____^ + | + = note: each element will point to the same `Weak` instance +help: consider initializing each `Weak` element individually + | +LL ~ let v1 = { +LL + let mut v = Vec::with_capacity(2); +LL + (0..2).for_each(|_| v.push(Rc::downgrade(..))); +LL + v +LL ~ }; + | +help: or if this is intentional, consider extracting the `Weak` initialization to a variable + | +LL ~ let v1 = { +LL + let data = Rc::downgrade(..); +LL + vec![data; 2] +LL ~ }; + | + +error: aborting due to 8 previous errors + diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index a394ef8f25c6..1fa9fc749a96 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -88,4 +88,11 @@ pub async fn foo2(_a: i32, _b: i64) { let _b = _a; } +fn ice_8748() { + let _ = [0; { + let x = 1; + if let Some(x) = Some(1) { x } else { 1 } + }]; +} + fn main() {} diff --git a/tests/ui/suspicious_operation_groupings.fixed b/tests/ui/suspicious_operation_groupings.fixed new file mode 100644 index 000000000000..ede8a39fed71 --- /dev/null +++ b/tests/ui/suspicious_operation_groupings.fixed @@ -0,0 +1,209 @@ +// run-rustfix +#![warn(clippy::suspicious_operation_groupings)] +#![allow(dead_code, unused_parens, clippy::eq_op)] + +struct Vec3 { + x: f64, + y: f64, + z: f64, +} + +impl Eq for Vec3 {} + +impl PartialEq for Vec3 { + fn eq(&self, other: &Self) -> bool { + // This should trigger the lint because `self.x` is compared to `other.y` + self.x == other.x && self.y == other.y && self.z == other.z + } +} + +struct S { + a: i32, + b: i32, + c: i32, + d: i32, +} + +fn buggy_ab_cmp(s1: &S, s2: &S) -> bool { + // There's no `s1.b` + s1.a < s2.a && s1.b < s2.b +} + +struct SaOnly { + a: i32, +} + +impl S { + fn a(&self) -> i32 { + 0 + } +} + +fn do_not_give_bad_suggestions_for_this_unusual_expr(s1: &S, s2: &SaOnly) -> bool { + // This is superficially similar to `buggy_ab_cmp`, but we should not suggest + // `s2.b` since that is invalid. + s1.a < s2.a && s1.a() < s1.b +} + +fn do_not_give_bad_suggestions_for_this_macro_expr(s1: &S, s2: &SaOnly) -> bool { + macro_rules! s1 { + () => { + S { + a: 1, + b: 1, + c: 1, + d: 1, + } + }; + } + + // This is superficially similar to `buggy_ab_cmp`, but we should not suggest + // `s2.b` since that is invalid. + s1.a < s2.a && s1!().a < s1.b +} + +fn do_not_give_bad_suggestions_for_this_incorrect_expr(s1: &S, s2: &SaOnly) -> bool { + // There's two `s1.b`, but we should not suggest `s2.b` since that is invalid + s1.a < s2.a && s1.b < s1.b +} + +fn permissable(s1: &S, s2: &S) -> bool { + // Something like this seems like it might actually be what is desired. + s1.a == s2.b +} + +fn non_boolean_operators(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + s1.a * s2.a + s1.b * s2.b + s1.c * s2.c + s1.d * s2.d +} + +fn odd_number_of_pairs(s1: &S, s2: &S) -> i32 { + // There's no `s2.b` + s1.a * s2.a + s1.b * s2.b + s1.c * s2.c +} + +fn not_caught_by_eq_op_middle_change_left(s1: &S, s2: &S) -> i32 { + // There's no `s1.b` + s1.a * s2.a + s1.b * s2.b + s1.c * s2.c +} + +fn not_caught_by_eq_op_middle_change_right(s1: &S, s2: &S) -> i32 { + // There's no `s2.b` + s1.a * s2.a + s1.b * s2.b + s1.c * s2.c +} + +fn not_caught_by_eq_op_start(s1: &S, s2: &S) -> i32 { + // There's no `s2.a` + s1.a * s2.a + s1.b * s2.b + s1.c * s2.c +} + +fn not_caught_by_eq_op_end(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + s1.a * s2.a + s1.b * s2.b + s1.c * s2.c +} + +fn the_cross_product_should_not_lint(s1: &S, s2: &S) -> (i32, i32, i32) { + ( + s1.b * s2.c - s1.c * s2.b, + s1.c * s2.a - s1.a * s2.c, + s1.a * s2.b - s1.b * s2.a, + ) +} + +fn outer_parens_simple(s1: &S, s2: &S) -> i32 { + // There's no `s2.b` + (s1.a * s2.a + s1.b * s2.b) +} + +fn outer_parens(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + (s1.a * s2.a + s1.b * s2.b + s1.c * s2.c + s1.d * s2.d) +} + +fn inner_parens(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.c) + (s1.d * s2.d) +} + +fn outer_and_some_inner_parens(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.c) + (s1.d * s2.d)) +} + +fn all_parens_balanced_tree(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.c) + (s1.d * s2.d))) +} + +fn all_parens_left_tree(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.c)) + (s1.d * s2.d)) +} + +fn all_parens_right_tree(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.c) + (s1.d * s2.d))) +} + +fn inside_other_binop_expression(s1: &S, s2: &S) -> i32 { + // There's no `s1.b` + (s1.a * s2.a + s1.b * s2.b) / 2 +} + +fn inside_function_call(s1: &S, s2: &S) -> i32 { + // There's no `s1.b` + i32::swap_bytes(s1.a * s2.a + s1.b * s2.b) +} + +fn inside_larger_boolean_expression(s1: &S, s2: &S) -> bool { + // There's no `s1.c` + s1.a > 0 && s1.b > 0 && s1.c == s2.c && s1.d == s2.d +} + +fn inside_larger_boolean_expression_with_unsorted_ops(s1: &S, s2: &S) -> bool { + // There's no `s1.c` + s1.a > 0 && s1.c == s2.c && s1.b > 0 && s1.d == s2.d +} + +struct Nested { + inner: ((i32,), (i32,), (i32,)), +} + +fn changed_middle_ident(n1: &Nested, n2: &Nested) -> bool { + // There's no `n2.inner.2.0` + (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0 +} + +// `eq_op` should catch this one. +fn changed_initial_ident(n1: &Nested, n2: &Nested) -> bool { + // There's no `n2.inner.0.0` + (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0 +} + +fn inside_fn_with_similar_expression(s1: &S, s2: &S, strict: bool) -> bool { + if strict { + s1.a < s2.a && s1.b < s2.b + } else { + // There's no `s1.b` in this subexpression + s1.a <= s2.a && s1.b <= s2.b + } +} + +fn inside_an_if_statement(s1: &mut S, s2: &S) { + // There's no `s1.b` + if s1.a < s2.a && s1.b < s2.b { + s1.c = s2.c; + } +} + +fn maximum_unary_minus_right_tree(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.c) + -(-s1.d * -s2.d))) +} + +fn unary_minus_and_an_if_expression(s1: &S, s2: &S) -> i32 { + // There's no `s1.b` + -(if -s1.a < -s2.a && -s1.b < -s2.b { s1.c } else { s2.a }) +} + +fn main() {} diff --git a/tests/ui/suspicious_operation_groupings.rs b/tests/ui/suspicious_operation_groupings.rs index 3201d5de0f35..26ce97bb37f8 100644 --- a/tests/ui/suspicious_operation_groupings.rs +++ b/tests/ui/suspicious_operation_groupings.rs @@ -1,5 +1,6 @@ +// run-rustfix #![warn(clippy::suspicious_operation_groupings)] -#![allow(clippy::eq_op)] +#![allow(dead_code, unused_parens, clippy::eq_op)] struct Vec3 { x: f64, diff --git a/tests/ui/suspicious_operation_groupings.stderr b/tests/ui/suspicious_operation_groupings.stderr index baf9bc74b000..29f229245fed 100644 --- a/tests/ui/suspicious_operation_groupings.stderr +++ b/tests/ui/suspicious_operation_groupings.stderr @@ -1,5 +1,5 @@ error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:15:9 + --> $DIR/suspicious_operation_groupings.rs:16:9 | LL | self.x == other.y && self.y == other.y && self.z == other.z | ^^^^^^^^^^^^^^^^^ help: did you mean: `self.x == other.x` @@ -7,151 +7,151 @@ LL | self.x == other.y && self.y == other.y && self.z == other.z = note: `-D clippy::suspicious-operation-groupings` implied by `-D warnings` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:28:20 + --> $DIR/suspicious_operation_groupings.rs:29:20 | LL | s1.a < s2.a && s1.a < s2.b | ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:76:33 + --> $DIR/suspicious_operation_groupings.rs:77:33 | LL | s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:81:19 + --> $DIR/suspicious_operation_groupings.rs:82:19 | LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:81:19 + --> $DIR/suspicious_operation_groupings.rs:82:19 | LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:86:19 + --> $DIR/suspicious_operation_groupings.rs:87:19 | LL | s1.a * s2.a + s2.b * s2.b + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:91:19 + --> $DIR/suspicious_operation_groupings.rs:92:19 | LL | s1.a * s2.a + s1.b * s1.b + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:96:5 + --> $DIR/suspicious_operation_groupings.rs:97:5 | LL | s1.a * s1.a + s1.b * s2.b + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.a * s2.a` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:101:33 + --> $DIR/suspicious_operation_groupings.rs:102:33 | LL | s1.a * s2.a + s1.b * s2.b + s1.c * s1.c | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:114:20 + --> $DIR/suspicious_operation_groupings.rs:115:20 | LL | (s1.a * s2.a + s1.b * s1.b) | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:119:34 + --> $DIR/suspicious_operation_groupings.rs:120:34 | LL | (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:124:38 + --> $DIR/suspicious_operation_groupings.rs:125:38 | LL | (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:129:39 + --> $DIR/suspicious_operation_groupings.rs:130:39 | LL | ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:134:42 + --> $DIR/suspicious_operation_groupings.rs:135:42 | LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:134:42 + --> $DIR/suspicious_operation_groupings.rs:135:42 | LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:139:40 + --> $DIR/suspicious_operation_groupings.rs:140:40 | LL | (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d)) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:144:40 + --> $DIR/suspicious_operation_groupings.rs:145:40 | LL | ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:149:20 + --> $DIR/suspicious_operation_groupings.rs:150:20 | LL | (s1.a * s2.a + s2.b * s2.b) / 2 | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:154:35 + --> $DIR/suspicious_operation_groupings.rs:155:35 | LL | i32::swap_bytes(s1.a * s2.a + s2.b * s2.b) | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:159:29 + --> $DIR/suspicious_operation_groupings.rs:160:29 | LL | s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d | ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:164:17 + --> $DIR/suspicious_operation_groupings.rs:165:17 | LL | s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d | ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:173:77 + --> $DIR/suspicious_operation_groupings.rs:174:77 | LL | (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `(n1.inner.2).0 == (n2.inner.2).0` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:187:25 + --> $DIR/suspicious_operation_groupings.rs:188:25 | LL | s1.a <= s2.a && s1.a <= s2.b | ^^^^^^^^^^^^ help: did you mean: `s1.b <= s2.b` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:193:23 + --> $DIR/suspicious_operation_groupings.rs:194:23 | LL | if s1.a < s2.a && s1.a < s2.b { | ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:200:48 + --> $DIR/suspicious_operation_groupings.rs:201:48 | LL | -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d))) | ^^^^^^^^^^^^^ help: did you mean: `-s1.c * -s2.c` error: this sequence of operators looks suspiciously like a bug - --> $DIR/suspicious_operation_groupings.rs:205:27 + --> $DIR/suspicious_operation_groupings.rs:206:27 | LL | -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a }) | ^^^^^^^^^^^^^ help: did you mean: `-s1.b < -s2.b` diff --git a/tests/ui/unicode.fixed b/tests/ui/unicode.fixed new file mode 100644 index 000000000000..328cda369e11 --- /dev/null +++ b/tests/ui/unicode.fixed @@ -0,0 +1,36 @@ +// run-rustfix +#[warn(clippy::invisible_characters)] +fn zero() { + print!("Here >\u{200B}< is a ZWS, and \u{200B}another"); + print!("This\u{200B}is\u{200B}fine"); + print!("Here >\u{AD}< is a SHY, and \u{AD}another"); + print!("This\u{ad}is\u{ad}fine"); + print!("Here >\u{2060}< is a WJ, and \u{2060}another"); + print!("This\u{2060}is\u{2060}fine"); +} + +#[warn(clippy::unicode_not_nfc)] +fn canon() { + print!("̀àh?"); + print!("a\u{0300}h?"); // also ok +} + +#[warn(clippy::non_ascii_literal)] +fn uni() { + print!("\u{dc}ben!"); + print!("\u{DC}ben!"); // this is ok +} + +// issue 8013 +#[warn(clippy::non_ascii_literal)] +fn single_quote() { + const _EMPTY_BLOCK: char = '\u{25b1}'; + const _FULL_BLOCK: char = '\u{25b0}'; +} + +fn main() { + zero(); + uni(); + canon(); + single_quote(); +} diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index e0a4eadce33b..7828d6bcbea7 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -1,3 +1,4 @@ +// run-rustfix #[warn(clippy::invisible_characters)] fn zero() { print!("Here >​< is a ZWS, and ​another"); diff --git a/tests/ui/unicode.stderr b/tests/ui/unicode.stderr index 3f54e3880e74..01d3f3c02967 100644 --- a/tests/ui/unicode.stderr +++ b/tests/ui/unicode.stderr @@ -1,5 +1,5 @@ error: invisible character detected - --> $DIR/unicode.rs:3:12 + --> $DIR/unicode.rs:4:12 | LL | print!("Here >​< is a ZWS, and ​another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{200B}< is a ZWS, and /u{200B}another"` @@ -7,19 +7,19 @@ LL | print!("Here >​< is a ZWS, and ​another"); = note: `-D clippy::invisible-characters` implied by `-D warnings` error: invisible character detected - --> $DIR/unicode.rs:5:12 + --> $DIR/unicode.rs:6:12 | LL | print!("Here >­< is a SHY, and ­another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{AD}< is a SHY, and /u{AD}another"` error: invisible character detected - --> $DIR/unicode.rs:7:12 + --> $DIR/unicode.rs:8:12 | LL | print!("Here >⁠< is a WJ, and ⁠another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{2060}< is a WJ, and /u{2060}another"` error: non-NFC Unicode sequence detected - --> $DIR/unicode.rs:13:12 + --> $DIR/unicode.rs:14:12 | LL | print!("̀àh?"); | ^^^^^ help: consider replacing the string with: `"̀àh?"` @@ -27,7 +27,7 @@ LL | print!("̀àh?"); = note: `-D clippy::unicode-not-nfc` implied by `-D warnings` error: literal non-ASCII character detected - --> $DIR/unicode.rs:19:12 + --> $DIR/unicode.rs:20:12 | LL | print!("Üben!"); | ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"` @@ -35,13 +35,13 @@ LL | print!("Üben!"); = note: `-D clippy::non-ascii-literal` implied by `-D warnings` error: literal non-ASCII character detected - --> $DIR/unicode.rs:26:32 + --> $DIR/unicode.rs:27:32 | LL | const _EMPTY_BLOCK: char = '▱'; | ^^^ help: consider replacing the string with: `'/u{25b1}'` error: literal non-ASCII character detected - --> $DIR/unicode.rs:27:31 + --> $DIR/unicode.rs:28:31 | LL | const _FULL_BLOCK: char = '▰'; | ^^^ help: consider replacing the string with: `'/u{25b0}'` diff --git a/tests/ui/unit_arg_empty_blocks.fixed b/tests/ui/unit_arg_empty_blocks.fixed new file mode 100644 index 000000000000..9400e93cac83 --- /dev/null +++ b/tests/ui/unit_arg_empty_blocks.fixed @@ -0,0 +1,30 @@ +// run-rustfix +#![warn(clippy::unit_arg)] +#![allow(clippy::no_effect, unused_must_use, unused_variables)] + +use std::fmt::Debug; + +fn foo(t: T) { + println!("{:?}", t); +} + +fn foo3(t1: T1, t2: T2, t3: T3) { + println!("{:?}, {:?}, {:?}", t1, t2, t3); +} + +fn bad() { + foo(()); + foo3((), 2, 2); + foo(0); + taking_two_units((), ()); + foo(0); + foo(1); + taking_three_units((), (), ()); +} + +fn taking_two_units(a: (), b: ()) {} +fn taking_three_units(a: (), b: (), c: ()) {} + +fn main() { + bad(); +} diff --git a/tests/ui/unit_arg_empty_blocks.rs b/tests/ui/unit_arg_empty_blocks.rs index 18a31eb3deee..5f52b6c5315f 100644 --- a/tests/ui/unit_arg_empty_blocks.rs +++ b/tests/ui/unit_arg_empty_blocks.rs @@ -1,3 +1,4 @@ +// run-rustfix #![warn(clippy::unit_arg)] #![allow(clippy::no_effect, unused_must_use, unused_variables)] diff --git a/tests/ui/unit_arg_empty_blocks.stderr b/tests/ui/unit_arg_empty_blocks.stderr index 39072c9a8cc0..d35e931697d2 100644 --- a/tests/ui/unit_arg_empty_blocks.stderr +++ b/tests/ui/unit_arg_empty_blocks.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg_empty_blocks.rs:15:5 + --> $DIR/unit_arg_empty_blocks.rs:16:5 | LL | foo({}); | ^^^^--^ @@ -9,7 +9,7 @@ LL | foo({}); = note: `-D clippy::unit-arg` implied by `-D warnings` error: passing a unit value to a function - --> $DIR/unit_arg_empty_blocks.rs:16:5 + --> $DIR/unit_arg_empty_blocks.rs:17:5 | LL | foo3({}, 2, 2); | ^^^^^--^^^^^^^ @@ -17,7 +17,7 @@ LL | foo3({}, 2, 2); | help: use a unit literal instead: `()` error: passing unit values to a function - --> $DIR/unit_arg_empty_blocks.rs:17:5 + --> $DIR/unit_arg_empty_blocks.rs:18:5 | LL | taking_two_units({}, foo(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL ~ taking_two_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg_empty_blocks.rs:18:5 + --> $DIR/unit_arg_empty_blocks.rs:19:5 | LL | taking_three_units({}, foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed new file mode 100644 index 000000000000..b352b285c862 --- /dev/null +++ b/tests/ui/unnecessary_cast.fixed @@ -0,0 +1,91 @@ +// run-rustfix +#![warn(clippy::unnecessary_cast)] +#![allow( + unused_must_use, + clippy::borrow_as_ptr, + clippy::no_effect, + clippy::nonstandard_macro_braces, + clippy::unnecessary_operation +)] + +#[rustfmt::skip] +fn main() { + // Test cast_unnecessary + 1_i32; + 1_f32; + false; + &1i32 as &i32; + + -1_i32; + - 1_i32; + -1_f32; + 1_i32; + 1_f32; + + // macro version + macro_rules! foo { + ($a:ident, $b:ident) => { + #[allow(unused)] + pub fn $a() -> $b { + 1 as $b + } + }; + } + foo!(a, i32); + foo!(b, f32); + foo!(c, f64); + + // do not lint cast to cfg-dependant type + 1 as std::os::raw::c_char; + + // do not lint cast to alias type + 1 as I32Alias; + &1 as &I32Alias; +} + +type I32Alias = i32; + +mod fixable { + #![allow(dead_code)] + + fn main() { + // casting integer literal to float is unnecessary + 100_f32; + 100_f64; + 100_f64; + let _ = -100_f32; + let _ = -100_f64; + let _ = -100_f64; + 100_f32; + 100_f64; + // Should not trigger + #[rustfmt::skip] + let v = vec!(1); + &v as &[i32]; + 0x10 as f32; + 0o10 as f32; + 0b10 as f32; + 0x11 as f64; + 0o11 as f64; + 0b11 as f64; + + 1_u32; + 0x10_i32; + 0b10_usize; + 0o73_u16; + 1_000_000_000_u32; + + 1.0_f64; + 0.5_f32; + + 1.0 as u16; + + let _ = -1_i32; + let _ = -1.0_f32; + + let _ = 1 as I32Alias; + let _ = &1 as &I32Alias; + } + + type I32Alias = i32; +} diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index 62c3e9636866..6c8cc3effe8f 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -1,5 +1,12 @@ +// run-rustfix #![warn(clippy::unnecessary_cast)] -#![allow(clippy::no_effect)] +#![allow( + unused_must_use, + clippy::borrow_as_ptr, + clippy::no_effect, + clippy::nonstandard_macro_braces, + clippy::unnecessary_operation +)] #[rustfmt::skip] fn main() { @@ -37,3 +44,48 @@ fn main() { } type I32Alias = i32; + +mod fixable { + #![allow(dead_code)] + + fn main() { + // casting integer literal to float is unnecessary + 100 as f32; + 100 as f64; + 100_i32 as f64; + let _ = -100 as f32; + let _ = -100 as f64; + let _ = -100_i32 as f64; + 100. as f32; + 100. as f64; + // Should not trigger + #[rustfmt::skip] + let v = vec!(1); + &v as &[i32]; + 0x10 as f32; + 0o10 as f32; + 0b10 as f32; + 0x11 as f64; + 0o11 as f64; + 0b11 as f64; + + 1 as u32; + 0x10 as i32; + 0b10 as usize; + 0o73 as u16; + 1_000_000_000 as u32; + + 1.0 as f64; + 0.5 as f32; + + 1.0 as u16; + + let _ = -1 as i32; + let _ = -1.0 as f32; + + let _ = 1 as I32Alias; + let _ = &1 as &I32Alias; + } + + type I32Alias = i32; +} diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr index a5a93c6110c6..bad45f0025b2 100644 --- a/tests/ui/unnecessary_cast.stderr +++ b/tests/ui/unnecessary_cast.stderr @@ -1,5 +1,5 @@ error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast.rs:7:5 + --> $DIR/unnecessary_cast.rs:14:5 | LL | 1i32 as i32; | ^^^^^^^^^^^ help: try: `1_i32` @@ -7,46 +7,148 @@ LL | 1i32 as i32; = note: `-D clippy::unnecessary-cast` implied by `-D warnings` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast.rs:8:5 + --> $DIR/unnecessary_cast.rs:15:5 | LL | 1f32 as f32; | ^^^^^^^^^^^ help: try: `1_f32` error: casting to the same type is unnecessary (`bool` -> `bool`) - --> $DIR/unnecessary_cast.rs:9:5 + --> $DIR/unnecessary_cast.rs:16:5 | LL | false as bool; | ^^^^^^^^^^^^^ help: try: `false` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast.rs:12:5 + --> $DIR/unnecessary_cast.rs:19:5 | LL | -1_i32 as i32; | ^^^^^^^^^^^^^ help: try: `-1_i32` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast.rs:13:5 + --> $DIR/unnecessary_cast.rs:20:5 | LL | - 1_i32 as i32; | ^^^^^^^^^^^^^^ help: try: `- 1_i32` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast.rs:14:5 + --> $DIR/unnecessary_cast.rs:21:5 | LL | -1f32 as f32; | ^^^^^^^^^^^^ help: try: `-1_f32` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast.rs:15:5 + --> $DIR/unnecessary_cast.rs:22:5 | LL | 1_i32 as i32; | ^^^^^^^^^^^^ help: try: `1_i32` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast.rs:16:5 + --> $DIR/unnecessary_cast.rs:23:5 | LL | 1_f32 as f32; | ^^^^^^^^^^^^ help: try: `1_f32` -error: aborting due to 8 previous errors +error: casting integer literal to `f32` is unnecessary + --> $DIR/unnecessary_cast.rs:53:9 + | +LL | 100 as f32; + | ^^^^^^^^^^ help: try: `100_f32` + +error: casting integer literal to `f64` is unnecessary + --> $DIR/unnecessary_cast.rs:54:9 + | +LL | 100 as f64; + | ^^^^^^^^^^ help: try: `100_f64` + +error: casting integer literal to `f64` is unnecessary + --> $DIR/unnecessary_cast.rs:55:9 + | +LL | 100_i32 as f64; + | ^^^^^^^^^^^^^^ help: try: `100_f64` + +error: casting integer literal to `f32` is unnecessary + --> $DIR/unnecessary_cast.rs:56:17 + | +LL | let _ = -100 as f32; + | ^^^^^^^^^^^ help: try: `-100_f32` + +error: casting integer literal to `f64` is unnecessary + --> $DIR/unnecessary_cast.rs:57:17 + | +LL | let _ = -100 as f64; + | ^^^^^^^^^^^ help: try: `-100_f64` + +error: casting integer literal to `f64` is unnecessary + --> $DIR/unnecessary_cast.rs:58:17 + | +LL | let _ = -100_i32 as f64; + | ^^^^^^^^^^^^^^^ help: try: `-100_f64` + +error: casting float literal to `f32` is unnecessary + --> $DIR/unnecessary_cast.rs:59:9 + | +LL | 100. as f32; + | ^^^^^^^^^^^ help: try: `100_f32` + +error: casting float literal to `f64` is unnecessary + --> $DIR/unnecessary_cast.rs:60:9 + | +LL | 100. as f64; + | ^^^^^^^^^^^ help: try: `100_f64` + +error: casting integer literal to `u32` is unnecessary + --> $DIR/unnecessary_cast.rs:72:9 + | +LL | 1 as u32; + | ^^^^^^^^ help: try: `1_u32` + +error: casting integer literal to `i32` is unnecessary + --> $DIR/unnecessary_cast.rs:73:9 + | +LL | 0x10 as i32; + | ^^^^^^^^^^^ help: try: `0x10_i32` + +error: casting integer literal to `usize` is unnecessary + --> $DIR/unnecessary_cast.rs:74:9 + | +LL | 0b10 as usize; + | ^^^^^^^^^^^^^ help: try: `0b10_usize` + +error: casting integer literal to `u16` is unnecessary + --> $DIR/unnecessary_cast.rs:75:9 + | +LL | 0o73 as u16; + | ^^^^^^^^^^^ help: try: `0o73_u16` + +error: casting integer literal to `u32` is unnecessary + --> $DIR/unnecessary_cast.rs:76:9 + | +LL | 1_000_000_000 as u32; + | ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32` + +error: casting float literal to `f64` is unnecessary + --> $DIR/unnecessary_cast.rs:78:9 + | +LL | 1.0 as f64; + | ^^^^^^^^^^ help: try: `1.0_f64` + +error: casting float literal to `f32` is unnecessary + --> $DIR/unnecessary_cast.rs:79:9 + | +LL | 0.5 as f32; + | ^^^^^^^^^^ help: try: `0.5_f32` + +error: casting integer literal to `i32` is unnecessary + --> $DIR/unnecessary_cast.rs:83:17 + | +LL | let _ = -1 as i32; + | ^^^^^^^^^ help: try: `-1_i32` + +error: casting float literal to `f32` is unnecessary + --> $DIR/unnecessary_cast.rs:84:17 + | +LL | let _ = -1.0 as f32; + | ^^^^^^^^^^^ help: try: `-1.0_f32` + +error: aborting due to 25 previous errors diff --git a/tests/ui/unnecessary_cast_fixable.fixed b/tests/ui/unnecessary_cast_fixable.fixed deleted file mode 100644 index 36800c5340db..000000000000 --- a/tests/ui/unnecessary_cast_fixable.fixed +++ /dev/null @@ -1,50 +0,0 @@ -// run-rustfix - -#![warn(clippy::unnecessary_cast)] -#![allow( - clippy::no_effect, - clippy::unnecessary_operation, - clippy::nonstandard_macro_braces, - clippy::borrow_as_ptr -)] - -fn main() { - // casting integer literal to float is unnecessary - 100_f32; - 100_f64; - 100_f64; - let _ = -100_f32; - let _ = -100_f64; - let _ = -100_f64; - 100_f32; - 100_f64; - // Should not trigger - #[rustfmt::skip] - let v = vec!(1); - &v as &[i32]; - 0x10 as f32; - 0o10 as f32; - 0b10 as f32; - 0x11 as f64; - 0o11 as f64; - 0b11 as f64; - - 1_u32; - 0x10_i32; - 0b10_usize; - 0o73_u16; - 1_000_000_000_u32; - - 1.0_f64; - 0.5_f32; - - 1.0 as u16; - - let _ = -1_i32; - let _ = -1.0_f32; - - let _ = 1 as I32Alias; - let _ = &1 as &I32Alias; -} - -type I32Alias = i32; diff --git a/tests/ui/unnecessary_cast_fixable.rs b/tests/ui/unnecessary_cast_fixable.rs deleted file mode 100644 index d4b6bb952ab3..000000000000 --- a/tests/ui/unnecessary_cast_fixable.rs +++ /dev/null @@ -1,50 +0,0 @@ -// run-rustfix - -#![warn(clippy::unnecessary_cast)] -#![allow( - clippy::no_effect, - clippy::unnecessary_operation, - clippy::nonstandard_macro_braces, - clippy::borrow_as_ptr -)] - -fn main() { - // casting integer literal to float is unnecessary - 100 as f32; - 100 as f64; - 100_i32 as f64; - let _ = -100 as f32; - let _ = -100 as f64; - let _ = -100_i32 as f64; - 100. as f32; - 100. as f64; - // Should not trigger - #[rustfmt::skip] - let v = vec!(1); - &v as &[i32]; - 0x10 as f32; - 0o10 as f32; - 0b10 as f32; - 0x11 as f64; - 0o11 as f64; - 0b11 as f64; - - 1 as u32; - 0x10 as i32; - 0b10 as usize; - 0o73 as u16; - 1_000_000_000 as u32; - - 1.0 as f64; - 0.5 as f32; - - 1.0 as u16; - - let _ = -1 as i32; - let _ = -1.0 as f32; - - let _ = 1 as I32Alias; - let _ = &1 as &I32Alias; -} - -type I32Alias = i32; diff --git a/tests/ui/unnecessary_cast_fixable.stderr b/tests/ui/unnecessary_cast_fixable.stderr deleted file mode 100644 index a281143281b5..000000000000 --- a/tests/ui/unnecessary_cast_fixable.stderr +++ /dev/null @@ -1,106 +0,0 @@ -error: casting integer literal to `f32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:13:5 - | -LL | 100 as f32; - | ^^^^^^^^^^ help: try: `100_f32` - | - = note: `-D clippy::unnecessary-cast` implied by `-D warnings` - -error: casting integer literal to `f64` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:14:5 - | -LL | 100 as f64; - | ^^^^^^^^^^ help: try: `100_f64` - -error: casting integer literal to `f64` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:15:5 - | -LL | 100_i32 as f64; - | ^^^^^^^^^^^^^^ help: try: `100_f64` - -error: casting integer literal to `f32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:16:13 - | -LL | let _ = -100 as f32; - | ^^^^^^^^^^^ help: try: `-100_f32` - -error: casting integer literal to `f64` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:17:13 - | -LL | let _ = -100 as f64; - | ^^^^^^^^^^^ help: try: `-100_f64` - -error: casting integer literal to `f64` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:18:13 - | -LL | let _ = -100_i32 as f64; - | ^^^^^^^^^^^^^^^ help: try: `-100_f64` - -error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:19:5 - | -LL | 100. as f32; - | ^^^^^^^^^^^ help: try: `100_f32` - -error: casting float literal to `f64` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:20:5 - | -LL | 100. as f64; - | ^^^^^^^^^^^ help: try: `100_f64` - -error: casting integer literal to `u32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:32:5 - | -LL | 1 as u32; - | ^^^^^^^^ help: try: `1_u32` - -error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:33:5 - | -LL | 0x10 as i32; - | ^^^^^^^^^^^ help: try: `0x10_i32` - -error: casting integer literal to `usize` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:34:5 - | -LL | 0b10 as usize; - | ^^^^^^^^^^^^^ help: try: `0b10_usize` - -error: casting integer literal to `u16` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:35:5 - | -LL | 0o73 as u16; - | ^^^^^^^^^^^ help: try: `0o73_u16` - -error: casting integer literal to `u32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:36:5 - | -LL | 1_000_000_000 as u32; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32` - -error: casting float literal to `f64` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:38:5 - | -LL | 1.0 as f64; - | ^^^^^^^^^^ help: try: `1.0_f64` - -error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:39:5 - | -LL | 0.5 as f32; - | ^^^^^^^^^^ help: try: `0.5_f32` - -error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:43:13 - | -LL | let _ = -1 as i32; - | ^^^^^^^^^ help: try: `-1_i32` - -error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:44:13 - | -LL | let _ = -1.0 as f32; - | ^^^^^^^^^^^ help: try: `-1.0_f32` - -error: aborting due to 17 previous errors - diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index 3e62ffe74fed..4f80aaecc902 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -542,3 +542,69 @@ mod use_self_in_pat { } } } + +mod issue8845 { + pub enum Something { + Num(u8), + TupleNums(u8, u8), + StructNums { one: u8, two: u8 }, + } + + struct Foo(u8); + + struct Bar { + x: u8, + y: usize, + } + + impl Something { + fn get_value(&self) -> u8 { + match self { + Self::Num(n) => *n, + Self::TupleNums(n, _m) => *n, + Self::StructNums { one, two: _ } => *one, + } + } + + fn use_crate(&self) -> u8 { + match self { + Self::Num(n) => *n, + Self::TupleNums(n, _m) => *n, + Self::StructNums { one, two: _ } => *one, + } + } + + fn imported_values(&self) -> u8 { + use Something::*; + match self { + Num(n) => *n, + TupleNums(n, _m) => *n, + StructNums { one, two: _ } => *one, + } + } + } + + impl Foo { + fn get_value(&self) -> u8 { + let Self(x) = self; + *x + } + + fn use_crate(&self) -> u8 { + let Self(x) = self; + *x + } + } + + impl Bar { + fn get_value(&self) -> u8 { + let Self { x, .. } = self; + *x + } + + fn use_crate(&self) -> u8 { + let Self { x, .. } = self; + *x + } + } +} diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index da2faddee12a..52da72db53ce 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -542,3 +542,69 @@ mod use_self_in_pat { } } } + +mod issue8845 { + pub enum Something { + Num(u8), + TupleNums(u8, u8), + StructNums { one: u8, two: u8 }, + } + + struct Foo(u8); + + struct Bar { + x: u8, + y: usize, + } + + impl Something { + fn get_value(&self) -> u8 { + match self { + Something::Num(n) => *n, + Something::TupleNums(n, _m) => *n, + Something::StructNums { one, two: _ } => *one, + } + } + + fn use_crate(&self) -> u8 { + match self { + crate::issue8845::Something::Num(n) => *n, + crate::issue8845::Something::TupleNums(n, _m) => *n, + crate::issue8845::Something::StructNums { one, two: _ } => *one, + } + } + + fn imported_values(&self) -> u8 { + use Something::*; + match self { + Num(n) => *n, + TupleNums(n, _m) => *n, + StructNums { one, two: _ } => *one, + } + } + } + + impl Foo { + fn get_value(&self) -> u8 { + let Foo(x) = self; + *x + } + + fn use_crate(&self) -> u8 { + let crate::issue8845::Foo(x) = self; + *x + } + } + + impl Bar { + fn get_value(&self) -> u8 { + let Bar { x, .. } = self; + *x + } + + fn use_crate(&self) -> u8 { + let crate::issue8845::Bar { x, .. } = self; + *x + } + } +} diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr index 34d98618253a..f06bb959b3bd 100644 --- a/tests/ui/use_self.stderr +++ b/tests/ui/use_self.stderr @@ -186,5 +186,65 @@ error: unnecessary structure name repetition LL | if let Foo::Bar = self { | ^^^ help: use the applicable keyword: `Self` -error: aborting due to 31 previous errors +error: unnecessary structure name repetition + --> $DIR/use_self.rs:563:17 + | +LL | Something::Num(n) => *n, + | ^^^^^^^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:564:17 + | +LL | Something::TupleNums(n, _m) => *n, + | ^^^^^^^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:565:17 + | +LL | Something::StructNums { one, two: _ } => *one, + | ^^^^^^^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:571:17 + | +LL | crate::issue8845::Something::Num(n) => *n, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:572:17 + | +LL | crate::issue8845::Something::TupleNums(n, _m) => *n, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:573:17 + | +LL | crate::issue8845::Something::StructNums { one, two: _ } => *one, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:589:17 + | +LL | let Foo(x) = self; + | ^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:594:17 + | +LL | let crate::issue8845::Foo(x) = self; + | ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:601:17 + | +LL | let Bar { x, .. } = self; + | ^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:606:17 + | +LL | let crate::issue8845::Bar { x, .. } = self; + | ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` + +error: aborting due to 41 previous errors