about summary refs log tree commit diff
diff options
context:
space:
mode:
authordvermd <315743+dvermd@users.noreply.github.com>2020-10-12 23:58:59 +0200
committerdvermd <315743+dvermd@users.noreply.github.com>2020-10-26 22:34:40 +0100
commit213dbf7aacb01cc4d05d47f010833aa6e9c2a7d0 (patch)
tree5d275255d35a08d2f5e176ee449f6cafba3a2fda
parentafbac8906e614a63ff5825710c3ebe45a3b5e01a (diff)
downloadrust-213dbf7aacb01cc4d05d47f010833aa6e9c2a7d0.tar.gz
rust-213dbf7aacb01cc4d05d47f010833aa6e9c2a7d0.zip
clippy_lint: Add 'ref_option_ref'
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/lib.rs5
-rw-r--r--clippy_lints/src/ref_option_ref.rs65
-rw-r--r--src/lintlist/mod.rs7
-rw-r--r--tests/ui/ref_option_ref.rs5
-rw-r--r--tests/ui/ref_option_ref.stderr10
6 files changed, 93 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 25f3b5da198..db834fe108b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1917,6 +1917,7 @@ Released 2018-09-13
 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
 [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
 [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
+[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
 [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 3be8bc0e36d..1ab36231758 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -293,6 +293,7 @@ mod redundant_closure_call;
 mod redundant_field_names;
 mod redundant_pub_crate;
 mod redundant_static_lifetimes;
+mod ref_option_ref;
 mod reference;
 mod regex;
 mod repeat_once;
@@ -803,6 +804,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &redundant_field_names::REDUNDANT_FIELD_NAMES,
         &redundant_pub_crate::REDUNDANT_PUB_CRATE,
         &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
+        &ref_option_ref::REF_OPTION_REF,
         &reference::DEREF_ADDROF,
         &reference::REF_IN_DEREF,
         &regex::INVALID_REGEX,
@@ -1024,6 +1026,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &sess.target,
     );
     store.register_late_pass(move || box pass_by_ref_or_value);
+    store.register_late_pass(|| box ref_option_ref::RefOptionRef);
     store.register_late_pass(|| box try_err::TryErr);
     store.register_late_pass(|| box use_self::UseSelf);
     store.register_late_pass(|| box bytecount::ByteCount);
@@ -1493,6 +1496,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL),
         LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
         LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
+        LintId::of(&ref_option_ref::REF_OPTION_REF),
         LintId::of(&reference::DEREF_ADDROF),
         LintId::of(&reference::REF_IN_DEREF),
         LintId::of(&regex::INVALID_REGEX),
@@ -1648,6 +1652,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&ranges::MANUAL_RANGE_CONTAINS),
         LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
         LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
+        LintId::of(&ref_option_ref::REF_OPTION_REF),
         LintId::of(&regex::TRIVIAL_REGEX),
         LintId::of(&returns::LET_AND_RETURN),
         LintId::of(&returns::NEEDLESS_RETURN),
diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs
new file mode 100644
index 00000000000..fbee3263556
--- /dev/null
+++ b/clippy_lints/src/ref_option_ref.rs
@@ -0,0 +1,65 @@
+use crate::utils::{last_path_segment, match_def_path, paths, snippet, span_lint_and_sugg};
+use rustc_hir::{GenericArg, Local, Mutability, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `&Option<&T>`.
+    ///
+    /// **Why is this bad?** Since `&` is Copy, it's useless to have a
+    /// reference on `Option<&T>`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust,ignore
+    /// // example code where clippy issues a warning
+    /// let x: &Option<&u32> = &Some(&0u32);
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// // example code which does not raise clippy warning
+    /// let x: Option<&u32> = Some(&0u32);
+    /// ```
+    pub REF_OPTION_REF,
+    style,
+    "use `Option<&T>` instead of `&Option<&T>`"
+}
+
+declare_lint_pass!(RefOptionRef => [REF_OPTION_REF]);
+
+impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
+        if_chain! {
+            if let Some(ref ty) = local.ty;
+            if let TyKind::Rptr(_, ref mut_ty) = ty.kind;
+            if mut_ty.mutbl == Mutability::Not;
+            if let TyKind::Path(ref qpath) = &mut_ty.ty.kind ;
+            if let Some(def_id) = cx.typeck_results().qpath_res(qpath, local.hir_id).opt_def_id();
+            if match_def_path(cx, def_id, &paths::OPTION);
+            if let Some(ref params) = last_path_segment(qpath).args ;
+            if !params.parenthesized;
+            if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg {
+                GenericArg::Type(inner_ty) => Some(inner_ty),
+                _ => None,
+            });
+            if let TyKind::Rptr(_, _) = inner_ty.kind;
+
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    REF_OPTION_REF,
+                    ty.span,
+                    "since & implements Copy trait, &Option<&T> can be simplifyied into Option<&T>",
+                    "try",
+                    format!("Option<{}>", &snippet(cx, inner_ty.span, "..")),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs
index 6272ce45efb..b3bd1923d4e 100644
--- a/src/lintlist/mod.rs
+++ b/src/lintlist/mod.rs
@@ -2014,6 +2014,13 @@ vec![
         module: "reference",
     },
     Lint {
+        name: "ref_option_ref",
+        group: "style",
+        desc: "use `Option<&T>` instead of `&Option<&T>`",
+        deprecation: None,
+        module: "ref_option_ref",
+    },
+    Lint {
         name: "repeat_once",
         group: "complexity",
         desc: "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` ",
diff --git a/tests/ui/ref_option_ref.rs b/tests/ui/ref_option_ref.rs
new file mode 100644
index 00000000000..7f05990c0a0
--- /dev/null
+++ b/tests/ui/ref_option_ref.rs
@@ -0,0 +1,5 @@
+#![warn(clippy::ref_option_ref)]
+
+fn main() {
+    let x: &Option<&u32> = &None;
+}
diff --git a/tests/ui/ref_option_ref.stderr b/tests/ui/ref_option_ref.stderr
new file mode 100644
index 00000000000..90bcaef7570
--- /dev/null
+++ b/tests/ui/ref_option_ref.stderr
@@ -0,0 +1,10 @@
+error: since & implements Copy trait, &Option<&T> can be simplifyied into Option<&T>
+  --> $DIR/ref_option_ref.rs:4:12
+   |
+LL |     let x: &Option<&u32> = &None;
+   |            ^^^^^^^^^^^^^ help: try: `Option<&u32>`
+   |
+   = note: `-D clippy::ref-option-ref` implied by `-D warnings`
+
+error: aborting due to previous error
+