diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 52855031a5a..5d0b302e06b 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -71,6 +71,9 @@ enum InitializationType<'tcx> { /// Resize is a slow initialization with the form `vec.resize(.., 0)` Resize(&'tcx Expr), + + /// UnsafeSetLen is a slow initialization with the form `vec.set_len(..)` + UnsafeSetLen(&'tcx Expr), } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { @@ -93,7 +96,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { len_expr: len_arg, }; - Pass::search_slow_zero_filling(cx, vi, expr.id, expr.span); + Pass::search_slow_initialization(cx, vi, expr.id, expr.span); } } } @@ -114,7 +117,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { len_expr: len_arg, }; - Pass::search_slow_zero_filling(cx, vi, stmt.node.id(), stmt.span); + Pass::search_slow_initialization(cx, vi, stmt.node.id(), stmt.span); } } } @@ -138,8 +141,8 @@ impl Pass { None } - /// Search for slow zero filling vector initialization for the given vector - fn search_slow_zero_filling<'tcx>( + /// Search a slow initialization for the given vector + fn search_slow_initialization<'tcx>( cx: &LateContext<'_, 'tcx>, vec_initialization: VecInitialization<'tcx>, parent_node: NodeId, @@ -171,11 +174,14 @@ impl Pass { match repeat_expr { InitializationType::Extend(e) => { - db.span_note(e.span, "extended here with .. 0"); + db.span_note(e.span, "extended at"); }, InitializationType::Resize(e) => { - db.span_note(e.span, "resize here with .. 0"); - } + db.span_note(e.span, "resized at"); + }, + InitializationType::UnsafeSetLen(e) => { + db.span_note(e.span, "changed len at"); + }, } } ); @@ -239,6 +245,25 @@ impl<'a, 'tcx> SlowInitializationVisitor<'a, 'tcx> { } } + /// Checks if the given expression is using `set_len` to initialize the vector + fn search_unsafe_set_len(&mut self, expr: &'tcx Expr) { + if_chain! { + if self.initialization_found; + if let ExprKind::MethodCall(ref path, _, ref args) = expr.node; + if let ExprKind::Path(ref qpath_subj) = args[0].node; + if match_qpath(&qpath_subj, &[&self.vec_ini.variable_name.to_string()]); + if path.ident.name == "set_len"; + if let Some(ref len_arg) = args.get(1); + + // Check that len expression is equals to `with_capacity` expression + if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_ini.len_expr); + + then { + self.slow_expression = Some(InitializationType::UnsafeSetLen(expr)); + } + } + } + /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&self, expr: &Expr) -> bool { if_chain! { @@ -294,6 +319,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SlowInitializationVisitor<'a, 'tcx> { self.search_slow_extend_filling(expr); self.search_slow_resize_filling(expr); + self.search_unsafe_set_len(expr); walk_expr(self, expr); } diff --git a/tests/ui/slow_vector_initialization.rs b/tests/ui/slow_vector_initialization.rs index f79abe8327e..991d850464e 100644 --- a/tests/ui/slow_vector_initialization.rs +++ b/tests/ui/slow_vector_initialization.rs @@ -13,6 +13,7 @@ fn main() { resize_vector(); extend_vector(); mixed_extend_resize_vector(); + unsafe_vector(); } fn extend_vector() { @@ -61,3 +62,11 @@ fn resize_vector() { vec1 = Vec::with_capacity(10); vec1.resize(10, 0); } + +fn unsafe_vector() { + let mut unsafe_vec: Vec = Vec::with_capacity(200); + + unsafe { + unsafe_vec.set_len(200); + } +} diff --git a/tests/ui/slow_vector_initialization.stderr b/tests/ui/slow_vector_initialization.stderr index 4941794d541..ece6f388c84 100644 --- a/tests/ui/slow_vector_initialization.stderr +++ b/tests/ui/slow_vector_initialization.stderr @@ -1,101 +1,115 @@ error: detected slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:21:5 + --> $DIR/slow_vector_initialization.rs:22:5 | -21 | let mut vec1 = Vec::with_capacity(len); +22 | let mut vec1 = Vec::with_capacity(len); | ^^^^^^^^^^^^^^^-----------------------^ | | | help: consider replacing with: `vec![0; ..]` | = note: `-D clippy::slow-vector-initialization` implied by `-D warnings` -note: extended here with .. 0 - --> $DIR/slow_vector_initialization.rs:22:5 +note: extended at + --> $DIR/slow_vector_initialization.rs:23:5 | -22 | vec1.extend(repeat(0).take(len)); +23 | vec1.extend(repeat(0).take(len)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: detected slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:25:5 + --> $DIR/slow_vector_initialization.rs:26:5 | -25 | let mut vec2 = Vec::with_capacity(len - 10); +26 | let mut vec2 = Vec::with_capacity(len - 10); | ^^^^^^^^^^^^^^^----------------------------^ | | | help: consider replacing with: `vec![0; ..]` | -note: extended here with .. 0 - --> $DIR/slow_vector_initialization.rs:26:5 +note: extended at + --> $DIR/slow_vector_initialization.rs:27:5 | -26 | vec2.extend(repeat(0).take(len - 10)); +27 | vec2.extend(repeat(0).take(len - 10)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: detected slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:38:5 - | -38 | let mut resized_vec = Vec::with_capacity(30); - | ^^^^^^^^^^^^^^^^^^^^^^----------------------^ - | | - | help: consider replacing with: `vec![0; ..]` - | -note: resize here with .. 0 - --> $DIR/slow_vector_initialization.rs:41:5 - | -41 | resized_vec.resize(30, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - error: detected slow zero-filling initialization --> $DIR/slow_vector_initialization.rs:39:5 | -39 | let mut extend_vec = Vec::with_capacity(30); +39 | let mut resized_vec = Vec::with_capacity(30); + | ^^^^^^^^^^^^^^^^^^^^^^----------------------^ + | | + | help: consider replacing with: `vec![0; ..]` + | +note: resized at + --> $DIR/slow_vector_initialization.rs:42:5 + | +42 | resized_vec.resize(30, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: detected slow zero-filling initialization + --> $DIR/slow_vector_initialization.rs:40:5 + | +40 | let mut extend_vec = Vec::with_capacity(30); | ^^^^^^^^^^^^^^^^^^^^^----------------------^ | | | help: consider replacing with: `vec![0; ..]` | -note: extended here with .. 0 - --> $DIR/slow_vector_initialization.rs:43:5 +note: extended at + --> $DIR/slow_vector_initialization.rs:44:5 | -43 | extend_vec.extend(repeat(0).take(30)); +44 | extend_vec.extend(repeat(0).take(30)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: detected slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:49:5 + --> $DIR/slow_vector_initialization.rs:50:5 | -49 | let mut vec1 = Vec::with_capacity(len); +50 | let mut vec1 = Vec::with_capacity(len); | ^^^^^^^^^^^^^^^-----------------------^ | | | help: consider replacing with: `vec![0; ..]` | -note: resize here with .. 0 - --> $DIR/slow_vector_initialization.rs:50:5 +note: resized at + --> $DIR/slow_vector_initialization.rs:51:5 | -50 | vec1.resize(len, 0); +51 | vec1.resize(len, 0); | ^^^^^^^^^^^^^^^^^^^ error: detected slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:57:5 + --> $DIR/slow_vector_initialization.rs:58:5 | -57 | let mut vec3 = Vec::with_capacity(len - 10); +58 | let mut vec3 = Vec::with_capacity(len - 10); | ^^^^^^^^^^^^^^^----------------------------^ | | | help: consider replacing with: `vec![0; ..]` | -note: resize here with .. 0 - --> $DIR/slow_vector_initialization.rs:58:5 +note: resized at + --> $DIR/slow_vector_initialization.rs:59:5 | -58 | vec3.resize(len - 10, 0); +59 | vec3.resize(len - 10, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: detected slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:61:5 + --> $DIR/slow_vector_initialization.rs:62:5 | -61 | vec1 = Vec::with_capacity(10); +62 | vec1 = Vec::with_capacity(10); | ^^^^^^^---------------------- | | | help: consider replacing with: `vec![0; ..]` | -note: resize here with .. 0 - --> $DIR/slow_vector_initialization.rs:62:5 +note: resized at + --> $DIR/slow_vector_initialization.rs:63:5 | -62 | vec1.resize(10, 0); +63 | vec1.resize(10, 0); | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: detected slow zero-filling initialization + --> $DIR/slow_vector_initialization.rs:67:5 + | +67 | let mut unsafe_vec: Vec = Vec::with_capacity(200); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------^ + | | + | help: consider replacing with: `vec![0; ..]` + | +note: changed len at + --> $DIR/slow_vector_initialization.rs:70:9 + | +70 | unsafe_vec.set_len(200); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors