about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Wright <mikerite@lavabit.com>2019-01-06 11:46:03 +0200
committerMichael Wright <mikerite@lavabit.com>2019-01-06 11:46:03 +0200
commit4add1e23f9b487373bd02852f3eef1ec15fdafc3 (patch)
treef7e98ba8fa2499572125dd63a871a4bffda52175
parentc63b6349b44019146cc2edcef8141692891b9401 (diff)
downloadrust-4add1e23f9b487373bd02852f3eef1ec15fdafc3.tar.gz
rust-4add1e23f9b487373bd02852f3eef1ec15fdafc3.zip
Improve `get_unwrap` suggestion
Handle case where a reference is immediately dereferenced.

Fixes 3625
-rw-r--r--clippy_lints/src/methods/mod.rs21
-rw-r--r--tests/ui/get_unwrap.fixed68
-rw-r--r--tests/ui/get_unwrap.rs1
-rw-r--r--tests/ui/get_unwrap.stderr32
4 files changed, 104 insertions, 18 deletions
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index dcd9e3ee153..afc875593ac 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -1603,7 +1603,7 @@ fn lint_get_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, get_args: &[hir::
     } else {
         return; // not linting on a .get().unwrap() chain or variant
     };
-    let needs_ref;
+    let mut needs_ref;
     let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
         needs_ref = get_args_str.parse::<usize>().is_ok();
         "slice"
@@ -1623,6 +1623,22 @@ fn lint_get_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, get_args: &[hir::
         return; // caller is not a type that we want to lint
     };
 
+    let mut span = expr.span;
+
+    // Handle the case where the result is immedately dereferenced
+    // by not requiring ref and pulling the dereference into the
+    // suggestion.
+    if needs_ref {
+        if let Some(parent) = get_parent_expr(cx, expr) {
+            if let hir::ExprKind::Unary(op, _) = parent.node {
+                if op == hir::UnOp::UnDeref {
+                    needs_ref = false;
+                    span = parent.span;
+                }
+            }
+        }
+    }
+
     let mut_str = if is_mut { "_mut" } else { "" };
     let borrow_str = if !needs_ref {
         ""
@@ -1631,10 +1647,11 @@ fn lint_get_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, get_args: &[hir::
     } else {
         "&"
     };
+
     span_lint_and_sugg(
         cx,
         GET_UNWRAP,
-        expr.span,
+        span,
         &format!(
             "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
             mut_str, caller_type
diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed
new file mode 100644
index 00000000000..4badef1b803
--- /dev/null
+++ b/tests/ui/get_unwrap.fixed
@@ -0,0 +1,68 @@
+// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+#![allow(unused_mut)]
+
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::collections::VecDeque;
+use std::iter::FromIterator;
+
+struct GetFalsePositive {
+    arr: [u32; 3],
+}
+
+impl GetFalsePositive {
+    fn get(&self, pos: usize) -> Option<&u32> {
+        self.arr.get(pos)
+    }
+    fn get_mut(&mut self, pos: usize) -> Option<&mut u32> {
+        self.arr.get_mut(pos)
+    }
+}
+
+fn main() {
+    let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
+    let mut some_slice = &mut [0, 1, 2, 3];
+    let mut some_vec = vec![0, 1, 2, 3];
+    let mut some_vecdeque: VecDeque<_> = some_vec.iter().cloned().collect();
+    let mut some_hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(1, 'a'), (2, 'b')]);
+    let mut some_btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(1, 'a'), (2, 'b')]);
+    let mut false_positive = GetFalsePositive { arr: [0, 1, 2] };
+
+    {
+        // Test `get().unwrap()`
+        let _ = &boxed_slice[1];
+        let _ = &some_slice[0];
+        let _ = &some_vec[0];
+        let _ = &some_vecdeque[0];
+        let _ = &some_hashmap[&1];
+        let _ = &some_btreemap[&1];
+        let _ = false_positive.get(0).unwrap();
+    }
+
+    {
+        // Test `get_mut().unwrap()`
+        boxed_slice[0] = 1;
+        some_slice[0] = 1;
+        some_vec[0] = 1;
+        some_vecdeque[0] = 1;
+        // Check false positives
+        *some_hashmap.get_mut(&1).unwrap() = 'b';
+        *some_btreemap.get_mut(&1).unwrap() = 'b';
+        *false_positive.get_mut(0).unwrap() = 1;
+    }
+
+    {
+        // Test `get().unwrap().foo()` and `get_mut().unwrap().bar()`
+        let _ = some_vec[0..1].to_vec();
+        let _ = some_vec[0..1].to_vec();
+    }
+}
diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs
index e8789db6fc1..d1a32dcbda3 100644
--- a/tests/ui/get_unwrap.rs
+++ b/tests/ui/get_unwrap.rs
@@ -7,6 +7,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// run-rustfix
 #![allow(unused_mut)]
 
 use std::collections::BTreeMap;
diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr
index 1f45c26048a..c947cf87d10 100644
--- a/tests/ui/get_unwrap.stderr
+++ b/tests/ui/get_unwrap.stderr
@@ -1,5 +1,5 @@
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:41:17
+  --> $DIR/get_unwrap.rs:42:17
    |
 LL |         let _ = boxed_slice.get(1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
@@ -7,67 +7,67 @@ LL |         let _ = boxed_slice.get(1).unwrap();
    = note: `-D clippy::get-unwrap` implied by `-D warnings`
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:42:17
+  --> $DIR/get_unwrap.rs:43:17
    |
 LL |         let _ = some_slice.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]`
 
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:43:17
+  --> $DIR/get_unwrap.rs:44:17
    |
 LL |         let _ = some_vec.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]`
 
 error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:44:17
+  --> $DIR/get_unwrap.rs:45:17
    |
 LL |         let _ = some_vecdeque.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]`
 
 error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:45:17
+  --> $DIR/get_unwrap.rs:46:17
    |
 LL |         let _ = some_hashmap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]`
 
 error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:46:17
+  --> $DIR/get_unwrap.rs:47:17
    |
 LL |         let _ = some_btreemap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]`
 
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:52:10
+  --> $DIR/get_unwrap.rs:53:9
    |
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut boxed_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]`
 
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:53:10
+  --> $DIR/get_unwrap.rs:54:9
    |
 LL |         *some_slice.get_mut(0).unwrap() = 1;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut some_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]`
 
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:54:10
+  --> $DIR/get_unwrap.rs:55:9
    |
 LL |         *some_vec.get_mut(0).unwrap() = 1;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut some_vec[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]`
 
 error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:55:10
+  --> $DIR/get_unwrap.rs:56:9
    |
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut some_vecdeque[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]`
 
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:64:17
+  --> $DIR/get_unwrap.rs:65:17
    |
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
 
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:65:17
+  --> $DIR/get_unwrap.rs:66:17
    |
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`