diff --git a/CHANGELOG.md b/CHANGELOG.md index bfe896d5efaf..f09af0466c01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1616,6 +1616,7 @@ Released 2018-09-13 [`mutex_atomic`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_atomic [`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer [`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount +[`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type [`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference @@ -1687,6 +1688,7 @@ Released 2018-09-13 [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition +[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dfc5cc077c37..5f7b1e85ee9a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,11 +28,14 @@ All contributors are expected to follow the [Rust Code of Conduct]. ## Getting started -High level approach: +**Note: If this is your first time contributing to Clippy, you should +first read the [Basics docs](doc/basics.md).** + +### High level approach 1. Find something to fix/improve 2. Change code (likely some file in `clippy_lints/src/`) -3. Follow the instructions in the [Basics docs](doc/basics.md) such as running the `setup-toolchain.sh` script +3. Follow the instructions in the [Basics docs](doc/basics.md) to get set up 4. Run `cargo test` in the root directory and wiggle code until it passes 5. Open a PR (also can be done after 2. if you run into problems) diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 08d8100a8854..80a067589824 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,7 +1,7 @@ use crate::utils::paths; use crate::utils::{ - get_trait_def_id, is_automatically_derived, is_copy, match_path, span_lint_and_help, span_lint_and_note, - span_lint_and_then, + get_trait_def_id, is_allowed, is_automatically_derived, is_copy, match_path, span_lint_and_help, + span_lint_and_note, span_lint_and_then, }; use if_chain::if_chain; use rustc_hir::def_id::DefId; @@ -354,7 +354,9 @@ fn check_unsafe_derive_deserialize<'tcx>( if_chain! { if match_path(&trait_ref.path, &paths::SERDE_DESERIALIZE); if let ty::Adt(def, _) = ty.kind; - if def.did.is_local(); + if let Some(local_def_id) = def.did.as_local(); + let adt_hir_id = cx.tcx.hir().as_local_hir_id(local_def_id); + if !is_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id); if cx.tcx.inherent_impls(def.did) .iter() .map(|imp_did| item_from_def_id(cx, *imp_did)) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 81864340f1a5..b26e10a464c5 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -250,6 +250,7 @@ mod mut_mut; mod mut_reference; mod mutable_debug_assertion; mod mutex_atomic; +mod needless_arbitrary_self_type; mod needless_bool; mod needless_borrow; mod needless_borrowed_ref; @@ -608,6 +609,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &loops::NEEDLESS_COLLECT, &loops::NEEDLESS_RANGE_LOOP, &loops::NEVER_LOOP, + &loops::SAME_ITEM_PUSH, &loops::WHILE_IMMUTABLE_CONDITION, &loops::WHILE_LET_LOOP, &loops::WHILE_LET_ON_ITERATOR, @@ -717,6 +719,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, &mutex_atomic::MUTEX_ATOMIC, &mutex_atomic::MUTEX_INTEGER, + &needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE, &needless_bool::BOOL_COMPARISON, &needless_bool::NEEDLESS_BOOL, &needless_borrow::NEEDLESS_BORROW, @@ -1027,6 +1030,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box items_after_statements::ItemsAfterStatements); store.register_early_pass(|| box precedence::Precedence); store.register_early_pass(|| box needless_continue::NeedlessContinue); + store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType); store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes); store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata); store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions); @@ -1295,6 +1299,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::NEEDLESS_COLLECT), LintId::of(&loops::NEEDLESS_RANGE_LOOP), LintId::of(&loops::NEVER_LOOP), + LintId::of(&loops::SAME_ITEM_PUSH), LintId::of(&loops::WHILE_IMMUTABLE_CONDITION), LintId::of(&loops::WHILE_LET_LOOP), LintId::of(&loops::WHILE_LET_ON_ITERATOR), @@ -1371,6 +1376,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mut_key::MUTABLE_KEY_TYPE), LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(&mutex_atomic::MUTEX_ATOMIC), + LintId::of(&needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), LintId::of(&needless_bool::BOOL_COMPARISON), LintId::of(&needless_bool::NEEDLESS_BOOL), LintId::of(&needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), @@ -1497,6 +1503,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::EMPTY_LOOP), LintId::of(&loops::FOR_KV_MAP), LintId::of(&loops::NEEDLESS_RANGE_LOOP), + LintId::of(&loops::SAME_ITEM_PUSH), LintId::of(&loops::WHILE_LET_ON_ITERATOR), LintId::of(&main_recursion::MAIN_RECURSION), LintId::of(&manual_async_fn::MANUAL_ASYNC_FN), @@ -1602,6 +1609,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&misc::SHORT_CIRCUIT_STATEMENT), LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN), LintId::of(&misc_early::ZERO_PREFIXED_LITERAL), + LintId::of(&needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), LintId::of(&needless_bool::BOOL_COMPARISON), LintId::of(&needless_bool::NEEDLESS_BOOL), LintId::of(&needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 1729fea7bc87..8352a8a3d2c6 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -5,8 +5,9 @@ use crate::utils::usage::{is_unused, mutated_variables}; use crate::utils::{ get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment, match_trait_method, - match_type, match_var, multispan_sugg, qpath_res, snippet, snippet_opt, snippet_with_applicability, span_lint, - span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq, + match_type, match_var, multispan_sugg, qpath_res, snippet, snippet_opt, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, + SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast; @@ -419,6 +420,39 @@ declare_clippy_lint! { "variables used within while expression are not mutated in the body" } +declare_clippy_lint! { + /// **What it does:** Checks whether a for loop is being used to push a constant + /// value into a Vec. + /// + /// **Why is this bad?** This kind of operation can be expressed more succinctly with + /// `vec![item;SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also + /// have better performance. + /// **Known problems:** None + /// + /// **Example:** + /// ```rust + /// let item1 = 2; + /// let item2 = 3; + /// let mut vec: Vec = Vec::new(); + /// for _ in 0..20 { + /// vec.push(item1); + /// } + /// for _ in 0..30 { + /// vec.push(item2); + /// } + /// ``` + /// could be written as + /// ```rust + /// let item1 = 2; + /// let item2 = 3; + /// let mut vec: Vec = vec![item1; 20]; + /// vec.resize(20 + 30, item2); + /// ``` + pub SAME_ITEM_PUSH, + style, + "the same item is pushed inside of a for loop" +} + declare_lint_pass!(Loops => [ MANUAL_MEMCPY, NEEDLESS_RANGE_LOOP, @@ -435,6 +469,7 @@ declare_lint_pass!(Loops => [ NEVER_LOOP, MUT_RANGE_BOUND, WHILE_IMMUTABLE_CONDITION, + SAME_ITEM_PUSH, ]); impl<'tcx> LateLintPass<'tcx> for Loops { @@ -740,6 +775,7 @@ fn check_for_loop<'tcx>( check_for_loop_over_map_kv(cx, pat, arg, body, expr); check_for_mut_range_bound(cx, arg, body); detect_manual_memcpy(cx, pat, arg, body, expr); + detect_same_item_push(cx, pat, arg, body, expr); } fn same_var<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, var: HirId) -> bool { @@ -1016,6 +1052,117 @@ fn detect_manual_memcpy<'tcx>( } } +// Scans the body of the for loop and determines whether lint should be given +struct SameItemPushVisitor<'a, 'tcx> { + should_lint: bool, + // this field holds the last vec push operation visited, which should be the only push seen + vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>, + cx: &'a LateContext<'tcx>, +} + +impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + match &expr.kind { + // Non-determinism may occur ... don't give a lint + ExprKind::Loop(_, _, _) | ExprKind::Match(_, _, _) => self.should_lint = false, + ExprKind::Block(block, _) => self.visit_block(block), + _ => {}, + } + } + + fn visit_block(&mut self, b: &'tcx Block<'_>) { + for stmt in b.stmts.iter() { + self.visit_stmt(stmt); + } + } + + fn visit_stmt(&mut self, s: &'tcx Stmt<'_>) { + let vec_push_option = get_vec_push(self.cx, s); + if vec_push_option.is_none() { + // Current statement is not a push so visit inside + match &s.kind { + StmtKind::Expr(expr) | StmtKind::Semi(expr) => self.visit_expr(&expr), + _ => {}, + } + } else { + // Current statement is a push ...check whether another + // push had been previously done + if self.vec_push.is_none() { + self.vec_push = vec_push_option; + } else { + // There are multiple pushes ... don't lint + self.should_lint = false; + } + } + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } +} + +// Given some statement, determine if that statement is a push on a Vec. If it is, return +// the Vec being pushed into and the item being pushed +fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { + if_chain! { + // Extract method being called + if let StmtKind::Semi(semi_stmt) = &stmt.kind; + if let ExprKind::MethodCall(path, _, args, _) = &semi_stmt.kind; + // Figure out the parameters for the method call + if let Some(self_expr) = args.get(0); + if let Some(pushed_item) = args.get(1); + // Check that the method being called is push() on a Vec + if match_type(cx, cx.typeck_results().expr_ty(self_expr), &paths::VEC); + if path.ident.name.as_str() == "push"; + then { + return Some((self_expr, pushed_item)) + } + } + None +} + +/// Detects for loop pushing the same item into a Vec +fn detect_same_item_push<'tcx>( + cx: &LateContext<'tcx>, + pat: &'tcx Pat<'_>, + _: &'tcx Expr<'_>, + body: &'tcx Expr<'_>, + _: &'tcx Expr<'_>, +) { + // Determine whether it is safe to lint the body + let mut same_item_push_visitor = SameItemPushVisitor { + should_lint: true, + vec_push: None, + cx, + }; + walk_expr(&mut same_item_push_visitor, body); + if same_item_push_visitor.should_lint { + if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push { + // Make sure that the push does not involve possibly mutating values + if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) { + if let PatKind::Wild = pat.kind { + let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); + let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); + + span_lint_and_help( + cx, + SAME_ITEM_PUSH, + vec.span, + "it looks like the same item is being pushed into this Vec", + None, + &format!( + "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", + item_str, vec_str, item_str + ), + ) + } + } + } + } +} + /// Checks for looping over a range and then indexing a sequence with it. /// The iteratee must be a range literal. #[allow(clippy::too_many_lines)] diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index dae39aaf5e21..004dd50a31be 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,5 +1,6 @@ use crate::consts::{constant_simple, Constant}; -use crate::utils::{match_def_path, paths, span_lint}; +use crate::utils::{match_def_path, match_trait_method, paths, span_lint}; +use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -18,6 +19,10 @@ declare_clippy_lint! { /// ```ignore /// min(0, max(100, x)) /// ``` + /// or + /// ```ignore + /// x.max(100).min(0) + /// ``` /// It will always be equal to `0`. Probably the author meant to clamp the value /// between 0 and 100, but has erroneously swapped `min` and `max`. pub MIN_MAX, @@ -60,25 +65,43 @@ enum MinMax { } fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant, &'a Expr<'a>)> { - if let ExprKind::Call(ref path, ref args) = expr.kind { - if let ExprKind::Path(ref qpath) = path.kind { - cx.typeck_results() - .qpath_res(qpath, path.hir_id) - .opt_def_id() - .and_then(|def_id| { - if match_def_path(cx, def_id, &paths::CMP_MIN) { - fetch_const(cx, args, MinMax::Min) - } else if match_def_path(cx, def_id, &paths::CMP_MAX) { + match expr.kind { + ExprKind::Call(ref path, ref args) => { + if let ExprKind::Path(ref qpath) = path.kind { + cx.typeck_results() + .qpath_res(qpath, path.hir_id) + .opt_def_id() + .and_then(|def_id| { + if match_def_path(cx, def_id, &paths::CMP_MIN) { + fetch_const(cx, args, MinMax::Min) + } else if match_def_path(cx, def_id, &paths::CMP_MAX) { + fetch_const(cx, args, MinMax::Max) + } else { + None + } + }) + } else { + None + } + }, + ExprKind::MethodCall(ref path, _, ref args, _) => { + if_chain! { + if let [obj, _] = args; + if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD); + then { + if path.ident.as_str() == sym!(max).as_str() { fetch_const(cx, args, MinMax::Max) + } else if path.ident.as_str() == sym!(min).as_str() { + fetch_const(cx, args, MinMax::Min) } else { None } - }) - } else { - None - } - } else { - None + } else { + None + } + } + }, + _ => None, } } diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs new file mode 100644 index 000000000000..38bdd0f7ed23 --- /dev/null +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -0,0 +1,118 @@ +use crate::utils::span_lint_and_sugg; +use if_chain::if_chain; +use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::kw; +use rustc_span::Span; + +declare_clippy_lint! { + /// **What it does:** The lint checks for `self` in fn parameters that + /// specify the `Self`-type explicitly + /// **Why is this bad?** Increases the amount and decreases the readability of code + /// + /// **Known problems:** None + /// + /// **Example:** + /// ```rust + /// enum ValType { + /// I32, + /// I64, + /// F32, + /// F64, + /// } + /// + /// impl ValType { + /// pub fn bytes(self: Self) -> usize { + /// match self { + /// Self::I32 | Self::F32 => 4, + /// Self::I64 | Self::F64 => 8, + /// } + /// } + /// } + /// ``` + /// + /// Could be rewritten as + /// + /// ```rust + /// enum ValType { + /// I32, + /// I64, + /// F32, + /// F64, + /// } + /// + /// impl ValType { + /// pub fn bytes(self) -> usize { + /// match self { + /// Self::I32 | Self::F32 => 4, + /// Self::I64 | Self::F64 => 8, + /// } + /// } + /// } + /// ``` + pub NEEDLESS_ARBITRARY_SELF_TYPE, + complexity, + "type of `self` parameter is already by default `Self`" +} + +declare_lint_pass!(NeedlessArbitrarySelfType => [NEEDLESS_ARBITRARY_SELF_TYPE]); + +enum Mode { + Ref(Option), + Value, +} + +fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mode: &Mode, mutbl: Mutability) { + if_chain! { + if let [segment] = &path.segments[..]; + if segment.ident.name == kw::SelfUpper; + then { + let self_param = match (binding_mode, mutbl) { + (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(), + (Mode::Ref(Some(lifetime)), Mutability::Mut) => format!("&{} mut self", &lifetime.ident.name), + (Mode::Ref(None), Mutability::Not) => "&self".to_string(), + (Mode::Ref(Some(lifetime)), Mutability::Not) => format!("&{} self", &lifetime.ident.name), + (Mode::Value, Mutability::Mut) => "mut self".to_string(), + (Mode::Value, Mutability::Not) => "self".to_string(), + }; + + span_lint_and_sugg( + cx, + NEEDLESS_ARBITRARY_SELF_TYPE, + span, + "the type of the `self` parameter does not need to be arbitrary", + "consider to change this parameter to", + self_param, + Applicability::MachineApplicable, + ) + } + } +} + +impl EarlyLintPass for NeedlessArbitrarySelfType { + fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) { + if !p.is_self() { + return; + } + + match &p.ty.kind { + TyKind::Path(None, path) => { + if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind { + check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl) + } + }, + TyKind::Rptr(lifetime, mut_ty) => { + if_chain! { + if let TyKind::Path(None, path) = &mut_ty.ty.kind; + if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind; + then { + check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl) + } + } + }, + _ => {}, + } + } +} diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 06631f89f27d..d4acf8df46d8 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -50,7 +50,7 @@ declare_clippy_lint! { /// fn func(arg: T) {} /// ``` /// or - /// /// + /// /// ```rust /// fn func(arg: T) where T: Clone + Default {} /// ``` diff --git a/doc/basics.md b/doc/basics.md index 5c07d9b98a5a..c81e7f6e0692 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -53,6 +53,9 @@ rustup-toolchain-install-master -f -n master -c rustc-dev -c llvm-tools rustup override set master ``` +_Note:_ Sometimes you may get compiler errors when building Clippy, even if you +didn't change anything. Normally those will be fixed by a maintainer in a few hours. + ## Building and Testing Once the `master` toolchain is installed, you can build and test Clippy like diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index b64c6e544095..6395b571504c 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1459,6 +1459,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "bytecount", }, + Lint { + name: "needless_arbitrary_self_type", + group: "complexity", + desc: "type of `self` parameter is already by default `Self`", + deprecation: None, + module: "needless_arbitrary_self_type", + }, Lint { name: "needless_bool", group: "complexity", @@ -1935,6 +1942,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "copies", }, + Lint { + name: "same_item_push", + group: "style", + desc: "the same item is pushed inside of a for loop", + deprecation: None, + module: "loops", + }, Lint { name: "search_is_some", group: "complexity", diff --git a/tests/ui/extra_unused_lifetimes.rs b/tests/ui/extra_unused_lifetimes.rs index ddbf4e98c51a..150acfbfee75 100644 --- a/tests/ui/extra_unused_lifetimes.rs +++ b/tests/ui/extra_unused_lifetimes.rs @@ -1,4 +1,10 @@ -#![allow(unused, dead_code, clippy::needless_lifetimes, clippy::needless_pass_by_value)] +#![allow( + unused, + dead_code, + clippy::needless_lifetimes, + clippy::needless_pass_by_value, + clippy::needless_arbitrary_self_type +)] #![warn(clippy::extra_unused_lifetimes)] fn empty() {} diff --git a/tests/ui/extra_unused_lifetimes.stderr b/tests/ui/extra_unused_lifetimes.stderr index 16bbb1c037d8..ebdb8e749520 100644 --- a/tests/ui/extra_unused_lifetimes.stderr +++ b/tests/ui/extra_unused_lifetimes.stderr @@ -1,5 +1,5 @@ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:8:14 + --> $DIR/extra_unused_lifetimes.rs:14:14 | LL | fn unused_lt<'a>(x: u8) {} | ^^ @@ -7,19 +7,19 @@ LL | fn unused_lt<'a>(x: u8) {} = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings` error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:10:25 + --> $DIR/extra_unused_lifetimes.rs:16:25 | LL | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) { | ^^ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:35:10 + --> $DIR/extra_unused_lifetimes.rs:41:10 | LL | fn x<'a>(&self) {} | ^^ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:61:22 + --> $DIR/extra_unused_lifetimes.rs:67:22 | LL | fn unused_lt<'a>(x: u8) {} | ^^ diff --git a/tests/ui/len_without_is_empty.rs b/tests/ui/len_without_is_empty.rs index 3ef29dd63880..b5211318a150 100644 --- a/tests/ui/len_without_is_empty.rs +++ b/tests/ui/len_without_is_empty.rs @@ -4,14 +4,14 @@ pub struct PubOne; impl PubOne { - pub fn len(self: &Self) -> isize { + pub fn len(&self) -> isize { 1 } } impl PubOne { // A second impl for this struct -- the error span shouldn't mention this. - pub fn irrelevant(self: &Self) -> bool { + pub fn irrelevant(&self) -> bool { false } } @@ -21,7 +21,7 @@ pub struct PubAllowed; #[allow(clippy::len_without_is_empty)] impl PubAllowed { - pub fn len(self: &Self) -> isize { + pub fn len(&self) -> isize { 1 } } @@ -29,17 +29,17 @@ impl PubAllowed { // No `allow` attribute on this impl block, but that doesn't matter -- we only require one on the // impl containing `len`. impl PubAllowed { - pub fn irrelevant(self: &Self) -> bool { + pub fn irrelevant(&self) -> bool { false } } pub trait PubTraitsToo { - fn len(self: &Self) -> isize; + fn len(&self) -> isize; } impl PubTraitsToo for One { - fn len(self: &Self) -> isize { + fn len(&self) -> isize { 0 } } @@ -47,11 +47,11 @@ impl PubTraitsToo for One { pub struct HasIsEmpty; impl HasIsEmpty { - pub fn len(self: &Self) -> isize { + pub fn len(&self) -> isize { 1 } - fn is_empty(self: &Self) -> bool { + fn is_empty(&self) -> bool { false } } @@ -59,11 +59,11 @@ impl HasIsEmpty { pub struct HasWrongIsEmpty; impl HasWrongIsEmpty { - pub fn len(self: &Self) -> isize { + pub fn len(&self) -> isize { 1 } - pub fn is_empty(self: &Self, x: u32) -> bool { + pub fn is_empty(&self, x: u32) -> bool { false } } @@ -71,7 +71,7 @@ impl HasWrongIsEmpty { struct NotPubOne; impl NotPubOne { - pub fn len(self: &Self) -> isize { + pub fn len(&self) -> isize { // No error; `len` is pub but `NotPubOne` is not exported anyway. 1 } @@ -80,19 +80,19 @@ impl NotPubOne { struct One; impl One { - fn len(self: &Self) -> isize { + fn len(&self) -> isize { // No error; `len` is private; see issue #1085. 1 } } trait TraitsToo { - fn len(self: &Self) -> isize; + fn len(&self) -> isize; // No error; `len` is private; see issue #1085. } impl TraitsToo for One { - fn len(self: &Self) -> isize { + fn len(&self) -> isize { 0 } } @@ -100,11 +100,11 @@ impl TraitsToo for One { struct HasPrivateIsEmpty; impl HasPrivateIsEmpty { - pub fn len(self: &Self) -> isize { + pub fn len(&self) -> isize { 1 } - fn is_empty(self: &Self) -> bool { + fn is_empty(&self) -> bool { false } } @@ -112,16 +112,16 @@ impl HasPrivateIsEmpty { struct Wither; pub trait WithIsEmpty { - fn len(self: &Self) -> isize; - fn is_empty(self: &Self) -> bool; + fn len(&self) -> isize; + fn is_empty(&self) -> bool; } impl WithIsEmpty for Wither { - fn len(self: &Self) -> isize { + fn len(&self) -> isize { 1 } - fn is_empty(self: &Self) -> bool { + fn is_empty(&self) -> bool { false } } diff --git a/tests/ui/len_without_is_empty.stderr b/tests/ui/len_without_is_empty.stderr index 4493b17a4b4e..d79c300c0744 100644 --- a/tests/ui/len_without_is_empty.stderr +++ b/tests/ui/len_without_is_empty.stderr @@ -2,7 +2,7 @@ error: item `PubOne` has a public `len` method but no corresponding `is_empty` m --> $DIR/len_without_is_empty.rs:6:1 | LL | / impl PubOne { -LL | | pub fn len(self: &Self) -> isize { +LL | | pub fn len(&self) -> isize { LL | | 1 LL | | } LL | | } @@ -14,7 +14,7 @@ error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_e --> $DIR/len_without_is_empty.rs:37:1 | LL | / pub trait PubTraitsToo { -LL | | fn len(self: &Self) -> isize; +LL | | fn len(&self) -> isize; LL | | } | |_^ @@ -22,7 +22,7 @@ error: item `HasIsEmpty` has a public `len` method but a private `is_empty` meth --> $DIR/len_without_is_empty.rs:49:1 | LL | / impl HasIsEmpty { -LL | | pub fn len(self: &Self) -> isize { +LL | | pub fn len(&self) -> isize { LL | | 1 LL | | } ... | @@ -34,7 +34,7 @@ error: item `HasWrongIsEmpty` has a public `len` method but no corresponding `is --> $DIR/len_without_is_empty.rs:61:1 | LL | / impl HasWrongIsEmpty { -LL | | pub fn len(self: &Self) -> isize { +LL | | pub fn len(&self) -> isize { LL | | 1 LL | | } ... | diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed index a29b832eb601..d81676a3d9f4 100644 --- a/tests/ui/len_zero.fixed +++ b/tests/ui/len_zero.fixed @@ -7,12 +7,12 @@ pub struct One; struct Wither; trait TraitsToo { - fn len(self: &Self) -> isize; + fn len(&self) -> isize; // No error; `len` is private; see issue #1085. } impl TraitsToo for One { - fn len(self: &Self) -> isize { + fn len(&self) -> isize { 0 } } @@ -20,11 +20,11 @@ impl TraitsToo for One { pub struct HasIsEmpty; impl HasIsEmpty { - pub fn len(self: &Self) -> isize { + pub fn len(&self) -> isize { 1 } - fn is_empty(self: &Self) -> bool { + fn is_empty(&self) -> bool { false } } @@ -32,26 +32,26 @@ impl HasIsEmpty { pub struct HasWrongIsEmpty; impl HasWrongIsEmpty { - pub fn len(self: &Self) -> isize { + pub fn len(&self) -> isize { 1 } - pub fn is_empty(self: &Self, x: u32) -> bool { + pub fn is_empty(&self, x: u32) -> bool { false } } pub trait WithIsEmpty { - fn len(self: &Self) -> isize; - fn is_empty(self: &Self) -> bool; + fn len(&self) -> isize; + fn is_empty(&self) -> bool; } impl WithIsEmpty for Wither { - fn len(self: &Self) -> isize { + fn len(&self) -> isize { 1 } - fn is_empty(self: &Self) -> bool { + fn is_empty(&self) -> bool { false } } diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index 8fd0093f4fdb..ecdba921a5d0 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -7,12 +7,12 @@ pub struct One; struct Wither; trait TraitsToo { - fn len(self: &Self) -> isize; + fn len(&self) -> isize; // No error; `len` is private; see issue #1085. } impl TraitsToo for One { - fn len(self: &Self) -> isize { + fn len(&self) -> isize { 0 } } @@ -20,11 +20,11 @@ impl TraitsToo for One { pub struct HasIsEmpty; impl HasIsEmpty { - pub fn len(self: &Self) -> isize { + pub fn len(&self) -> isize { 1 } - fn is_empty(self: &Self) -> bool { + fn is_empty(&self) -> bool { false } } @@ -32,26 +32,26 @@ impl HasIsEmpty { pub struct HasWrongIsEmpty; impl HasWrongIsEmpty { - pub fn len(self: &Self) -> isize { + pub fn len(&self) -> isize { 1 } - pub fn is_empty(self: &Self, x: u32) -> bool { + pub fn is_empty(&self, x: u32) -> bool { false } } pub trait WithIsEmpty { - fn len(self: &Self) -> isize; - fn is_empty(self: &Self) -> bool; + fn len(&self) -> isize; + fn is_empty(&self) -> bool; } impl WithIsEmpty for Wither { - fn len(self: &Self) -> isize { + fn len(&self) -> isize { 1 } - fn is_empty(self: &Self) -> bool { + fn is_empty(&self) -> bool { false } } diff --git a/tests/ui/min_max.rs b/tests/ui/min_max.rs index 8307d4b3019f..f7ed72a11cf6 100644 --- a/tests/ui/min_max.rs +++ b/tests/ui/min_max.rs @@ -6,6 +6,18 @@ use std::cmp::{max, min}; const LARGE: usize = 3; +struct NotOrd(u64); + +impl NotOrd { + fn min(self, x: u64) -> NotOrd { + NotOrd(x) + } + + fn max(self, x: u64) -> NotOrd { + NotOrd(x) + } +} + fn main() { let x; x = 2usize; @@ -30,4 +42,24 @@ fn main() { max(min(s, "Apple"), "Zoo"); max("Apple", min(s, "Zoo")); // ok + + let f = 3f32; + x.min(1).max(3); + x.max(3).min(1); + f.max(3f32).min(1f32); + + x.max(1).min(3); // ok + x.min(3).max(1); // ok + f.min(3f32).max(1f32); // ok + + max(x.min(1), 3); + min(x.max(1), 3); // ok + + s.max("Zoo").min("Apple"); + s.min("Apple").max("Zoo"); + + s.min("Zoo").max("Apple"); // ok + + let not_ord = NotOrd(1); + not_ord.min(1).max(3); // ok } diff --git a/tests/ui/min_max.stderr b/tests/ui/min_max.stderr index b552c137f7c7..9f8e26fa406f 100644 --- a/tests/ui/min_max.stderr +++ b/tests/ui/min_max.stderr @@ -1,5 +1,5 @@ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:12:5 + --> $DIR/min_max.rs:24:5 | LL | min(1, max(3, x)); | ^^^^^^^^^^^^^^^^^ @@ -7,40 +7,76 @@ LL | min(1, max(3, x)); = note: `-D clippy::min-max` implied by `-D warnings` error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:13:5 + --> $DIR/min_max.rs:25:5 | LL | min(max(3, x), 1); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:14:5 + --> $DIR/min_max.rs:26:5 | LL | max(min(x, 1), 3); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:15:5 + --> $DIR/min_max.rs:27:5 | LL | max(3, min(x, 1)); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:17:5 + --> $DIR/min_max.rs:29:5 | LL | my_max(3, my_min(x, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:29:5 + --> $DIR/min_max.rs:41:5 | LL | min("Apple", max("Zoo", s)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:30:5 + --> $DIR/min_max.rs:42:5 | LL | max(min(s, "Apple"), "Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: this `min`/`max` combination leads to constant result + --> $DIR/min_max.rs:47:5 + | +LL | x.min(1).max(3); + | ^^^^^^^^^^^^^^^ + +error: this `min`/`max` combination leads to constant result + --> $DIR/min_max.rs:48:5 + | +LL | x.max(3).min(1); + | ^^^^^^^^^^^^^^^ + +error: this `min`/`max` combination leads to constant result + --> $DIR/min_max.rs:49:5 + | +LL | f.max(3f32).min(1f32); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: this `min`/`max` combination leads to constant result + --> $DIR/min_max.rs:55:5 + | +LL | max(x.min(1), 3); + | ^^^^^^^^^^^^^^^^ + +error: this `min`/`max` combination leads to constant result + --> $DIR/min_max.rs:58:5 + | +LL | s.max("Zoo").min("Apple"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this `min`/`max` combination leads to constant result + --> $DIR/min_max.rs:59:5 + | +LL | s.min("Apple").max("Zoo"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 13 previous errors diff --git a/tests/ui/needless_arbitrary_self_type.fixed b/tests/ui/needless_arbitrary_self_type.fixed new file mode 100644 index 000000000000..9da21eb6b29b --- /dev/null +++ b/tests/ui/needless_arbitrary_self_type.fixed @@ -0,0 +1,69 @@ +// run-rustfix + +#![warn(clippy::needless_arbitrary_self_type)] +#![allow(unused_mut, clippy::needless_lifetimes)] + +pub enum ValType { + A, + B, +} + +impl ValType { + pub fn bad(self) { + unimplemented!(); + } + + pub fn good(self) { + unimplemented!(); + } + + pub fn mut_bad(mut self) { + unimplemented!(); + } + + pub fn mut_good(mut self) { + unimplemented!(); + } + + pub fn ref_bad(&self) { + unimplemented!(); + } + + pub fn ref_good(&self) { + unimplemented!(); + } + + pub fn ref_bad_with_lifetime<'a>(&'a self) { + unimplemented!(); + } + + pub fn ref_good_with_lifetime<'a>(&'a self) { + unimplemented!(); + } + + pub fn mut_ref_bad(&mut self) { + unimplemented!(); + } + + pub fn mut_ref_good(&mut self) { + unimplemented!(); + } + + pub fn mut_ref_bad_with_lifetime<'a>(&'a mut self) { + unimplemented!(); + } + + pub fn mut_ref_good_with_lifetime<'a>(&'a mut self) { + unimplemented!(); + } + + pub fn mut_ref_mut_good(mut self: &mut Self) { + unimplemented!(); + } + + pub fn mut_ref_mut_ref_good(self: &&mut &mut Self) { + unimplemented!(); + } +} + +fn main() {} diff --git a/tests/ui/needless_arbitrary_self_type.rs b/tests/ui/needless_arbitrary_self_type.rs new file mode 100644 index 000000000000..17aeaaf97ac7 --- /dev/null +++ b/tests/ui/needless_arbitrary_self_type.rs @@ -0,0 +1,69 @@ +// run-rustfix + +#![warn(clippy::needless_arbitrary_self_type)] +#![allow(unused_mut, clippy::needless_lifetimes)] + +pub enum ValType { + A, + B, +} + +impl ValType { + pub fn bad(self: Self) { + unimplemented!(); + } + + pub fn good(self) { + unimplemented!(); + } + + pub fn mut_bad(mut self: Self) { + unimplemented!(); + } + + pub fn mut_good(mut self) { + unimplemented!(); + } + + pub fn ref_bad(self: &Self) { + unimplemented!(); + } + + pub fn ref_good(&self) { + unimplemented!(); + } + + pub fn ref_bad_with_lifetime<'a>(self: &'a Self) { + unimplemented!(); + } + + pub fn ref_good_with_lifetime<'a>(&'a self) { + unimplemented!(); + } + + pub fn mut_ref_bad(self: &mut Self) { + unimplemented!(); + } + + pub fn mut_ref_good(&mut self) { + unimplemented!(); + } + + pub fn mut_ref_bad_with_lifetime<'a>(self: &'a mut Self) { + unimplemented!(); + } + + pub fn mut_ref_good_with_lifetime<'a>(&'a mut self) { + unimplemented!(); + } + + pub fn mut_ref_mut_good(mut self: &mut Self) { + unimplemented!(); + } + + pub fn mut_ref_mut_ref_good(self: &&mut &mut Self) { + unimplemented!(); + } +} + +fn main() {} diff --git a/tests/ui/needless_arbitrary_self_type.stderr b/tests/ui/needless_arbitrary_self_type.stderr new file mode 100644 index 000000000000..f4c645d35c8f --- /dev/null +++ b/tests/ui/needless_arbitrary_self_type.stderr @@ -0,0 +1,40 @@ +error: the type of the `self` parameter does not need to be arbitrary + --> $DIR/needless_arbitrary_self_type.rs:12:16 + | +LL | pub fn bad(self: Self) { + | ^^^^^^^^^^ help: consider to change this parameter to: `self` + | + = note: `-D clippy::needless-arbitrary-self-type` implied by `-D warnings` + +error: the type of the `self` parameter does not need to be arbitrary + --> $DIR/needless_arbitrary_self_type.rs:20:20 + | +LL | pub fn mut_bad(mut self: Self) { + | ^^^^^^^^^^^^^^ help: consider to change this parameter to: `mut self` + +error: the type of the `self` parameter does not need to be arbitrary + --> $DIR/needless_arbitrary_self_type.rs:28:20 + | +LL | pub fn ref_bad(self: &Self) { + | ^^^^^^^^^^^ help: consider to change this parameter to: `&self` + +error: the type of the `self` parameter does not need to be arbitrary + --> $DIR/needless_arbitrary_self_type.rs:36:38 + | +LL | pub fn ref_bad_with_lifetime<'a>(self: &'a Self) { + | ^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'a self` + +error: the type of the `self` parameter does not need to be arbitrary + --> $DIR/needless_arbitrary_self_type.rs:44:24 + | +LL | pub fn mut_ref_bad(self: &mut Self) { + | ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&mut self` + +error: the type of the `self` parameter does not need to be arbitrary + --> $DIR/needless_arbitrary_self_type.rs:52:42 + | +LL | pub fn mut_ref_bad_with_lifetime<'a>(self: &'a mut Self) { + | ^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'a mut self` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/option_map_unit_fn_fixable.fixed b/tests/ui/option_map_unit_fn_fixable.fixed index 9a0da404cb6d..96d1c54946c0 100644 --- a/tests/ui/option_map_unit_fn_fixable.fixed +++ b/tests/ui/option_map_unit_fn_fixable.fixed @@ -22,9 +22,9 @@ struct HasOption { } impl HasOption { - fn do_option_nothing(self: &Self, value: usize) {} + fn do_option_nothing(&self, value: usize) {} - fn do_option_plus_one(self: &Self, value: usize) -> usize { + fn do_option_plus_one(&self, value: usize) -> usize { value + 1 } } diff --git a/tests/ui/option_map_unit_fn_fixable.rs b/tests/ui/option_map_unit_fn_fixable.rs index 58041b62df35..931ffc186659 100644 --- a/tests/ui/option_map_unit_fn_fixable.rs +++ b/tests/ui/option_map_unit_fn_fixable.rs @@ -22,9 +22,9 @@ struct HasOption { } impl HasOption { - fn do_option_nothing(self: &Self, value: usize) {} + fn do_option_nothing(&self, value: usize) {} - fn do_option_plus_one(self: &Self, value: usize) -> usize { + fn do_option_plus_one(&self, value: usize) -> usize { value + 1 } } diff --git a/tests/ui/result_map_unit_fn_fixable.fixed b/tests/ui/result_map_unit_fn_fixable.fixed index 1d0a3ecd0ff8..631042c616bc 100644 --- a/tests/ui/result_map_unit_fn_fixable.fixed +++ b/tests/ui/result_map_unit_fn_fixable.fixed @@ -18,9 +18,9 @@ struct HasResult { } impl HasResult { - fn do_result_nothing(self: &Self, value: usize) {} + fn do_result_nothing(&self, value: usize) {} - fn do_result_plus_one(self: &Self, value: usize) -> usize { + fn do_result_plus_one(&self, value: usize) -> usize { value + 1 } } diff --git a/tests/ui/result_map_unit_fn_fixable.rs b/tests/ui/result_map_unit_fn_fixable.rs index 2fe18f923f08..679eb2326268 100644 --- a/tests/ui/result_map_unit_fn_fixable.rs +++ b/tests/ui/result_map_unit_fn_fixable.rs @@ -18,9 +18,9 @@ struct HasResult { } impl HasResult { - fn do_result_nothing(self: &Self, value: usize) {} + fn do_result_nothing(&self, value: usize) {} - fn do_result_plus_one(self: &Self, value: usize) -> usize { + fn do_result_plus_one(&self, value: usize) -> usize { value + 1 } } diff --git a/tests/ui/same_item_push.rs b/tests/ui/same_item_push.rs new file mode 100644 index 000000000000..ff1088f86f64 --- /dev/null +++ b/tests/ui/same_item_push.rs @@ -0,0 +1,89 @@ +#![warn(clippy::same_item_push)] + +fn mutate_increment(x: &mut u8) -> u8 { + *x += 1; + *x +} + +fn increment(x: u8) -> u8 { + x + 1 +} + +fn main() { + // Test for basic case + let mut spaces = Vec::with_capacity(10); + for _ in 0..10 { + spaces.push(vec![b' ']); + } + + let mut vec2: Vec = Vec::new(); + let item = 2; + for _ in 5..=20 { + vec2.push(item); + } + + let mut vec3: Vec = Vec::new(); + for _ in 0..15 { + let item = 2; + vec3.push(item); + } + + let mut vec4: Vec = Vec::new(); + for _ in 0..15 { + vec4.push(13); + } + + // Suggestion should not be given as pushed variable can mutate + let mut vec5: Vec = Vec::new(); + let mut item: u8 = 2; + for _ in 0..30 { + vec5.push(mutate_increment(&mut item)); + } + + let mut vec6: Vec = Vec::new(); + let mut item: u8 = 2; + let mut item2 = &mut mutate_increment(&mut item); + for _ in 0..30 { + vec6.push(mutate_increment(item2)); + } + + let mut vec7: Vec = Vec::new(); + for (a, b) in [0, 1, 4, 9, 16].iter().enumerate() { + vec7.push(a); + } + + let mut vec8: Vec = Vec::new(); + for i in 0..30 { + vec8.push(increment(i)); + } + + let mut vec9: Vec = Vec::new(); + for i in 0..30 { + vec9.push(i + i * i); + } + + // Suggestion should not be given as there are multiple pushes that are not the same + let mut vec10: Vec = Vec::new(); + let item: u8 = 2; + for _ in 0..30 { + vec10.push(item); + vec10.push(item * 2); + } + + // Suggestion should not be given as Vec is not involved + for _ in 0..5 { + println!("Same Item Push"); + } + + struct A { + kind: u32, + } + let mut vec_a: Vec = Vec::new(); + for i in 0..30 { + vec_a.push(A { kind: i }); + } + let mut vec12: Vec = Vec::new(); + for a in vec_a { + vec12.push(2u8.pow(a.kind)); + } +} diff --git a/tests/ui/same_item_push.stderr b/tests/ui/same_item_push.stderr new file mode 100644 index 000000000000..ddc5d48cd413 --- /dev/null +++ b/tests/ui/same_item_push.stderr @@ -0,0 +1,35 @@ +error: it looks like the same item is being pushed into this Vec + --> $DIR/same_item_push.rs:16:9 + | +LL | spaces.push(vec![b' ']); + | ^^^^^^ + | + = note: `-D clippy::same-item-push` implied by `-D warnings` + = help: try using vec![vec![b' '];SIZE] or spaces.resize(NEW_SIZE, vec![b' ']) + +error: it looks like the same item is being pushed into this Vec + --> $DIR/same_item_push.rs:22:9 + | +LL | vec2.push(item); + | ^^^^ + | + = help: try using vec![item;SIZE] or vec2.resize(NEW_SIZE, item) + +error: it looks like the same item is being pushed into this Vec + --> $DIR/same_item_push.rs:28:9 + | +LL | vec3.push(item); + | ^^^^ + | + = help: try using vec![item;SIZE] or vec3.resize(NEW_SIZE, item) + +error: it looks like the same item is being pushed into this Vec + --> $DIR/same_item_push.rs:33:9 + | +LL | vec4.push(13); + | ^^^^ + | + = help: try using vec![13;SIZE] or vec4.resize(NEW_SIZE, 13) + +error: aborting due to 4 previous errors + diff --git a/tests/ui/unsafe_derive_deserialize.rs b/tests/ui/unsafe_derive_deserialize.rs index 7bee9c499e1f..690d705573d3 100644 --- a/tests/ui/unsafe_derive_deserialize.rs +++ b/tests/ui/unsafe_derive_deserialize.rs @@ -57,4 +57,14 @@ impl E { #[derive(Deserialize)] pub struct F {} +// Check that we honor the `allow` attribute on the ADT +#[allow(clippy::unsafe_derive_deserialize)] +#[derive(Deserialize)] +pub struct G {} +impl G { + pub fn unsafe_block(&self) { + unsafe {} + } +} + fn main() {}