-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add an internal lint for FxHashMap/FxHashSet #3026
Conversation
} | ||
|
||
impl EarlyLintPass for PreferFxHash { | ||
fn check_ident(&mut self, cx: &EarlyContext, ident: Ident) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be the first EarlyLintPass Herr, so you want to use syntax::ast::*;
.
|
||
impl EarlyLintPass for PreferFxHash { | ||
fn check_ident(&mut self, cx: &EarlyContext, ident: Ident) { | ||
if ident.to_string().contains("HashMap") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if
is an expression in Rust, so you can just use it to decide on the message without all the other code duplicated.
|
||
impl EarlyLintPass for PreferFxHash { | ||
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { | ||
if let Some(prefer) = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable prefer
?
|
||
impl EarlyLintPass for PreferFxHash { | ||
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { | ||
if let Some(msg) = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can get rid of the if let
and the Some(_)
if you use an early return
in the else
case.
Like: let msg = if .. { .. } else if .. { .. } else { return; }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh neat. Will do.
The name should describe the flaw the lint is catching so that it makes sense when you allow/warn/deny it. |
impl EarlyLintPass for PreferFxHash { | ||
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { | ||
if let Some(msg) = { | ||
if ident.to_string().contains("HashMap") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this lint FxHashMap
as well? Shouldn't it be ==
instead of contains
? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah you're right. I don't know Ident
, so I'm looking for help on this one..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Went the easy way..
Thanks @mikerite for the feedback. Pushed my attempts to resolving them. |
|
||
impl LintPass for DefaultHashTypes { | ||
fn get_lints(&self) -> LintArray { | ||
lint_array!(PREFER_FX_HASH) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still the old lint name here
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { | ||
let msg = { | ||
let ident: String = ident.to_string(); | ||
if ident.contains("HashMap") && !ident.contains("FxHashMap") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another solution to consider for this would be to have a FxHashMap
with the keys being the disallowed ident
s (strings) and the value the wanted replacement.
Then you can just
let msg = if let Some(replace) = map.get(ident_string) {
format!("Prefer {} over {}", replace, ident_string);
} else {
return
}
This would also be easy to extend, if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the to_string
of an Ident
that .contains("HashMap")
? Is it "HashMap"
? Or is it something more fully-qualified?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should just be "HashMap"
.
Even nicer, @flip1995. Thank you! |
|
||
impl EarlyLintPass for DefaultHashTypes { | ||
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { | ||
let mut map = HashMap::default(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should do this in a new()
function on creating the Lint. Doing this here will create a new HashMap
everytime you check an ident
. This happens pretty often and is bad for the performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh and you're using HashMap
instead of FxHashMap
. 😄
LGTM! Could you add a few test cases with |
Sure, I'll have to look into how to do that. |
Thanks! Waiting for the new nightly and a CI rerun. Could you squash some of the commits? |
Just tested it locally: stderr diff
error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy
- --> $DIR/fxhash.rs:7:24
+ --> $DIR/fxhash.rs:6:24
|
-7 | use std::collections::{HashMap, HashSet};
+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:7:33
+ --> $DIR/fxhash.rs:6:33
|
-7 | use std::collections::{HashMap, HashSet};
+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:12:15
+ --> $DIR/fxhash.rs:10:15
|
-12 | let _map: HashMap<String, String> = HashMap::default();
+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:12:41
+ --> $DIR/fxhash.rs:10:41
|
-12 | let _map: HashMap<String, String> = HashMap::default();
+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:13:15
+ --> $DIR/fxhash.rs:11:15
|
-13 | let _set: HashSet<String> = HashSet::default();
+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:13:33
+ --> $DIR/fxhash.rs:11:33
|
-13 | let _set: HashSet<String> = HashSet::default();
+11 | let _set: HashSet<String> = HashSet::default();
| ^^^^^^^
error: aborting due to 6 previous errors |
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think using the utils::span_lint_and_sugg
function here would be even nicer.
https://github.com/rust-lang-nursery/rust-clippy/blob/e6d92f95c6d6964628d75c25fb3d1a58a9f25e5d/clippy_lints/src/utils/mod.rs#L580-L587
help
: "use"
sugg
: replace
You should always use the span_lint
functions from the utils
module for Clippy lints, because they add the link to the doc to the warning messages.
Sorry I missed that in the previous review.
|
Thanks for all the review comments @flip1995: it's been silly mistake after silly mistake from me. 🙂 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Always happy to help!
Fixes #2853
My first lint, so feedback and guidance welcome! Thank you.