1 use crate::utils
::{get_parent_expr, implements_trait, snippet, span_lint_and_sugg}
;
2 use if_chain
::if_chain
;
3 use rustc_ast
::util
::parser
::{ExprPrecedence, PREC_POSTFIX, PREC_PREFIX}
;
4 use rustc_errors
::Applicability
;
5 use rustc_hir
::{Expr, ExprKind}
;
6 use rustc_lint
::{LateContext, LateLintPass}
;
7 use rustc_session
::{declare_lint_pass, declare_tool_lint}
;
8 use rustc_span
::source_map
::Span
;
10 declare_clippy_lint
! {
11 /// **What it does:** Checks for explicit `deref()` or `deref_mut()` method calls.
13 /// **Why is this bad?** Dereferencing by `&*x` or `&mut *x` is clearer and more concise,
14 /// when not part of a method chain.
18 /// use std::ops::Deref;
19 /// let a: &mut String = &mut String::from("foo");
20 /// let b: &str = a.deref();
22 /// Could be written as:
24 /// let a: &mut String = &mut String::from("foo");
28 /// This lint excludes
30 /// let _ = d.unwrap().deref();
32 pub EXPLICIT_DEREF_METHODS
,
34 "Explicit use of deref or deref_mut method while not in a method chain."
37 declare_lint_pass
!(Dereferencing
=> [
38 EXPLICIT_DEREF_METHODS
41 impl<'tcx
> LateLintPass
<'tcx
> for Dereferencing
{
42 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, expr
: &'tcx Expr
<'_
>) {
44 if !expr
.span
.from_expansion();
45 if let ExprKind
::MethodCall(ref method_name
, _
, ref args
, _
) = &expr
.kind
;
49 if let Some(parent_expr
) = get_parent_expr(cx
, expr
) {
50 // Check if we have the whole call chain here
51 if let ExprKind
::MethodCall(..) = parent_expr
.kind
{
54 // Check for Expr that we don't want to be linted
55 let precedence
= parent_expr
.precedence();
57 // Lint a Call is ok though
58 ExprPrecedence
::Call
| ExprPrecedence
::AddrOf
=> (),
60 if precedence
.order() >= PREC_PREFIX
&& precedence
.order() <= PREC_POSTFIX
{
66 let name
= method_name
.ident
.as_str();
67 lint_deref(cx
, &*name
, &args
[0], args
[0].span
, expr
.span
);
73 fn lint_deref(cx
: &LateContext
<'_
>, method_name
: &str, call_expr
: &Expr
<'_
>, var_span
: Span
, expr_span
: Span
) {
76 let impls_deref_trait
= cx
.tcx
.lang_items().deref_trait().map_or(false, |id
| {
77 implements_trait(cx
, cx
.typeck_results().expr_ty(&call_expr
), id
, &[])
79 if impls_deref_trait
{
82 EXPLICIT_DEREF_METHODS
,
84 "explicit deref method call",
86 format
!("&*{}", &snippet(cx
, var_span
, "..")),
87 Applicability
::MachineApplicable
,
92 let impls_deref_mut_trait
= cx
.tcx
.lang_items().deref_mut_trait().map_or(false, |id
| {
93 implements_trait(cx
, cx
.typeck_results().expr_ty(&call_expr
), id
, &[])
95 if impls_deref_mut_trait
{
98 EXPLICIT_DEREF_METHODS
,
100 "explicit deref_mut method call",
102 format
!("&mut *{}", &snippet(cx
, var_span
, "..")),
103 Applicability
::MachineApplicable
,