]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/methods.rs
Use span_suggestion_with_applicability instead of span_suggestion
[rust.git] / clippy_lints / src / methods.rs
index bbf1f984d31d8d324af4da4ffe9832c4cb3136b0..f61995cf26509cd472c64c57fc13ae855da609f6 100644 (file)
@@ -1,15 +1,15 @@
 use matches::matches;
-use rustc::hir;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::rustc::hir;
+use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, Lint, LintContext};
+use crate::rustc::{declare_tool_lint, lint_array};
 use if_chain::if_chain;
-use rustc::ty::{self, Ty};
-use rustc::hir::def::Def;
+use crate::rustc::ty::{self, Ty};
+use crate::rustc::hir::def::Def;
 use std::borrow::Cow;
 use std::fmt;
 use std::iter;
-use syntax::ast;
-use syntax::codemap::{Span, BytePos};
+use crate::syntax::ast;
+use crate::syntax::source_map::{Span, BytePos};
 use crate::utils::{get_arg_name, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, is_self,
             is_self_ty, iter_input_pats, last_path_segment, match_def_path, match_path, match_qpath, match_trait_method,
             match_type, method_chain_args, match_var, return_ty, remove_blocks, same_tys, single_segment_path, snippet,
@@ -17,6 +17,7 @@
 use crate::utils::paths;
 use crate::utils::sugg;
 use crate::consts::{constant, Constant};
+use crate::rustc_errors::Applicability;
 
 #[derive(Clone)]
 pub struct Pass;
 ///
 /// **Example:**
 /// ```rust
-/// foo.expect(&format("Err {}: {}", err_code, err_msg))
+/// foo.expect(&format!("Err {}: {}", err_code, err_msg))
 /// ```
 /// or
 /// ```rust
-/// foo.expect(format("Err {}: {}", err_code, err_msg).as_str())
+/// foo.expect(format!("Err {}: {}", err_code, err_msg).as_str())
 /// ```
 /// this can instead be written:
 /// ```rust
 /// foo.unwrap_or_else(|_| panic!("Err {}: {}", err_code, err_msg))
 /// ```
-/// or
-/// ```rust
-/// foo.unwrap_or_else(|_| panic!(format("Err {}: {}", err_code, err_msg).as_str()))
-/// ```
 declare_clippy_lint! {
     pub EXPECT_FUN_CALL,
     perf,
 /// **Known problems:** Does not catch multi-byte unicode characters.
 ///
 /// **Example:**
-/// `_.split("x")` could be `_.split('x')
+/// `_.split("x")` could be `_.split('x')`
 declare_clippy_lint! {
     pub SINGLE_CHAR_PATTERN,
     perf,
 /// ```rust,ignore
 /// let c_str = CString::new("foo").unwrap().as_ptr();
 /// unsafe {
-/// call_some_ffi_func(c_str);
+///     call_some_ffi_func(c_str);
 /// }
 /// ```
 /// Here `c_str` point to a freed address. The correct use would be:
@@ -714,7 +711,7 @@ fn get_lints(&self) -> LintArray {
 }
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
-    #[allow(cyclomatic_complexity)]
+    #[allow(clippy::cyclomatic_complexity)]
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
         if in_macro(expr.span) {
             return;
@@ -784,7 +781,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
                 }
 
                 match self_ty.sty {
-                    ty::TyRef(_, ty, _) if ty.sty == ty::TyStr => for &(method, pos) in &PATTERN_METHODS {
+                    ty::Ref(_, ty, _) if ty.sty == ty::Str => for &(method, pos) in &PATTERN_METHODS {
                         if method_call.ident.name == method && args.len() > pos {
                             lint_single_char_pattern(cx, expr, &args[pos]);
                         }
@@ -922,7 +919,7 @@ fn check_unwrap_or_default(
     }
 
     /// Check for `*or(foo())`.
-    #[allow(too_many_arguments)]
+    #[allow(clippy::too_many_arguments)]
     fn check_general_case(
         cx: &LateContext<'_, '_>,
         name: &str,
@@ -1047,10 +1044,21 @@ fn check_general_case(
             return;
         }
 
-        // don't lint for constant values
-        let owner_def = cx.tcx.hir.get_parent_did(arg.id);
-        let promotable = cx.tcx.rvalue_promotable_map(owner_def).contains(&arg.hir_id.local_id);
-        if promotable {
+        fn is_call(node: &hir::ExprKind) -> bool {
+            match node {
+                hir::ExprKind::AddrOf(_, expr) => {
+                    is_call(&expr.node)
+                },
+                hir::ExprKind::Call(..)
+                | hir::ExprKind::MethodCall(..)
+                // These variants are debatable or require further examination
+                | hir::ExprKind::If(..)
+                | hir::ExprKind::Match(..) => true,
+                _ => false,
+            }
+        }
+
+        if !is_call(&arg.node) {
             return;
         }
 
@@ -1102,8 +1110,8 @@ fn check_general_case(
 /// Checks for the `CLONE_ON_COPY` lint.
 fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Expr, arg_ty: Ty<'_>) {
     let ty = cx.tables.expr_ty(expr);
-    if let ty::TyRef(_, inner, _) = arg_ty.sty {
-        if let ty::TyRef(_, innermost, _) = inner.sty {
+    if let ty::Ref(_, inner, _) = arg_ty.sty {
+        if let ty::Ref(_, innermost, _) = inner.sty {
             span_lint_and_then(
                 cx,
                 CLONE_DOUBLE_REF,
@@ -1113,15 +1121,25 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
                 |db| if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
                     let mut ty = innermost;
                     let mut n = 0;
-                    while let ty::TyRef(_, inner, _) = ty.sty {
+                    while let ty::Ref(_, inner, _) = ty.sty {
                         ty = inner;
                         n += 1;
                     }
                     let refs: String = iter::repeat('&').take(n + 1).collect();
                     let derefs: String = iter::repeat('*').take(n).collect();
                     let explicit = format!("{}{}::clone({})", refs, ty, snip);
-                    db.span_suggestion(expr.span, "try dereferencing it", format!("{}({}{}).clone()", refs, derefs, snip.deref()));
-                    db.span_suggestion(expr.span, "or try being explicit about what type to clone", explicit);
+                    db.span_suggestion_with_applicability(
+                            expr.span,
+                            "try dereferencing it",
+                            format!("{}({}{}).clone()", refs, derefs, snip.deref()),
+                            Applicability::Unspecified,
+                            );
+                    db.span_suggestion_with_applicability(
+                            expr.span, 
+                            "or try being explicit about what type to clone", 
+                            explicit,
+                            Applicability::Unspecified,
+                            );
                 },
             );
             return; // don't report clone_on_copy
@@ -1131,17 +1149,17 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
     if is_copy(cx, ty) {
         let snip;
         if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) {
-            if let ty::TyRef(..) = cx.tables.expr_ty(arg).sty {
+            if let ty::Ref(..) = cx.tables.expr_ty(arg).sty {
                 let parent = cx.tcx.hir.get_parent_node(expr.id);
                 match cx.tcx.hir.get(parent) {
-                    hir::map::NodeExpr(parent) => match parent.node {
+                    hir::Node::Expr(parent) => match parent.node {
                         // &*x is a nop, &x.clone() is not
                         hir::ExprKind::AddrOf(..) |
                         // (*x).func() is useless, x.clone().func() can work in case func borrows mutably
                         hir::ExprKind::MethodCall(..) => return,
                         _ => {},
                     }
-                    hir::map::NodeStmt(stmt) => {
+                    hir::Node::Stmt(stmt) => {
                         if let hir::StmtKind::Decl(ref decl, _) = stmt.node {
                             if let hir::DeclKind::Local(ref loc) = decl.node {
                                 if let hir::PatKind::Ref(..) = loc.pat.node {
@@ -1162,7 +1180,12 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
         }
         span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |db| {
             if let Some((text, snip)) = snip {
-                db.span_suggestion(expr.span, text, snip);
+                db.span_suggestion_with_applicability(
+                    expr.span,
+                    text,
+                    snip,
+                    Applicability::Unspecified,
+                    );
             }
         });
     }
@@ -1171,7 +1194,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
 fn lint_clone_on_ref_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Expr) {
     let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(arg));
 
-    if let ty::TyAdt(_, subst) = obj_ty.sty {
+    if let ty::Adt(_, subst) = obj_ty.sty {
         let caller_type = if match_type(cx, obj_ty, &paths::RC) {
             "Rc"
         } else if match_type(cx, obj_ty, &paths::ARC) {
@@ -1199,7 +1222,7 @@ fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::E
     if let Some(arglists) = method_chain_args(arg, &["chars"]) {
         let target = &arglists[0][0];
         let self_ty = walk_ptrs_ty(cx.tables.expr_ty(target));
-        let ref_str = if self_ty.sty == ty::TyStr {
+        let ref_str = if self_ty.sty == ty::Str {
             ""
         } else if match_type(cx, self_ty, &paths::STRING) {
             "&"
@@ -1300,7 +1323,7 @@ fn check_fold_with_op(
 
             then {
                 // Span containing `.fold(...)`
-                let next_point = cx.sess().codemap().next_point(fold_args[0].span);
+                let next_point = cx.sess().source_map().next_point(fold_args[0].span);
                 let fold_span = next_point.with_hi(fold_args[2].span.hi() + BytePos(1));
 
                 let sugg = if replacement_has_args {
@@ -1431,11 +1454,11 @@ fn lint_iter_skip_next(cx: &LateContext<'_, '_>, expr: &hir::Expr) {
 fn derefs_to_slice(cx: &LateContext<'_, '_>, expr: &hir::Expr, ty: Ty<'_>) -> Option<sugg::Sugg<'static>> {
     fn may_slice(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool {
         match ty.sty {
-            ty::TySlice(_) => true,
-            ty::TyAdt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
-            ty::TyAdt(..) => match_type(cx, ty, &paths::VEC),
-            ty::TyArray(_, size) => size.assert_usize(cx.tcx).expect("array length") < 32,
-            ty::TyRef(_, inner, _) => may_slice(cx, inner),
+            ty::Slice(_) => true,
+            ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
+            ty::Adt(..) => match_type(cx, ty, &paths::VEC),
+            ty::Array(_, size) => size.assert_usize(cx.tcx).expect("array length") < 32,
+            ty::Ref(_, inner, _) => may_slice(cx, inner),
             _ => false,
         }
     }
@@ -1448,9 +1471,9 @@ fn may_slice(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool {
         }
     } else {
         match ty.sty {
-            ty::TySlice(_) => sugg::Sugg::hir_opt(cx, expr),
-            ty::TyAdt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => sugg::Sugg::hir_opt(cx, expr),
-            ty::TyRef(_, inner, _) => if may_slice(cx, inner) {
+            ty::Slice(_) => sugg::Sugg::hir_opt(cx, expr),
+            ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => sugg::Sugg::hir_opt(cx, expr),
+            ty::Ref(_, inner, _) => if may_slice(cx, inner) {
                 sugg::Sugg::hir_opt(cx, expr)
             } else {
                 None
@@ -1632,7 +1655,12 @@ fn lint_map_or_none<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr,
             let map_or_func_snippet = snippet(cx, map_or_args[2].span, "..");
             let hint = format!("{0}.and_then({1})", map_or_self_snippet, map_or_func_snippet);
             span_lint_and_then(cx, OPTION_MAP_OR_NONE, expr.span, msg, |db| {
-                db.span_suggestion(expr.span, "try using and_then instead", hint);
+                db.span_suggestion_with_applicability(
+                        expr.span,
+                        "try using and_then instead",
+                        hint,
+                        Applicability::Unspecified,
+                        );
             });
         }
     }
@@ -1801,7 +1829,7 @@ fn lint_chars_cmp(
         then {
             let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0]));
 
-            if self_ty.sty != ty::TyStr {
+            if self_ty.sty != ty::Str {
                 return false;
             }
 
@@ -1928,7 +1956,7 @@ fn lint_asref(cx: &LateContext<'_, '_>, expr: &hir::Expr, call_name: &str, as_re
 
 /// Given a `Result<T, E>` type, return its error type (`E`).
 fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> {
-    if let ty::TyAdt(_, substs) = ty.sty {
+    if let ty::Adt(_, substs) = ty.sty {
         if match_type(cx, ty, &paths::RESULT) {
             substs.types().nth(1)
         } else {
@@ -1952,7 +1980,7 @@ enum Convention {
     StartsWith(&'static str),
 }
 
-#[cfg_attr(rustfmt, rustfmt_skip)]
+#[rustfmt::skip]
 const CONVENTIONS: [(Convention, &[SelfKind]); 6] = [
     (Convention::Eq("new"), &[SelfKind::No]),
     (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]),
@@ -1962,7 +1990,7 @@ enum Convention {
     (Convention::StartsWith("to_"), &[SelfKind::Ref]),
 ];
 
-#[cfg_attr(rustfmt, rustfmt_skip)]
+#[rustfmt::skip]
 const TRAIT_METHODS: [(&str, usize, SelfKind, OutType, &str); 30] = [
     ("add", 2, SelfKind::Value, OutType::Any, "std::ops::Add"),
     ("as_mut", 1, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"),
@@ -1996,7 +2024,7 @@ enum Convention {
     ("sub", 2, SelfKind::Value, OutType::Any, "std::ops::Sub"),
 ];
 
-#[cfg_attr(rustfmt, rustfmt_skip)]
+#[rustfmt::skip]
 const PATTERN_METHODS: [(&str, usize); 17] = [
     ("contains", 1),
     ("starts_with", 1),