diff options
| author | dvermd <315743+dvermd@users.noreply.github.com> | 2020-10-12 23:58:59 +0200 |
|---|---|---|
| committer | dvermd <315743+dvermd@users.noreply.github.com> | 2020-10-26 22:34:40 +0100 |
| commit | 213dbf7aacb01cc4d05d47f010833aa6e9c2a7d0 (patch) | |
| tree | 5d275255d35a08d2f5e176ee449f6cafba3a2fda | |
| parent | afbac8906e614a63ff5825710c3ebe45a3b5e01a (diff) | |
| download | rust-213dbf7aacb01cc4d05d47f010833aa6e9c2a7d0.tar.gz rust-213dbf7aacb01cc4d05d47f010833aa6e9c2a7d0.zip | |
clippy_lint: Add 'ref_option_ref'
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | clippy_lints/src/lib.rs | 5 | ||||
| -rw-r--r-- | clippy_lints/src/ref_option_ref.rs | 65 | ||||
| -rw-r--r-- | src/lintlist/mod.rs | 7 | ||||
| -rw-r--r-- | tests/ui/ref_option_ref.rs | 5 | ||||
| -rw-r--r-- | tests/ui/ref_option_ref.stderr | 10 |
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, ®ex::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(®ex::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(®ex::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 + |
