]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #4084 - mikerite:fix-4019, r=oli-obk
authorbors <bors@rust-lang.org>
Tue, 14 May 2019 11:26:16 +0000 (11:26 +0000)
committerbors <bors@rust-lang.org>
Tue, 14 May 2019 11:26:16 +0000 (11:26 +0000)
Fix 4019

Fixes #4019

1  2 
clippy_lints/src/methods/mod.rs

index 3e093cf31094e8cf01a2f78e489f8cdef8655744,fb13598dea9ab5522e715e4c697f84ab66cfd449..8621d112a9dda43d48cda0d8b3f09b5ed1d08d56
@@@ -6,26 -6,25 +6,27 @@@ use std::fmt
  use std::iter;
  
  use if_chain::if_chain;
 +use lazy_static::lazy_static;
  use matches::matches;
  use rustc::hir;
  use rustc::hir::def::{DefKind, Res};
+ use rustc::hir::intravisit::{self, Visitor};
  use rustc::lint::{in_external_macro, LateContext, LateLintPass, Lint, LintArray, LintContext, LintPass};
  use rustc::ty::{self, Predicate, Ty};
  use rustc::{declare_lint_pass, declare_tool_lint};
  use rustc_errors::Applicability;
  use syntax::ast;
  use syntax::source_map::{BytePos, Span};
 -use syntax::symbol::LocalInternedString;
 +use syntax::symbol::{LocalInternedString, Symbol};
  
  use crate::utils::paths;
  use crate::utils::sugg;
 +use crate::utils::sym;
  use crate::utils::{
      get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy,
 -    is_ctor_function, is_expn_of, is_self, is_self_ty, iter_input_pats, last_path_segment, match_path, match_qpath,
 -    match_trait_method, match_type, match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys,
 -    single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
 +    is_ctor_function, 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, match_var, method_calls, method_chain_args, remove_blocks, return_ty,
 +    same_tys, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
      span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
  };
  
@@@ -907,20 -906,20 +908,20 @@@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> f
                  lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
  
                  let self_ty = cx.tables.expr_ty_adjusted(&args[0]);
 -                if args.len() == 1 && method_call.ident.name == "clone" {
 +                if args.len() == 1 && method_call.ident.name == *sym::clone {
                      lint_clone_on_copy(cx, expr, &args[0], self_ty);
                      lint_clone_on_ref_ptr(cx, expr, &args[0]);
                  }
  
                  match self_ty.sty {
                      ty::Ref(_, ty, _) if ty.sty == ty::Str => {
 -                        for &(method, pos) in &PATTERN_METHODS {
 +                        for &(method, pos) in PATTERN_METHODS.iter() {
                              if method_call.ident.name == method && args.len() > pos {
                                  lint_single_char_pattern(cx, expr, &args[pos]);
                              }
                          }
                      },
 -                    ty::Ref(..) if method_call.ident.name == "into_iter" => {
 +                    ty::Ref(..) if method_call.ident.name == *sym::into_iter => {
                          lint_into_iter(cx, expr, self_ty, *method_span);
                      },
                      _ => (),
              then {
                  if cx.access_levels.is_exported(implitem.hir_id) {
                  // check missing trait implementations
 -                    for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS {
 +                    for &(method_name, n_args, self_kind, out_type, trait_name) in TRAIT_METHODS.iter() {
                          if name == method_name &&
                          sig.decl.inputs.len() == n_args &&
                          out_type.matches(cx, &sig.decl.output) &&
                  }
              }
  
 -            if name == "new" && !same_tys(cx, ret_ty, ty) {
 +            if name == *sym::new && !same_tys(cx, ret_ty, ty) {
                  span_lint(
                      cx,
                      NEW_RET_NO_SELF,
  
  /// Checks for the `OR_FUN_CALL` lint.
  #[allow(clippy::too_many_lines)]
- fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) {
+ fn lint_or_fun_call<'a, 'tcx: 'a>(
+     cx: &LateContext<'a, 'tcx>,
+     expr: &hir::Expr,
+     method_span: Span,
+     name: &str,
+     args: &'tcx [hir::Expr],
+ ) {
+     // Searches an expression for method calls or function calls that aren't ctors
+     struct FunCallFinder<'a, 'tcx: 'a> {
+         cx: &'a LateContext<'a, 'tcx>,
+         found: bool,
+     }
+     impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> {
+         fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
+             let call_found = match &expr.node {
+                 // ignore enum and struct constructors
+                 hir::ExprKind::Call(..) => !is_ctor_function(self.cx, expr),
+                 hir::ExprKind::MethodCall(..) => true,
+                 _ => false,
+             };
+             if call_found {
+                 // don't lint for constant values
+                 let owner_def = self.cx.tcx.hir().get_parent_did_by_hir_id(expr.hir_id);
+                 let promotable = self
+                     .cx
+                     .tcx
+                     .rvalue_promotable_map(owner_def)
+                     .contains(&expr.hir_id.local_id);
+                 if !promotable {
+                     self.found |= true;
+                 }
+             }
+             if !self.found {
+                 intravisit::walk_expr(self, expr);
+             }
+         }
+         fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
+             intravisit::NestedVisitorMap::None
+         }
+     }
      /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
      fn check_unwrap_or_default(
          cx: &LateContext<'_, '_>,
  
                  if ["default", "new"].contains(&path) {
                      let arg_ty = cx.tables.expr_ty(arg);
 -                    let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT) {
 +                    let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &*paths::DEFAULT_TRAIT)
 +                    {
                          default_trait_id
                      } else {
                          return false;
  
      /// Checks for `*or(foo())`.
      #[allow(clippy::too_many_arguments)]
-     fn check_general_case(
-         cx: &LateContext<'_, '_>,
+     fn check_general_case<'a, 'tcx: 'a>(
+         cx: &LateContext<'a, 'tcx>,
          name: &str,
          method_span: Span,
          fun_span: Span,
          self_expr: &hir::Expr,
-         arg: &hir::Expr,
+         arg: &'tcx hir::Expr,
          or_has_args: bool,
          span: Span,
      ) {
          // (path, fn_has_argument, methods, suffix)
          let know_types: &[(&[_], _, &[_], _)] = &[
 -            (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
 -            (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
 -            (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
 -            (&paths::RESULT, true, &["or", "unwrap_or"], "else"),
 +            (&*paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
 +            (&*paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
 +            (&*paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
 +            (&*paths::RESULT, true, &["or", "unwrap_or"], "else"),
          ];
  
          // early check if the name is one we care about
              return;
          }
  
-         // ignore enum and struct constructors
-         if is_ctor_function(cx, &arg) {
-             return;
-         }
-         // don't lint for constant values
-         let owner_def = cx.tcx.hir().get_parent_did_by_hir_id(arg.hir_id);
-         let promotable = cx.tcx.rvalue_promotable_map(owner_def).contains(&arg.hir_id.local_id);
-         if promotable {
+         let mut finder = FunCallFinder { cx: &cx, found: false };
+         finder.visit_expr(&arg);
+         if !finder.found {
              return;
          }
  
@@@ -1209,11 -1245,11 +1248,11 @@@ fn lint_expect_fun_call(cx: &LateContex
                  hir::ExprKind::AddrOf(_, expr) => expr,
                  hir::ExprKind::MethodCall(method_name, _, call_args) => {
                      if call_args.len() == 1
 -                        && (method_name.ident.name == "as_str" || method_name.ident.name == "as_ref")
 +                        && (method_name.ident.name == *sym::as_str || method_name.ident.name == *sym::as_ref)
                          && {
                              let arg_type = cx.tables.expr_ty(&call_args[0]);
                              let base_type = walk_ptrs_ty(arg_type);
 -                            base_type.sty == ty::Str || match_type(cx, base_type, &paths::STRING)
 +                            base_type.sty == ty::Str || match_type(cx, base_type, &*paths::STRING)
                          }
                      {
                          &call_args[0]
      // converted to string.
      fn requires_to_string(cx: &LateContext<'_, '_>, arg: &hir::Expr) -> bool {
          let arg_ty = cx.tables.expr_ty(arg);
 -        if match_type(cx, arg_ty, &paths::STRING) {
 +        if match_type(cx, arg_ty, &*paths::STRING) {
              return false;
          }
          if let ty::Ref(ty::ReStatic, ty, ..) = arg_ty.sty {
      }
  
      let receiver_type = cx.tables.expr_ty(&args[0]);
 -    let closure_args = if match_type(cx, receiver_type, &paths::OPTION) {
 +    let closure_args = if match_type(cx, receiver_type, &*paths::OPTION) {
          "||"
 -    } else if match_type(cx, receiver_type, &paths::RESULT) {
 +    } else if match_type(cx, receiver_type, &*paths::RESULT) {
          "|_|"
      } else {
          return;
  
      //Special handling for `format!` as arg_root
      if let hir::ExprKind::Call(ref inner_fun, ref inner_args) = arg_root.node {
 -        if is_expn_of(inner_fun.span, "format").is_some() && inner_args.len() == 1 {
 +        if is_expn_of(inner_fun.span, *sym::format).is_some() && inner_args.len() == 1 {
              if let hir::ExprKind::Call(_, format_args) = &inner_args[0].node {
                  let fmt_spec = &format_args[0];
                  let fmt_args = &format_args[1];
@@@ -1436,11 -1472,11 +1475,11 @@@ fn lint_clone_on_ref_ptr(cx: &LateConte
      let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(arg));
  
      if let ty::Adt(_, subst) = obj_ty.sty {
 -        let caller_type = if match_type(cx, obj_ty, &paths::RC) {
 +        let caller_type = if match_type(cx, obj_ty, &*paths::RC) {
              "Rc"
 -        } else if match_type(cx, obj_ty, &paths::ARC) {
 +        } else if match_type(cx, obj_ty, &*paths::ARC) {
              "Arc"
 -        } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) {
 +        } else if match_type(cx, obj_ty, &*paths::WEAK_RC) || match_type(cx, obj_ty, &*paths::WEAK_ARC) {
              "Weak"
          } else {
              return;
  
  fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
      let arg = &args[1];
 -    if let Some(arglists) = method_chain_args(arg, &["chars"]) {
 +    if let Some(arglists) = method_chain_args(arg, &[*sym::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::Str {
              ""
 -        } else if match_type(cx, self_ty, &paths::STRING) {
 +        } else if match_type(cx, self_ty, &*paths::STRING) {
              "&"
          } else {
              return;
  
  fn lint_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
      let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
 -    if match_type(cx, obj_ty, &paths::STRING) {
 +    if match_type(cx, obj_ty, &*paths::STRING) {
          lint_string_extend(cx, expr, args);
      }
  }
@@@ -1507,7 -1543,7 +1546,7 @@@ fn lint_cstring_as_ptr(cx: &LateContext
          if args.len() == 1;
          if let hir::ExprKind::Path(ref path) = fun.node;
          if let Res::Def(DefKind::Method, did) = cx.tables.qpath_res(path, fun.hir_id);
 -        if cx.match_def_path(did, &paths::CSTRING_NEW);
 +        if match_def_path(cx, did, &*paths::CSTRING_NEW);
          then {
              span_lint_and_then(
                  cx,
  }
  
  fn lint_iter_cloned_collect<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, iter_args: &'tcx [hir::Expr]) {
 -    if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC) {
 +    if match_type(cx, cx.tables.expr_ty(expr), &*paths::VEC) {
          if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])) {
              if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()) {
                  span_lint_and_sugg(
@@@ -1601,7 -1637,7 +1640,7 @@@ fn lint_unnecessary_fold(cx: &LateConte
      }
  
      // Check that this is a call to Iterator::fold rather than just some function called fold
 -    if !match_trait_method(cx, expr, &paths::ITERATOR) {
 +    if !match_trait_method(cx, expr, &*paths::ITERATOR) {
          return;
      }
  
@@@ -1627,9 -1663,9 +1666,9 @@@ fn lint_iter_nth<'a, 'tcx>(cx: &LateCon
      let mut_str = if is_mut { "_mut" } else { "" };
      let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() {
          "slice"
 -    } else if match_type(cx, cx.tables.expr_ty(&iter_args[0]), &paths::VEC) {
 +    } else if match_type(cx, cx.tables.expr_ty(&iter_args[0]), &*paths::VEC) {
          "Vec"
 -    } else if match_type(cx, cx.tables.expr_ty(&iter_args[0]), &paths::VEC_DEQUE) {
 +    } else if match_type(cx, cx.tables.expr_ty(&iter_args[0]), &*paths::VEC_DEQUE) {
          "VecDeque"
      } else {
          return; // caller is not a type that we want to lint
@@@ -1660,16 -1696,16 +1699,16 @@@ fn lint_get_unwrap<'a, 'tcx>(cx: &LateC
      let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
          needs_ref = get_args_str.parse::<usize>().is_ok();
          "slice"
 -    } else if match_type(cx, expr_ty, &paths::VEC) {
 +    } else if match_type(cx, expr_ty, &*paths::VEC) {
          needs_ref = get_args_str.parse::<usize>().is_ok();
          "Vec"
 -    } else if match_type(cx, expr_ty, &paths::VEC_DEQUE) {
 +    } else if match_type(cx, expr_ty, &*paths::VEC_DEQUE) {
          needs_ref = get_args_str.parse::<usize>().is_ok();
          "VecDeque"
 -    } else if !is_mut && match_type(cx, expr_ty, &paths::HASHMAP) {
 +    } else if !is_mut && match_type(cx, expr_ty, &*paths::HASHMAP) {
          needs_ref = true;
          "HashMap"
 -    } else if !is_mut && match_type(cx, expr_ty, &paths::BTREEMAP) {
 +    } else if !is_mut && match_type(cx, expr_ty, &*paths::BTREEMAP) {
          needs_ref = true;
          "BTreeMap"
      } else {
  
  fn lint_iter_skip_next(cx: &LateContext<'_, '_>, expr: &hir::Expr) {
      // lint if caller of skip is an Iterator
 -    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +    if match_trait_method(cx, expr, &*paths::ITERATOR) {
          span_lint(
              cx,
              ITER_SKIP_NEXT,
@@@ -1740,7 -1776,7 +1779,7 @@@ fn derefs_to_slice<'a, 'tcx>
          match ty.sty {
              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::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,
      }
  
      if let hir::ExprKind::MethodCall(ref path, _, ref args) = expr.node {
 -        if path.ident.name == "iter" && may_slice(cx, cx.tables.expr_ty(&args[0])) {
 +        if path.ident.name == *sym::iter && may_slice(cx, cx.tables.expr_ty(&args[0])) {
              Some(&args[0])
          } else {
              None
  fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, unwrap_args: &[hir::Expr]) {
      let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&unwrap_args[0]));
  
 -    let mess = if match_type(cx, obj_ty, &paths::OPTION) {
 +    let mess = if match_type(cx, obj_ty, &*paths::OPTION) {
          Some((OPTION_UNWRAP_USED, "an Option", "None"))
 -    } else if match_type(cx, obj_ty, &paths::RESULT) {
 +    } else if match_type(cx, obj_ty, &*paths::RESULT) {
          Some((RESULT_UNWRAP_USED, "a Result", "Err"))
      } else {
          None
  /// lint use of `ok().expect()` for `Result`s
  fn lint_ok_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr, ok_args: &[hir::Expr]) {
      // lint if the caller of `ok()` is a `Result`
 -    if match_type(cx, cx.tables.expr_ty(&ok_args[0]), &paths::RESULT) {
 +    if match_type(cx, cx.tables.expr_ty(&ok_args[0]), &*paths::RESULT) {
          let result_type = cx.tables.expr_ty(&ok_args[0]);
          if let Some(error_type) = get_error_type(cx, result_type) {
              if has_debug_impl(error_type, cx) {
  /// lint use of `map().flatten()` for `Iterators`
  fn lint_map_flatten<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_args: &'tcx [hir::Expr]) {
      // lint if caller of `.map().flatten()` is an Iterator
 -    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +    if match_trait_method(cx, expr, &*paths::ITERATOR) {
          let msg = "called `map(..).flatten()` on an `Iterator`. \
                     This is more succinctly expressed by calling `.flat_map(..)`";
          let self_snippet = snippet(cx, map_args[0].span, "..");
@@@ -1842,8 -1878,8 +1881,8 @@@ fn lint_map_unwrap_or_else<'a, 'tcx>
      unwrap_args: &'tcx [hir::Expr],
  ) {
      // lint if the caller of `map()` is an `Option`
 -    let is_option = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION);
 -    let is_result = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::RESULT);
 +    let is_option = match_type(cx, cx.tables.expr_ty(&map_args[0]), &*paths::OPTION);
 +    let is_result = match_type(cx, cx.tables.expr_ty(&map_args[0]), &*paths::RESULT);
      if is_option || is_result {
          // lint message
          let msg = if is_option {
  
  /// lint use of `_.map_or(None, _)` for `Option`s
  fn lint_map_or_none<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_or_args: &'tcx [hir::Expr]) {
 -    if match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &paths::OPTION) {
 +    if match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &*paths::OPTION) {
          // check if the first non-self argument to map_or() is None
          let map_or_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].node {
 -            match_qpath(qpath, &paths::OPTION_NONE)
 +            match_qpath(qpath, &*paths::OPTION_NONE)
          } else {
              false
          };
  /// lint use of `filter().next()` for `Iterators`
  fn lint_filter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, filter_args: &'tcx [hir::Expr]) {
      // lint if caller of `.filter().next()` is an Iterator
 -    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +    if match_trait_method(cx, expr, &*paths::ITERATOR) {
          let msg = "called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling \
                     `.find(p)` instead.";
          let filter_snippet = snippet(cx, filter_args[1].span, "..");
@@@ -1953,7 -1989,7 +1992,7 @@@ fn lint_filter_map<'a, 'tcx>
      _map_args: &'tcx [hir::Expr],
  ) {
      // lint if caller of `.filter().map()` is an Iterator
 -    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +    if match_trait_method(cx, expr, &*paths::ITERATOR) {
          let msg = "called `filter(p).map(q)` on an `Iterator`. \
                     This is more succinctly expressed by calling `.filter_map(..)` instead.";
          span_lint(cx, FILTER_MAP, expr.span, msg);
  
  /// lint use of `filter_map().next()` for `Iterators`
  fn lint_filter_map_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, filter_args: &'tcx [hir::Expr]) {
 -    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +    if match_trait_method(cx, expr, &*paths::ITERATOR) {
          let msg = "called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling \
                     `.find_map(p)` instead.";
          let filter_snippet = snippet(cx, filter_args[1].span, "..");
@@@ -1989,7 -2025,7 +2028,7 @@@ fn lint_find_map<'a, 'tcx>
      map_args: &'tcx [hir::Expr],
  ) {
      // lint if caller of `.filter().map()` is an Iterator
 -    if match_trait_method(cx, &map_args[0], &paths::ITERATOR) {
 +    if match_trait_method(cx, &map_args[0], &*paths::ITERATOR) {
          let msg = "called `find(p).map(q)` on an `Iterator`. \
                     This is more succinctly expressed by calling `.find_map(..)` instead.";
          span_lint(cx, FIND_MAP, expr.span, msg);
@@@ -2004,7 -2040,7 +2043,7 @@@ fn lint_filter_map_map<'a, 'tcx>
      _map_args: &'tcx [hir::Expr],
  ) {
      // lint if caller of `.filter().map()` is an Iterator
 -    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +    if match_trait_method(cx, expr, &*paths::ITERATOR) {
          let msg = "called `filter_map(p).map(q)` on an `Iterator`. \
                     This is more succinctly expressed by only calling `.filter_map(..)` instead.";
          span_lint(cx, FILTER_MAP, expr.span, msg);
@@@ -2019,7 -2055,7 +2058,7 @@@ fn lint_filter_flat_map<'a, 'tcx>
      _map_args: &'tcx [hir::Expr],
  ) {
      // lint if caller of `.filter().flat_map()` is an Iterator
 -    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +    if match_trait_method(cx, expr, &*paths::ITERATOR) {
          let msg = "called `filter(p).flat_map(q)` on an `Iterator`. \
                     This is more succinctly expressed by calling `.flat_map(..)` \
                     and filtering by returning an empty Iterator.";
@@@ -2035,7 -2071,7 +2074,7 @@@ fn lint_filter_map_flat_map<'a, 'tcx>
      _map_args: &'tcx [hir::Expr],
  ) {
      // lint if caller of `.filter_map().flat_map()` is an Iterator
 -    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +    if match_trait_method(cx, expr, &*paths::ITERATOR) {
          let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`. \
                     This is more succinctly expressed by calling `.flat_map(..)` \
                     and filtering by returning an empty Iterator.";
@@@ -2052,7 -2088,7 +2091,7 @@@ fn lint_search_is_some<'a, 'tcx>
      is_some_args: &'tcx [hir::Expr],
  ) {
      // lint if caller of search is an Iterator
 -    if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) {
 +    if match_trait_method(cx, &is_some_args[0], &*paths::ITERATOR) {
          let msg = format!(
              "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \
               expressed by calling `any()`.",
@@@ -2125,7 -2161,7 +2164,7 @@@ fn lint_binary_expr_with_method_call(cx
  fn lint_chars_cmp(
      cx: &LateContext<'_, '_>,
      info: &BinaryExprInfo<'_>,
 -    chain_methods: &[&str],
 +    chain_methods: &[Symbol],
      lint: &'static Lint,
      suggest: &str,
  ) -> bool {
          if arg_char.len() == 1;
          if let hir::ExprKind::Path(ref qpath) = fun.node;
          if let Some(segment) = single_segment_path(qpath);
 -        if segment.ident.name == "Some";
 +        if segment.ident.name == *sym::Some;
          then {
              let mut applicability = Applicability::MachineApplicable;
              let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0]));
  
  /// Checks for the `CHARS_NEXT_CMP` lint.
  fn lint_chars_next_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
 -    lint_chars_cmp(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
 +    lint_chars_cmp(cx, info, &[*sym::chars, *sym::next], CHARS_NEXT_CMP, "starts_with")
  }
  
  /// Checks for the `CHARS_LAST_CMP` lint.
  fn lint_chars_last_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
 -    if lint_chars_cmp(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") {
 +    if lint_chars_cmp(cx, info, &[*sym::chars, *sym::last], CHARS_LAST_CMP, "ends_with") {
          true
      } else {
 -        lint_chars_cmp(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with")
 +        lint_chars_cmp(cx, info, &[*sym::chars, *sym::next_back], CHARS_LAST_CMP, "ends_with")
      }
  }
  
  fn lint_chars_cmp_with_unwrap<'a, 'tcx>(
      cx: &LateContext<'a, 'tcx>,
      info: &BinaryExprInfo<'_>,
 -    chain_methods: &[&str],
 +    chain_methods: &[Symbol],
      lint: &'static Lint,
      suggest: &str,
  ) -> bool {
  
  /// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
  fn lint_chars_next_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
 -    lint_chars_cmp_with_unwrap(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
 +    lint_chars_cmp_with_unwrap(
 +        cx,
 +        info,
 +        &[*sym::chars, *sym::next, *sym::unwrap],
 +        CHARS_NEXT_CMP,
 +        "starts_with",
 +    )
  }
  
  /// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
  fn lint_chars_last_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
 -    if lint_chars_cmp_with_unwrap(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
 +    if lint_chars_cmp_with_unwrap(
 +        cx,
 +        info,
 +        &[*sym::chars, *sym::last, *sym::unwrap],
 +        CHARS_LAST_CMP,
 +        "ends_with",
 +    ) {
          true
      } else {
 -        lint_chars_cmp_with_unwrap(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with")
 +        lint_chars_cmp_with_unwrap(
 +            cx,
 +            info,
 +            &[*sym::chars, *sym::next_back, *sym::unwrap],
 +            CHARS_LAST_CMP,
 +            "ends_with",
 +        )
      }
  }
  
@@@ -2274,7 -2292,7 +2313,7 @@@ fn lint_single_char_pattern<'a, 'tcx>(c
  fn lint_asref(cx: &LateContext<'_, '_>, expr: &hir::Expr, call_name: &str, as_ref_args: &[hir::Expr]) {
      // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
      // check if the call is to the actual `AsRef` or `AsMut` trait
 -    if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
 +    if match_trait_method(cx, expr, &*paths::ASREF_TRAIT) || match_trait_method(cx, expr, &*paths::ASMUT_TRAIT) {
          // check if the type after `as_ref` or `as_mut` is the same as before
          let recvr = &as_ref_args[0];
          let rcv_ty = cx.tables.expr_ty(recvr);
      }
  }
  
 -fn ty_has_iter_method(
 -    cx: &LateContext<'_, '_>,
 -    self_ref_ty: Ty<'_>,
 -) -> Option<(&'static Lint, &'static str, &'static str)> {
 +fn ty_has_iter_method(cx: &LateContext<'_, '_>, self_ref_ty: Ty<'_>) -> Option<(&'static Lint, Symbol, &'static str)> {
      if let Some(ty_name) = has_iter_method(cx, self_ref_ty) {
 -        let lint = match ty_name {
 -            "array" | "PathBuf" => INTO_ITER_ON_ARRAY,
 -            _ => INTO_ITER_ON_REF,
 +        let lint = if ty_name == *sym::array || ty_name == *sym::PathBuf {
 +            INTO_ITER_ON_ARRAY
 +        } else {
 +            INTO_ITER_ON_REF
          };
          let mutbl = match self_ref_ty.sty {
              ty::Ref(_, _, mutbl) => mutbl,
  }
  
  fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: Ty<'_>, method_span: Span) {
 -    if !match_trait_method(cx, expr, &paths::INTO_ITERATOR) {
 +    if !match_trait_method(cx, expr, &*paths::INTO_ITERATOR) {
          return;
      }
      if let Some((lint, kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) {
  /// 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::Adt(_, substs) = ty.sty {
 -        if match_type(cx, ty, &paths::RESULT) {
 +        if match_type(cx, ty, &*paths::RESULT) {
              substs.types().nth(1)
          } else {
              None
@@@ -2385,63 -2405,59 +2424,63 @@@ const CONVENTIONS: [(Convention, &[Self
  ];
  
  #[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"),
 -    ("as_ref", 1, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"),
 -    ("bitand", 2, SelfKind::Value, OutType::Any, "std::ops::BitAnd"),
 -    ("bitor", 2, SelfKind::Value, OutType::Any, "std::ops::BitOr"),
 -    ("bitxor", 2, SelfKind::Value, OutType::Any, "std::ops::BitXor"),
 -    ("borrow", 1, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"),
 -    ("borrow_mut", 1, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"),
 -    ("clone", 1, SelfKind::Ref, OutType::Any, "std::clone::Clone"),
 -    ("cmp", 2, SelfKind::Ref, OutType::Any, "std::cmp::Ord"),
 -    ("default", 0, SelfKind::No, OutType::Any, "std::default::Default"),
 -    ("deref", 1, SelfKind::Ref, OutType::Ref, "std::ops::Deref"),
 -    ("deref_mut", 1, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"),
 -    ("div", 2, SelfKind::Value, OutType::Any, "std::ops::Div"),
 -    ("drop", 1, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"),
 -    ("eq", 2, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"),
 -    ("from_iter", 1, SelfKind::No, OutType::Any, "std::iter::FromIterator"),
 -    ("from_str", 1, SelfKind::No, OutType::Any, "std::str::FromStr"),
 -    ("hash", 2, SelfKind::Ref, OutType::Unit, "std::hash::Hash"),
 -    ("index", 2, SelfKind::Ref, OutType::Ref, "std::ops::Index"),
 -    ("index_mut", 2, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"),
 -    ("into_iter", 1, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"),
 -    ("mul", 2, SelfKind::Value, OutType::Any, "std::ops::Mul"),
 -    ("neg", 1, SelfKind::Value, OutType::Any, "std::ops::Neg"),
 -    ("next", 1, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"),
 -    ("not", 1, SelfKind::Value, OutType::Any, "std::ops::Not"),
 -    ("rem", 2, SelfKind::Value, OutType::Any, "std::ops::Rem"),
 -    ("shl", 2, SelfKind::Value, OutType::Any, "std::ops::Shl"),
 -    ("shr", 2, SelfKind::Value, OutType::Any, "std::ops::Shr"),
 -    ("sub", 2, SelfKind::Value, OutType::Any, "std::ops::Sub"),
 +lazy_static! {
 +static ref TRAIT_METHODS: [(Symbol, usize, SelfKind, OutType, &'static str); 30] = [
 +    (*sym::add, 2, SelfKind::Value, OutType::Any, "std::ops::Add"),
 +    (*sym::as_mut, 1, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"),
 +    (*sym::as_ref, 1, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"),
 +    (*sym::bitand, 2, SelfKind::Value, OutType::Any, "std::ops::BitAnd"),
 +    (*sym::bitor, 2, SelfKind::Value, OutType::Any, "std::ops::BitOr"),
 +    (*sym::bitxor, 2, SelfKind::Value, OutType::Any, "std::ops::BitXor"),
 +    (*sym::borrow, 1, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"),
 +    (*sym::borrow_mut, 1, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"),
 +    (*sym::clone, 1, SelfKind::Ref, OutType::Any, "std::clone::Clone"),
 +    (*sym::cmp, 2, SelfKind::Ref, OutType::Any, "std::cmp::Ord"),
 +    (*sym::default, 0, SelfKind::No, OutType::Any, "std::default::Default"),
 +    (*sym::deref, 1, SelfKind::Ref, OutType::Ref, "std::ops::Deref"),
 +    (*sym::deref_mut, 1, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"),
 +    (*sym::div, 2, SelfKind::Value, OutType::Any, "std::ops::Div"),
 +    (*sym::drop, 1, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"),
 +    (*sym::eq, 2, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"),
 +    (*sym::from_iter, 1, SelfKind::No, OutType::Any, "std::iter::FromIterator"),
 +    (*sym::from_str, 1, SelfKind::No, OutType::Any, "std::str::FromStr"),
 +    (*sym::hash, 2, SelfKind::Ref, OutType::Unit, "std::hash::Hash"),
 +    (*sym::index, 2, SelfKind::Ref, OutType::Ref, "std::ops::Index"),
 +    (*sym::index_mut, 2, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"),
 +    (*sym::into_iter, 1, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"),
 +    (*sym::mul, 2, SelfKind::Value, OutType::Any, "std::ops::Mul"),
 +    (*sym::neg, 1, SelfKind::Value, OutType::Any, "std::ops::Neg"),
 +    (*sym::next, 1, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"),
 +    (*sym::not, 1, SelfKind::Value, OutType::Any, "std::ops::Not"),
 +    (*sym::rem, 2, SelfKind::Value, OutType::Any, "std::ops::Rem"),
 +    (*sym::shl, 2, SelfKind::Value, OutType::Any, "std::ops::Shl"),
 +    (*sym::shr, 2, SelfKind::Value, OutType::Any, "std::ops::Shr"),
 +    (*sym::sub, 2, SelfKind::Value, OutType::Any, "std::ops::Sub"),
  ];
 +}
  
  #[rustfmt::skip]
 -const PATTERN_METHODS: [(&str, usize); 17] = [
 -    ("contains", 1),
 -    ("starts_with", 1),
 -    ("ends_with", 1),
 -    ("find", 1),
 -    ("rfind", 1),
 -    ("split", 1),
 -    ("rsplit", 1),
 -    ("split_terminator", 1),
 -    ("rsplit_terminator", 1),
 -    ("splitn", 2),
 -    ("rsplitn", 2),
 -    ("matches", 1),
 -    ("rmatches", 1),
 -    ("match_indices", 1),
 -    ("rmatch_indices", 1),
 -    ("trim_start_matches", 1),
 -    ("trim_end_matches", 1),
 +lazy_static! {
 +static ref PATTERN_METHODS: [(Symbol, usize); 17] = [
 +    (*sym::contains, 1),
 +    (*sym::starts_with, 1),
 +    (*sym::ends_with, 1),
 +    (*sym::find, 1),
 +    (*sym::rfind, 1),
 +    (*sym::split, 1),
 +    (*sym::rsplit, 1),
 +    (*sym::split_terminator, 1),
 +    (*sym::rsplit_terminator, 1),
 +    (*sym::splitn, 2),
 +    (*sym::rsplitn, 2),
 +    (*sym::matches, 1),
 +    (*sym::rmatches, 1),
 +    (*sym::match_indices, 1),
 +    (*sym::rmatch_indices, 1),
 +    (*sym::trim_start_matches, 1),
 +    (*sym::trim_end_matches, 1),
  ];
 +}
  
  #[derive(Clone, Copy, PartialEq, Debug)]
  enum SelfKind {
@@@ -2497,8 -2513,8 +2536,8 @@@ impl SelfKind 
          } else {
              match self {
                  SelfKind::Value => false,
 -                SelfKind::Ref => is_as_ref_or_mut_trait(ty, self_ty, generics, &paths::ASREF_TRAIT),
 -                SelfKind::RefMut => is_as_ref_or_mut_trait(ty, self_ty, generics, &paths::ASMUT_TRAIT),
 +                SelfKind::Ref => is_as_ref_or_mut_trait(ty, self_ty, generics, &*paths::ASREF_TRAIT),
 +                SelfKind::RefMut => is_as_ref_or_mut_trait(ty, self_ty, generics, &*paths::ASMUT_TRAIT),
                  SelfKind::No => true,
              }
          }
      }
  }
  
 -fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Generics, name: &[&str]) -> bool {
 +fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Generics, name: &[Symbol]) -> bool {
      single_segment_ty(ty).map_or(false, |seg| {
          generics.params.iter().any(|param| match param.kind {
              hir::GenericParamKind::Type { .. } => {
@@@ -2618,7 -2634,7 +2657,7 @@@ impl OutType 
  
  fn is_bool(ty: &hir::Ty) -> bool {
      if let hir::TyKind::Path(ref p) = ty.node {
 -        match_qpath(p, &["bool"])
 +        match_qpath(p, &[*sym::bool])
      } else {
          false
      }