]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/implicit_hasher.rs
modify code
[rust.git] / clippy_lints / src / implicit_hasher.rs
index 9a040ca572af51613733a328828800d25ec6693b..eed25e9bc0ea8c7458a18480a2d956af5f9b1aaa 100644 (file)
@@ -1,14 +1,12 @@
-#![cfg_attr(bootstrap, allow(rustc::default_hash_types))]
-
 use std::borrow::Cow;
 use std::collections::BTreeMap;
 
 use rustc_errors::DiagnosticBuilder;
 use rustc_hir as hir;
-use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{Ty, TyS, TypeckResults};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use if_chain::if_chain;
 
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
-use clippy_utils::paths;
+use clippy_utils::differing_macro_contexts;
 use clippy_utils::source::{snippet, snippet_opt};
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{differing_macro_contexts, match_def_path};
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for public `impl` or `fn` missing generalization
+    /// ### What it does
+    /// Checks for public `impl` or `fn` missing generalization
     /// over different hashers and implicitly defaulting to the default hashing
     /// algorithm (`SipHash`).
     ///
-    /// **Why is this bad?** `HashMap` or `HashSet` with custom hashers cannot be
+    /// ### Why is this bad?
+    /// `HashMap` or `HashSet` with custom hashers cannot be
     /// used with them.
     ///
-    /// **Known problems:** Suggestions for replacing constructors can contain
+    /// ### Known problems
+    /// Suggestions for replacing constructors can contain
     /// false-positives. Also applying suggestions can require modification of other
     /// pieces of code, possibly including external crates.
     ///
-    /// **Example:**
+    /// ### Example
     /// ```rust
     /// # use std::collections::HashMap;
     /// # use std::hash::{Hash, BuildHasher};
@@ -54,6 +54,7 @@
     ///
     /// pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { }
     /// ```
+    #[clippy::version = "pre 1.29.0"]
     pub IMPLICIT_HASHER,
     pedantic,
     "missing generalization over different hashers"
@@ -112,7 +113,7 @@ fn suggestion<'tcx>(
             }
         }
 
-        if !cx.access_levels.is_exported(item.hir_id()) {
+        if !cx.access_levels.is_exported(item.def_id) {
             return;
         }
 
@@ -130,7 +131,7 @@ fn suggestion<'tcx>(
                         let pos = snippet_opt(cx, item.span.until(target.span()))
                             .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
                         if let Some(pos) = pos {
-                            Span::new(pos, pos, item.span.data().ctxt)
+                            Span::new(pos, pos, item.span.ctxt(), item.span.parent())
                         } else {
                             return;
                         }
@@ -167,13 +168,21 @@ fn suggestion<'tcx>(
                             continue;
                         }
                         let generics_suggestion_span = generics.span.substitute_dummy({
-                            let pos = snippet_opt(cx, item.span.until(body.params[0].pat.span))
-                                .and_then(|snip| {
-                                    let i = snip.find("fn")?;
-                                    Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32))
-                                })
-                                .expect("failed to create span for type parameters");
-                            Span::new(pos, pos, item.span.data().ctxt)
+                            let pos = snippet_opt(
+                                cx,
+                                Span::new(
+                                    item.span.lo(),
+                                    body.params[0].pat.span.lo(),
+                                    item.span.ctxt(),
+                                    item.span.parent(),
+                                ),
+                            )
+                            .and_then(|snip| {
+                                let i = snip.find("fn")?;
+                                Some(item.span.lo() + BytePos((i + snip[i..].find('(')?) as u32))
+                            })
+                            .expect("failed to create span for type parameters");
+                            Span::new(pos, pos, item.span.ctxt(), item.span.parent())
                         });
 
                         let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
@@ -225,14 +234,14 @@ fn new(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> Option<Self> {
 
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
 
-            if is_type_diagnostic_item(cx, ty, sym::hashmap_type) && params_len == 2 {
+            if is_type_diagnostic_item(cx, ty, sym::HashMap) && params_len == 2 {
                 Some(ImplicitHasherType::HashMap(
                     hir_ty.span,
                     ty,
                     snippet(cx, params[0].span, "K"),
                     snippet(cx, params[1].span, "V"),
                 ))
-            } else if is_type_diagnostic_item(cx, ty, sym::hashset_type) && params_len == 1 {
+            } else if is_type_diagnostic_item(cx, ty, sym::HashSet) && params_len == 1 {
                 Some(ImplicitHasherType::HashSet(
                     hir_ty.span,
                     ty,
@@ -285,8 +294,6 @@ fn new(cx: &'a LateContext<'tcx>) -> Self {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
         if let Some(target) = ImplicitHasherType::new(self.cx, t) {
             self.found.push(target);
@@ -295,8 +302,12 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
         walk_ty(self, t);
     }
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
+    fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
+        if let Some(target) = ImplicitHasherType::new(self.cx, &inf.to_ty()) {
+            self.found.push(target);
+        }
+
+        walk_inf(self, inf);
     }
 }
 
@@ -320,7 +331,7 @@ fn new(cx: &'a LateContext<'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self
 }
 
 impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_body(&mut self, body: &'tcx Body<'_>) {
         let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body.id()));
@@ -339,7 +350,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                     return;
                 }
 
-                if match_def_path(self.cx, ty_did, &paths::HASHMAP) {
+                if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) {
                     if method.ident.name == sym::new {
                         self.suggestions
                             .insert(e.span, "HashMap::default()".to_string());
@@ -352,7 +363,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                             ),
                         );
                     }
-                } else if match_def_path(self.cx, ty_did, &paths::HASHSET) {
+                } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) {
                     if method.ident.name == sym::new {
                         self.suggestions
                             .insert(e.span, "HashSet::default()".to_string());
@@ -372,7 +383,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         walk_expr(self, e);
     }
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 }