Skip to content

Commit

Permalink
option_needless_deref
Browse files Browse the repository at this point in the history
  • Loading branch information
lengyijun committed Aug 24, 2021
1 parent 15b1c6f commit d2d1794
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2848,6 +2848,7 @@ Released 2018-09-13
[`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
[`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none
[`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn
[`option_needless_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_needless_deref
[`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option
[`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call
[`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
Expand Down
5 changes: 5 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ mod nonstandard_macro_braces;
mod open_options;
mod option_env_unwrap;
mod option_if_let_else;
mod option_needless_deref;
mod overflow_check_conditional;
mod panic_in_result_fn;
mod panic_unimplemented;
Expand Down Expand Up @@ -865,6 +866,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
open_options::NONSENSICAL_OPEN_OPTIONS,
option_env_unwrap::OPTION_ENV_UNWRAP,
option_if_let_else::OPTION_IF_LET_ELSE,
option_needless_deref::OPTION_NEEDLESS_DEREF,
overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
panic_in_result_fn::PANIC_IN_RESULT_FN,
panic_unimplemented::PANIC,
Expand Down Expand Up @@ -1387,6 +1389,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(option_needless_deref::OPTION_NEEDLESS_DEREF),
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
LintId::of(precedence::PRECEDENCE),
Expand Down Expand Up @@ -1640,6 +1643,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
LintId::of(no_effect::NO_EFFECT),
LintId::of(no_effect::UNNECESSARY_OPERATION),
LintId::of(option_needless_deref::OPTION_NEEDLESS_DEREF),
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
LintId::of(precedence::PRECEDENCE),
Expand Down Expand Up @@ -1863,6 +1867,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box ptr::Ptr);
store.register_late_pass(|| box ptr_eq::PtrEq);
store.register_late_pass(|| box needless_bool::NeedlessBool);
store.register_late_pass(|| box option_needless_deref::OptionNeedlessDeref);
store.register_late_pass(|| box needless_bool::BoolComparison);
store.register_late_pass(|| box needless_for_each::NeedlessForEach);
store.register_late_pass(|| box approx_const::ApproxConstant);
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/loops/never_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult

fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
let stmts = block.stmts.iter().map(stmt_to_expr);
let expr = once(block.expr.as_deref());
let expr = once(block.expr);
let mut iter = stmts.chain(expr).flatten();
never_loop_expr_seq(&mut iter, main_loop_id)
}
Expand All @@ -100,7 +100,7 @@ fn never_loop_expr_seq<'a, T: Iterator<Item = &'a Expr<'a>>>(es: &mut T, main_lo
fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> {
match stmt.kind {
StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some(e),
StmtKind::Local(local) => local.init.as_deref(),
StmtKind::Local(local) => local.init,
StmtKind::Item(..) => None,
}
}
Expand Down
71 changes: 71 additions & 0 deletions clippy_lints/src/option_needless_deref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_macro;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::TyS;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::sym;

declare_clippy_lint! {
/// ### What it does
/// Checks for no-op uses of {Option,Result}::{as_deref,as_deref_mut}.
///
/// ### Why is this bad?
/// Removes useless code, removing clutter and improving readability.
///
/// ### Example
/// ```rust
/// let a = Some(&1);
/// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32>
/// ```
/// Could be written as:
/// ```rust
/// let a = Some(&1);
/// let b = a;
/// ```
pub OPTION_NEEDLESS_DEREF,
complexity,
"Explicit use of deref or deref_mut method while not in a method chain."
}

declare_lint_pass!(OptionNeedlessDeref=> [
OPTION_NEEDLESS_DEREF,
]);

impl<'tcx> LateLintPass<'tcx> for OptionNeedlessDeref {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if expr.span.from_expansion() {
return;
}
if in_macro(expr.span) {
return;
}
let typeck = cx.typeck_results();
let outer_ty = typeck.expr_ty(expr);

if_chain! {
if is_type_diagnostic_item(cx,outer_ty,sym::option_type) ||
is_type_diagnostic_item(cx,outer_ty,sym::result_type) ;
if let ExprKind::MethodCall(path, _, [sub_expr], _) = expr.kind;
let symbol = &*path.ident.as_str();
if symbol=="as_deref" || symbol=="as_deref_mut";
if TyS::same_type( outer_ty, typeck.expr_ty(sub_expr) );
then{

span_lint_and_sugg(
cx,
OPTION_NEEDLESS_DEREF,
expr.span,
"derefed type is same as origin",
"try this",
snippet_opt(cx,sub_expr.span).unwrap(),
Applicability::MachineApplicable
);

}
}
}
}
13 changes: 13 additions & 0 deletions tests/ui/option_needless_deref.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// run-rustfix

#[warn(clippy::option_needless_deref)]

fn main() {
// should lint
let _: Option<&usize> = Some(&1);
let _: Option<&mut usize> = Some(&mut 1);

// should not lint
let _ = Some(Box::new(1)).as_deref();
let _ = Some(Box::new(1)).as_deref_mut();
}
13 changes: 13 additions & 0 deletions tests/ui/option_needless_deref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// run-rustfix

#[warn(clippy::option_needless_deref)]

fn main() {
// should lint
let _: Option<&usize> = Some(&1).as_deref();
let _: Option<&mut usize> = Some(&mut 1).as_deref_mut();

// should not lint
let _ = Some(Box::new(1)).as_deref();
let _ = Some(Box::new(1)).as_deref_mut();
}
16 changes: 16 additions & 0 deletions tests/ui/option_needless_deref.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error: derefed type is same as origin
--> $DIR/option_needless_deref.rs:7:29
|
LL | let _: Option<&usize> = Some(&1).as_deref();
| ^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&1)`
|
= note: `-D clippy::option-needless-deref` implied by `-D warnings`

error: derefed type is same as origin
--> $DIR/option_needless_deref.rs:8:33
|
LL | let _: Option<&mut usize> = Some(&mut 1).as_deref_mut();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&mut 1)`

error: aborting due to 2 previous errors

0 comments on commit d2d1794

Please sign in to comment.