Skip to content

Commit 84aa499

Browse files
authored
Merge pull request #3026 from dwijnand/fxhash
Add an internal lint for FxHashMap/FxHashSet
2 parents 72b8c9b + 22ff5a3 commit 84aa499

File tree

4 files changed

+104
-2
lines changed

4 files changed

+104
-2
lines changed

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
266266
reg.register_late_lint_pass(box serde_api::Serde);
267267
reg.register_early_lint_pass(box utils::internal_lints::Clippy);
268268
reg.register_late_lint_pass(box utils::internal_lints::LintWithoutLintPass::default());
269+
reg.register_early_lint_pass(box utils::internal_lints::DefaultHashTypes::default());
269270
reg.register_late_lint_pass(box utils::inspector::Pass);
270271
reg.register_late_lint_pass(box utils::author::Pass);
271272
reg.register_late_lint_pass(box types::TypePass);
@@ -467,6 +468,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
467468
reg.register_lint_group("clippy_internal", vec![
468469
utils::internal_lints::CLIPPY_LINTS_INTERNAL,
469470
utils::internal_lints::LINT_WITHOUT_LINT_PASS,
471+
utils::internal_lints::DEFAULT_HASH_TYPES,
470472
]);
471473

472474
reg.register_lint_group("clippy", vec![

clippy_lints/src/utils/internal_lints.rs

+46-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ use rustc::{declare_lint, lint_array};
33
use rustc::hir::*;
44
use rustc::hir;
55
use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
6-
use crate::utils::{match_qpath, paths, span_lint};
6+
use rustc_data_structures::fx::FxHashMap;
7+
use crate::utils::{match_qpath, paths, span_lint, span_lint_and_sugg};
78
use syntax::symbol::LocalInternedString;
8-
use syntax::ast::{Crate as AstCrate, ItemKind, Name};
9+
use syntax::ast::{Crate as AstCrate, Ident, ItemKind, Name};
910
use syntax::codemap::Span;
1011
use std::collections::{HashMap, HashSet};
1112

@@ -54,6 +55,18 @@ declare_clippy_lint! {
5455
}
5556

5657

58+
/// **What it does:** Checks for the presence of the default hash types "HashMap" or "HashSet"
59+
/// and recommends the FxHash* variants.
60+
///
61+
/// **Why is this bad?** The FxHash variants have better performance
62+
/// and we don't need any collision prevention in clippy.
63+
declare_clippy_lint! {
64+
pub DEFAULT_HASH_TYPES,
65+
internal,
66+
"forbid HashMap and HashSet and suggest the FxHash* variants"
67+
}
68+
69+
5770
#[derive(Copy, Clone)]
5871
pub struct Clippy;
5972

@@ -207,3 +220,34 @@ impl<'a, 'tcx: 'a> Visitor<'tcx> for LintCollector<'a, 'tcx> {
207220
NestedVisitorMap::All(&self.cx.tcx.hir)
208221
}
209222
}
223+
224+
225+
226+
pub struct DefaultHashTypes {
227+
map: FxHashMap<String, String>,
228+
}
229+
230+
impl DefaultHashTypes {
231+
pub fn default() -> Self {
232+
let mut map = FxHashMap::default();
233+
map.insert("HashMap".to_owned(), "FxHashMap".to_owned());
234+
map.insert("HashSet".to_owned(), "FxHashSet".to_owned());
235+
Self { map }
236+
}
237+
}
238+
239+
impl LintPass for DefaultHashTypes {
240+
fn get_lints(&self) -> LintArray {
241+
lint_array!(DEFAULT_HASH_TYPES)
242+
}
243+
}
244+
245+
impl EarlyLintPass for DefaultHashTypes {
246+
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
247+
let ident_string = ident.to_string();
248+
if let Some(replace) = self.map.get(&ident_string) {
249+
let msg = format!("Prefer {} over {}, it has better performance and we don't need any collision prevention in clippy", replace, ident_string);
250+
span_lint_and_sugg(cx, DEFAULT_HASH_TYPES, ident.span, &msg, "use", replace.to_owned());
251+
}
252+
}
253+
}

tests/ui/fxhash.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![warn(default_hash_types)]
2+
#![feature(rustc_private)]
3+
4+
extern crate rustc_data_structures;
5+
6+
use std::collections::{HashMap, HashSet};
7+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
8+
9+
fn main() {
10+
let _map: HashMap<String, String> = HashMap::default();
11+
let _set: HashSet<String> = HashSet::default();
12+
13+
// test that the lint doesn't also match the Fx variants themselves 😂
14+
let _fx_map: FxHashMap<String, String> = FxHashMap::default();
15+
let _fx_set: FxHashSet<String> = FxHashSet::default();
16+
}

tests/ui/fxhash.stderr

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy
2+
--> $DIR/fxhash.rs:6:24
3+
|
4+
6 | use std::collections::{HashMap, HashSet};
5+
| ^^^^^^^ help: use: `FxHashMap`
6+
|
7+
= note: `-D default-hash-types` implied by `-D warnings`
8+
9+
error: Prefer FxHashSet over HashSet, it has better performance and we don't need any collision prevention in clippy
10+
--> $DIR/fxhash.rs:6:33
11+
|
12+
6 | use std::collections::{HashMap, HashSet};
13+
| ^^^^^^^ help: use: `FxHashSet`
14+
15+
error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy
16+
--> $DIR/fxhash.rs:10:15
17+
|
18+
10 | let _map: HashMap<String, String> = HashMap::default();
19+
| ^^^^^^^ help: use: `FxHashMap`
20+
21+
error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy
22+
--> $DIR/fxhash.rs:10:41
23+
|
24+
10 | let _map: HashMap<String, String> = HashMap::default();
25+
| ^^^^^^^ help: use: `FxHashMap`
26+
27+
error: Prefer FxHashSet over HashSet, it has better performance and we don't need any collision prevention in clippy
28+
--> $DIR/fxhash.rs:11:15
29+
|
30+
11 | let _set: HashSet<String> = HashSet::default();
31+
| ^^^^^^^ help: use: `FxHashSet`
32+
33+
error: Prefer FxHashSet over HashSet, it has better performance and we don't need any collision prevention in clippy
34+
--> $DIR/fxhash.rs:11:33
35+
|
36+
11 | let _set: HashSet<String> = HashSet::default();
37+
| ^^^^^^^ help: use: `FxHashSet`
38+
39+
error: aborting due to 6 previous errors
40+

0 commit comments

Comments
 (0)