Skip to content

Commit 4184cc3

Browse files
committed
needless_option_as_deref
1 parent a8c2c7b commit 4184cc3

7 files changed

+119
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -2822,6 +2822,7 @@ Released 2018-09-13
28222822
[`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main
28232823
[`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each
28242824
[`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
2825+
[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
28252826
[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
28262827
[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
28272828
[`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop

clippy_lints/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ mod needless_borrow;
289289
mod needless_borrowed_ref;
290290
mod needless_continue;
291291
mod needless_for_each;
292+
mod needless_option_as_deref;
292293
mod needless_pass_by_value;
293294
mod needless_question_mark;
294295
mod needless_update;
@@ -847,6 +848,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
847848
needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
848849
needless_continue::NEEDLESS_CONTINUE,
849850
needless_for_each::NEEDLESS_FOR_EACH,
851+
needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF,
850852
needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
851853
needless_question_mark::NEEDLESS_QUESTION_MARK,
852854
needless_update::NEEDLESS_UPDATE,
@@ -1374,6 +1376,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13741376
LintId::of(needless_bool::NEEDLESS_BOOL),
13751377
LintId::of(needless_borrow::NEEDLESS_BORROW),
13761378
LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
1379+
LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
13771380
LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
13781381
LintId::of(needless_update::NEEDLESS_UPDATE),
13791382
LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
@@ -1636,6 +1639,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16361639
LintId::of(needless_bool::BOOL_COMPARISON),
16371640
LintId::of(needless_bool::NEEDLESS_BOOL),
16381641
LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
1642+
LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
16391643
LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
16401644
LintId::of(needless_update::NEEDLESS_UPDATE),
16411645
LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
@@ -1863,6 +1867,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
18631867
store.register_late_pass(|| Box::new(ptr::Ptr));
18641868
store.register_late_pass(|| Box::new(ptr_eq::PtrEq));
18651869
store.register_late_pass(|| Box::new(needless_bool::NeedlessBool));
1870+
store.register_late_pass(|| Box::new(needless_option_as_deref::OptionNeedlessDeref));
18661871
store.register_late_pass(|| Box::new(needless_bool::BoolComparison));
18671872
store.register_late_pass(|| Box::new(needless_for_each::NeedlessForEach));
18681873
store.register_late_pass(|| Box::new(approx_const::ApproxConstant));

clippy_lints/src/loops/never_loop.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
8787

8888
fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
8989
let stmts = block.stmts.iter().map(stmt_to_expr);
90-
let expr = once(block.expr.as_deref());
90+
let expr = once(block.expr);
9191
let mut iter = stmts.chain(expr).flatten();
9292
never_loop_expr_seq(&mut iter, main_loop_id)
9393
}
@@ -100,7 +100,7 @@ fn never_loop_expr_seq<'a, T: Iterator<Item = &'a Expr<'a>>>(es: &mut T, main_lo
100100
fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> {
101101
match stmt.kind {
102102
StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some(e),
103-
StmtKind::Local(local) => local.init.as_deref(),
103+
StmtKind::Local(local) => local.init,
104104
StmtKind::Item(..) => None,
105105
}
106106
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::in_macro;
3+
use clippy_utils::source::snippet_opt;
4+
use clippy_utils::ty::is_type_diagnostic_item;
5+
use rustc_errors::Applicability;
6+
use rustc_hir::{Expr, ExprKind};
7+
use rustc_lint::{LateContext, LateLintPass};
8+
use rustc_middle::ty::TyS;
9+
use rustc_session::{declare_lint_pass, declare_tool_lint};
10+
use rustc_span::symbol::sym;
11+
12+
declare_clippy_lint! {
13+
/// ### What it does
14+
/// Checks for no-op uses of Option::{as_deref,as_deref_mut},
15+
/// for example, `Option<&T>::as_deref()` returns the same type.
16+
///
17+
/// ### Why is this bad?
18+
/// Redundant code and improving readability.
19+
///
20+
/// ### Example
21+
/// ```rust
22+
/// let a = Some(&1);
23+
/// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32>
24+
/// ```
25+
/// Could be written as:
26+
/// ```rust
27+
/// let a = Some(&1);
28+
/// let b = a;
29+
/// ```
30+
pub NEEDLESS_OPTION_AS_DEREF,
31+
complexity,
32+
"no-op use of `deref` or `deref_mut` method to `Option`."
33+
}
34+
35+
declare_lint_pass!(OptionNeedlessDeref=> [
36+
NEEDLESS_OPTION_AS_DEREF,
37+
]);
38+
39+
impl<'tcx> LateLintPass<'tcx> for OptionNeedlessDeref {
40+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
41+
if expr.span.from_expansion() {
42+
return;
43+
}
44+
if in_macro(expr.span) {
45+
return;
46+
}
47+
let typeck = cx.typeck_results();
48+
let outer_ty = typeck.expr_ty(expr);
49+
50+
if_chain! {
51+
if is_type_diagnostic_item(cx,outer_ty,sym::option_type);
52+
if let ExprKind::MethodCall(path, _, [sub_expr], _) = expr.kind;
53+
let symbol = path.ident.as_str();
54+
if symbol=="as_deref" || symbol=="as_deref_mut";
55+
if TyS::same_type( outer_ty, typeck.expr_ty(sub_expr) );
56+
then{
57+
span_lint_and_sugg(
58+
cx,
59+
NEEDLESS_OPTION_AS_DEREF,
60+
expr.span,
61+
"derefed type is same as origin",
62+
"try this",
63+
snippet_opt(cx,sub_expr.span).unwrap(),
64+
Applicability::MachineApplicable
65+
);
66+
}
67+
}
68+
}
69+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// run-rustfix
2+
3+
#[warn(clippy::needless_option_as_deref)]
4+
5+
fn main() {
6+
// should lint
7+
let _: Option<&usize> = Some(&1);
8+
let _: Option<&mut usize> = Some(&mut 1);
9+
10+
// should not lint
11+
let _ = Some(Box::new(1)).as_deref();
12+
let _ = Some(Box::new(1)).as_deref_mut();
13+
}

tests/ui/needless_option_as_deref.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// run-rustfix
2+
3+
#[warn(clippy::needless_option_as_deref)]
4+
5+
fn main() {
6+
// should lint
7+
let _: Option<&usize> = Some(&1).as_deref();
8+
let _: Option<&mut usize> = Some(&mut 1).as_deref_mut();
9+
10+
// should not lint
11+
let _ = Some(Box::new(1)).as_deref();
12+
let _ = Some(Box::new(1)).as_deref_mut();
13+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: derefed type is same as origin
2+
--> $DIR/needless_option_as_deref.rs:7:29
3+
|
4+
LL | let _: Option<&usize> = Some(&1).as_deref();
5+
| ^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&1)`
6+
|
7+
= note: `-D clippy::needless-option-as-deref` implied by `-D warnings`
8+
9+
error: derefed type is same as origin
10+
--> $DIR/needless_option_as_deref.rs:8:33
11+
|
12+
LL | let _: Option<&mut usize> = Some(&mut 1).as_deref_mut();
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&mut 1)`
14+
15+
error: aborting due to 2 previous errors
16+

0 commit comments

Comments
 (0)