Add an internal lint for FxHashMap/FxHashSet

This commit is contained in:
Dale Wijnand 2018-08-10 18:58:23 +01:00
parent 82e9f5ffa3
commit 8fc425b676
No known key found for this signature in database
GPG key ID: 4F256E3D151DF5EF
4 changed files with 103 additions and 1 deletions

View file

@ -266,6 +266,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
reg.register_late_lint_pass(box serde_api::Serde);
reg.register_early_lint_pass(box utils::internal_lints::Clippy);
reg.register_late_lint_pass(box utils::internal_lints::LintWithoutLintPass::default());
reg.register_early_lint_pass(box utils::internal_lints::DefaultHashTypes::new());
reg.register_late_lint_pass(box utils::inspector::Pass);
reg.register_late_lint_pass(box utils::author::Pass);
reg.register_late_lint_pass(box types::TypePass);
@ -467,6 +468,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
reg.register_lint_group("clippy_internal", vec![
utils::internal_lints::CLIPPY_LINTS_INTERNAL,
utils::internal_lints::LINT_WITHOUT_LINT_PASS,
utils::internal_lints::DEFAULT_HASH_TYPES,
]);
reg.register_lint_group("clippy", vec![

View file

@ -3,9 +3,10 @@ use rustc::{declare_lint, lint_array};
use rustc::hir::*;
use rustc::hir;
use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_data_structures::fx::FxHashMap;
use crate::utils::{match_qpath, paths, span_lint};
use syntax::symbol::LocalInternedString;
use syntax::ast::{Crate as AstCrate, ItemKind, Name};
use syntax::ast::{Crate as AstCrate, Ident, ItemKind, Name};
use syntax::codemap::Span;
use std::collections::{HashMap, HashSet};
@ -54,6 +55,18 @@ declare_clippy_lint! {
}
/// **What it does:** Checks for the presence of the default hash types "HashMap" or "HashSet"
/// and recommends the FxHash* variants.
///
/// **Why is this bad?** The FxHash variants have better performance
/// and we don't need any collision prevention in clippy.
declare_clippy_lint! {
pub DEFAULT_HASH_TYPES,
internal,
"forbid HashMap and HashSet and suggest the FxHash* variants"
}
#[derive(Copy, Clone)]
pub struct Clippy;
@ -207,3 +220,34 @@ impl<'a, 'tcx: 'a> Visitor<'tcx> for LintCollector<'a, 'tcx> {
NestedVisitorMap::All(&self.cx.tcx.hir)
}
}
pub struct DefaultHashTypes {
map: FxHashMap<String, String>,
}
impl DefaultHashTypes {
pub fn new() -> Self {
let mut map = FxHashMap::default();
map.insert("HashMap".to_owned(), "FxHashMap".to_owned());
map.insert("HashSet".to_owned(), "FxHashSet".to_owned());
Self { map }
}
}
impl LintPass for DefaultHashTypes {
fn get_lints(&self) -> LintArray {
lint_array!(DEFAULT_HASH_TYPES)
}
}
impl EarlyLintPass for DefaultHashTypes {
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
let ident_string = ident.to_string();
if let Some(replace) = self.map.get(&ident_string) {
let msg = format!("Prefer {} over {}, it has better performance and we don't need any collision prevention in clippy", replace, ident_string);
cx.span_lint(DEFAULT_HASH_TYPES, ident.span, &msg);
}
}
}

16
tests/ui/fxhash.rs Normal file
View file

@ -0,0 +1,16 @@
#![warn(default_hash_types)]
#![feature(rustc_private)]
extern crate rustc_data_structures;
use std::collections::{HashMap, HashSet};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
fn main() {
let _map: HashMap<String, String> = HashMap::default();
let _set: HashSet<String> = HashSet::default();
// test that the lint doesn't also match the Fx variants themselves 😂
let _fx_map: FxHashMap<String, String> = FxHashMap::default();
let _fx_set: FxHashSet<String> = FxHashSet::default();
}

40
tests/ui/fxhash.stderr Normal file
View file

@ -0,0 +1,40 @@
error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy
--> $DIR/fxhash.rs:6:24
|
6 | use std::collections::{HashMap, HashSet};
| ^^^^^^^
|
= note: `-D default-hash-types` implied by `-D warnings`
error: Prefer FxHashSet over HashSet, it has better performance and we don't need any collision prevention in clippy
--> $DIR/fxhash.rs:6:33
|
6 | use std::collections::{HashMap, HashSet};
| ^^^^^^^
error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy
--> $DIR/fxhash.rs:10:15
|
10 | let _map: HashMap<String, String> = HashMap::default();
| ^^^^^^^
error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy
--> $DIR/fxhash.rs:10:41
|
10 | let _map: HashMap<String, String> = HashMap::default();
| ^^^^^^^
error: Prefer FxHashSet over HashSet, it has better performance and we don't need any collision prevention in clippy
--> $DIR/fxhash.rs:11:15
|
11 | let _set: HashSet<String> = HashSet::default();
| ^^^^^^^
error: Prefer FxHashSet over HashSet, it has better performance and we don't need any collision prevention in clippy
--> $DIR/fxhash.rs:11:33
|
11 | let _set: HashSet<String> = HashSet::default();
| ^^^^^^^
error: aborting due to 6 previous errors