-#![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, walk_inf, 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};
///
/// 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"
}
}
- if !cx.access_levels.is_exported(item.hir_id()) {
+ if !cx.access_levels.is_exported(item.def_id) {
return;
}
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;
}
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);
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,
}
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);
walk_inf(self, inf);
}
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
}
/// Looks for default-hasher-dependent constructors like `HashMap::new`.
}
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()));
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());
),
);
}
- } 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());
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()
}
}