about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/lib.rs5
-rw-r--r--clippy_lints/src/utils/paths.rs1
-rw-r--r--clippy_lints/src/vec_resize_to_zero.rs59
-rw-r--r--src/lintlist/mod.rs7
-rw-r--r--tests/ui/vec_resize_to_zero.rs15
-rw-r--r--tests/ui/vec_resize_to_zero.stderr13
7 files changed, 101 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2ac9057199f..f7dae3dcfff 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1630,6 +1630,7 @@ Released 2018-09-13
 [`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute
 [`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec
 [`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box
+[`vec_resize_to_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_resize_to_zero
 [`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
 [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
 [`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 902f3d56c1e..4f0ecab393d 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -325,6 +325,7 @@ mod unwrap;
 mod use_self;
 mod useless_conversion;
 mod vec;
+mod vec_resize_to_zero;
 mod verbose_file_reads;
 mod wildcard_dependencies;
 mod wildcard_imports;
@@ -847,6 +848,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &utils::internal_lints::OUTER_EXPN_EXPN_DATA,
         &utils::internal_lints::PRODUCE_ICE,
         &vec::USELESS_VEC,
+        &vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
         &verbose_file_reads::VERBOSE_FILE_READS,
         &wildcard_dependencies::WILDCARD_DEPENDENCIES,
         &wildcard_imports::ENUM_GLOB_USE,
@@ -1062,6 +1064,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive);
     store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
     store.register_early_pass(|| box redundant_field_names::RedundantFieldNames);
+    store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
     let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
     store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
         single_char_binding_names_threshold,
@@ -1430,6 +1433,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&unwrap::UNNECESSARY_UNWRAP),
         LintId::of(&useless_conversion::USELESS_CONVERSION),
         LintId::of(&vec::USELESS_VEC),
+        LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
         LintId::of(&write::PRINTLN_EMPTY_STRING),
         LintId::of(&write::PRINT_LITERAL),
         LintId::of(&write::PRINT_WITH_NEWLINE),
@@ -1677,6 +1681,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
         LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
         LintId::of(&unwrap::PANICKING_UNWRAP),
+        LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
     ]);
 
     store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs
index 779da7e6bf2..3b7e9739211 100644
--- a/clippy_lints/src/utils/paths.rs
+++ b/clippy_lints/src/utils/paths.rs
@@ -138,5 +138,6 @@ pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
 pub const VEC_DEQUE: [&str; 4] = ["alloc", "collections", "vec_deque", "VecDeque"];
 pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
 pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
+pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
 pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
 pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
diff --git a/clippy_lints/src/vec_resize_to_zero.rs b/clippy_lints/src/vec_resize_to_zero.rs
new file mode 100644
index 00000000000..86cbfa8203d
--- /dev/null
+++ b/clippy_lints/src/vec_resize_to_zero.rs
@@ -0,0 +1,59 @@
+use crate::utils::span_lint_and_then;
+use if_chain::if_chain;
+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_span::source_map::Spanned;
+
+use crate::utils::{match_def_path, paths};
+use rustc_ast::ast::LitKind;
+use rustc_hir as hir;
+
+declare_clippy_lint! {
+    /// **What it does:** Finds occurences of `Vec::resize(0, an_int)`
+    ///
+    /// **Why is this bad?** This is probably an argument inversion mistake.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// vec!(1, 2, 3, 4, 5).resize(0, 5)
+    /// ```
+    pub VEC_RESIZE_TO_ZERO,
+    correctness,
+    "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake"
+}
+
+declare_lint_pass!(VecResizeToZero => [VEC_RESIZE_TO_ZERO]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VecResizeToZero {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
+        if_chain! {
+            if let hir::ExprKind::MethodCall(path_segment, _, ref args) = expr.kind;
+            if let Some(method_def_id) = cx.tables.type_dependent_def_id(expr.hir_id);
+            if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3;
+            if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind;
+            if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = args[2].kind;
+            then {
+                let method_call_span = expr.span.with_lo(path_segment.ident.span.lo());
+                span_lint_and_then(
+                    cx,
+                    VEC_RESIZE_TO_ZERO,
+                    expr.span,
+                    "emptying a vector with `resize`",
+                    |db| {
+                        db.help("the arguments may be inverted...");
+                        db.span_suggestion(
+                            method_call_span,
+                            "...or you can empty the vector with",
+                            "clear()".to_string(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    },
+                );
+            }
+        }
+    }
+}
diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs
index f63301c7db0..1e94ca00c14 100644
--- a/src/lintlist/mod.rs
+++ b/src/lintlist/mod.rs
@@ -2461,6 +2461,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "types",
     },
     Lint {
+        name: "vec_resize_to_zero",
+        group: "correctness",
+        desc: "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake",
+        deprecation: None,
+        module: "vec_resize_to_zero",
+    },
+    Lint {
         name: "verbose_bit_mask",
         group: "style",
         desc: "expressions where a bit mask is less readable than the corresponding method call",
diff --git a/tests/ui/vec_resize_to_zero.rs b/tests/ui/vec_resize_to_zero.rs
new file mode 100644
index 00000000000..0263e2f5f20
--- /dev/null
+++ b/tests/ui/vec_resize_to_zero.rs
@@ -0,0 +1,15 @@
+#![warn(clippy::vec_resize_to_zero)]
+
+fn main() {
+    // applicable here
+    vec![1, 2, 3, 4, 5].resize(0, 5);
+
+    // not applicable
+    vec![1, 2, 3, 4, 5].resize(2, 5);
+
+    // applicable here, but only implemented for integer litterals for now
+    vec!["foo", "bar", "baz"].resize(0, "bar");
+
+    // not applicable
+    vec!["foo", "bar", "baz"].resize(2, "bar")
+}
diff --git a/tests/ui/vec_resize_to_zero.stderr b/tests/ui/vec_resize_to_zero.stderr
new file mode 100644
index 00000000000..feb846298c6
--- /dev/null
+++ b/tests/ui/vec_resize_to_zero.stderr
@@ -0,0 +1,13 @@
+error: emptying a vector with `resize`
+  --> $DIR/vec_resize_to_zero.rs:5:5
+   |
+LL |     vec![1, 2, 3, 4, 5].resize(0, 5);
+   |     ^^^^^^^^^^^^^^^^^^^^------------
+   |                         |
+   |                         help: ...or you can empty the vector with: `clear()`
+   |
+   = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings`
+   = help: the arguments may be inverted...
+
+error: aborting due to previous error
+