Skip to content

Commit

Permalink
perf(linter, prettier, diagnostics): use FxHashMap instead of `std:…
Browse files Browse the repository at this point in the history
…:collections::HashMap` (#5993)

Using `FxHashMap` is faster than `HashMap` in many cases, especially for hashing-heavy workloads. This change improves the performance of the linter, prettier, and diagnostics crates by using `FxHashMap` instead of `std::collections::HashMap`.
  • Loading branch information
camchenry committed Sep 23, 2024
1 parent b240b42 commit 2b17003
Show file tree
Hide file tree
Showing 17 changed files with 67 additions and 62 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/oxc_diagnostics/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ doctest = false
miette = { workspace = true }

owo-colors = { workspace = true }
rustc-hash = { workspace = true }
textwrap = { workspace = true }
unicode-width = { workspace = true }
5 changes: 3 additions & 2 deletions crates/oxc_diagnostics/src/reporter/checkstyle.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::{borrow::Cow, collections::HashMap};
use std::borrow::Cow;

use super::{DiagnosticReporter, Info};
use crate::{Error, Severity};
use rustc_hash::FxHashMap;

#[derive(Default)]
pub struct CheckstyleReporter {
Expand All @@ -24,7 +25,7 @@ impl DiagnosticReporter for CheckstyleReporter {
#[allow(clippy::print_stdout)]
fn format_checkstyle(diagnostics: &[Error]) {
let infos = diagnostics.iter().map(Info::new).collect::<Vec<_>>();
let mut grouped: HashMap<String, Vec<Info>> = HashMap::new();
let mut grouped: FxHashMap<String, Vec<Info>> = FxHashMap::default();
for info in infos {
grouped.entry(info.filename.clone()).or_default().push(info);
}
Expand Down
10 changes: 6 additions & 4 deletions crates/oxc_linter/src/rules/eslint/no_this_before_super.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;

use oxc_ast::{
ast::{Argument, Expression, MethodDefinitionKind},
Expand All @@ -12,6 +12,7 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::NodeId;
use oxc_span::{GetSpan, Span};
use rustc_hash::FxHashMap;

use crate::{context::LintContext, rule::Rule, AstNode};

Expand Down Expand Up @@ -62,7 +63,8 @@ impl Rule for NoThisBeforeSuper {
// first pass -> find super calls and local violations
let mut wanted_nodes = Vec::new();
let mut basic_blocks_with_super_called = HashSet::<BasicBlockId>::new();
let mut basic_blocks_with_local_violations = HashMap::<BasicBlockId, Vec<NodeId>>::new();
let mut basic_blocks_with_local_violations =
FxHashMap::<BasicBlockId, Vec<NodeId>>::default();
for node in semantic.nodes() {
match node.kind() {
AstKind::Function(_) | AstKind::ArrowFunctionExpression(_) => {
Expand Down Expand Up @@ -153,7 +155,7 @@ impl NoThisBeforeSuper {
cfg: &ControlFlowGraph,
id: BasicBlockId,
basic_blocks_with_super_called: &HashSet<BasicBlockId>,
basic_blocks_with_local_violations: &HashMap<BasicBlockId, Vec<NodeId>>,
basic_blocks_with_local_violations: &FxHashMap<BasicBlockId, Vec<NodeId>>,
follow_join: bool,
) -> Vec<DefinitelyCallsThisBeforeSuper> {
neighbors_filtered_by_edge_weight(
Expand Down Expand Up @@ -212,7 +214,7 @@ impl NoThisBeforeSuper {
cfg: &ControlFlowGraph,
output: Vec<DefinitelyCallsThisBeforeSuper>,
basic_blocks_with_super_called: &HashSet<BasicBlockId>,
basic_blocks_with_local_violations: &HashMap<BasicBlockId, Vec<NodeId>>,
basic_blocks_with_local_violations: &FxHashMap<BasicBlockId, Vec<NodeId>>,
) -> bool {
// Deciding whether we definitely call this before super in all
// codepaths is as simple as seeing if any individual codepath
Expand Down
16 changes: 8 additions & 8 deletions crates/oxc_linter/src/rules/jest/no_confusing_set_timeout.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use std::collections::HashMap;

use cow_utils::CowUtils;
use oxc_ast::{ast::MemberExpression, AstKind};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::{AstNode, NodeId, ReferenceId};
use oxc_span::{GetSpan, Span};
use rustc_hash::FxHashMap;

use crate::{
context::LintContext,
Expand Down Expand Up @@ -80,10 +79,11 @@ impl Rule for NoConfusingSetTimeout {
let scopes = ctx.scopes();
let symbol_table = ctx.symbols();
let possible_nodes = collect_possible_jest_call_node(ctx);
let id_to_jest_node_map = possible_nodes.iter().fold(HashMap::new(), |mut acc, cur| {
acc.insert(cur.node.id(), cur);
acc
});
let id_to_jest_node_map =
possible_nodes.iter().fold(FxHashMap::default(), |mut acc, cur| {
acc.insert(cur.node.id(), cur);
acc
});

let mut jest_reference_id_list: Vec<(ReferenceId, Span)> = vec![];
let mut seen_jest_set_timeout = false;
Expand Down Expand Up @@ -151,7 +151,7 @@ fn handle_jest_set_time_out<'a>(
reference_id_list: impl Iterator<Item = ReferenceId>,
jest_reference_id_list: &Vec<(ReferenceId, Span)>,
seen_jest_set_timeout: &mut bool,
id_to_jest_node_map: &HashMap<NodeId, &PossibleJestNode<'a, '_>>,
id_to_jest_node_map: &FxHashMap<NodeId, &PossibleJestNode<'a, '_>>,
) {
let nodes = ctx.nodes();
let scopes = ctx.scopes();
Expand Down Expand Up @@ -199,7 +199,7 @@ fn handle_jest_set_time_out<'a>(

fn is_jest_fn_call<'a>(
parent_node: &AstNode<'a>,
id_to_jest_node_map: &HashMap<NodeId, &PossibleJestNode<'a, '_>>,
id_to_jest_node_map: &FxHashMap<NodeId, &PossibleJestNode<'a, '_>>,
ctx: &LintContext<'a>,
) -> bool {
let mut id = parent_node.id();
Expand Down
10 changes: 5 additions & 5 deletions crates/oxc_linter/src/rules/jest/no_duplicate_hooks.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::collections::HashMap;

use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::NodeId;
use oxc_span::Span;
use rustc_hash::FxHashMap;

use crate::{
context::LintContext,
Expand Down Expand Up @@ -104,7 +103,8 @@ impl Rule for NoDuplicateHooks {
let Some(root_node) = ctx.nodes().root_node() else {
return;
};
let mut hook_contexts: HashMap<NodeId, Vec<HashMap<String, i32>>> = HashMap::new();
let mut hook_contexts: FxHashMap<NodeId, Vec<FxHashMap<String, i32>>> =
FxHashMap::default();
hook_contexts.insert(root_node.id(), Vec::new());

let mut possibles_jest_nodes = collect_possible_jest_call_node(ctx);
Expand All @@ -120,7 +120,7 @@ impl NoDuplicateHooks {
fn run<'a>(
possible_jest_node: &PossibleJestNode<'a, '_>,
root_node_id: NodeId,
hook_contexts: &mut HashMap<NodeId, Vec<HashMap<String, i32>>>,
hook_contexts: &mut FxHashMap<NodeId, Vec<FxHashMap<String, i32>>>,
ctx: &LintContext<'a>,
) {
let node = possible_jest_node.node;
Expand Down Expand Up @@ -157,7 +157,7 @@ impl NoDuplicateHooks {
let last_context = if let Some(val) = contexts.last_mut() {
Some(val)
} else {
let mut context = HashMap::new();
let mut context = FxHashMap::default();
context.insert(hook_name.clone(), 0);
contexts.push(context);
contexts.last_mut()
Expand Down
7 changes: 3 additions & 4 deletions crates/oxc_linter/src/rules/jest/no_identical_title.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::collections::HashMap;

use oxc_ast::{
ast::{Argument, CallExpression},
AstKind,
Expand All @@ -8,6 +6,7 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::NodeId;
use oxc_span::Span;
use rustc_hash::FxHashMap;

use crate::{
context::LintContext,
Expand Down Expand Up @@ -74,8 +73,8 @@ declare_oxc_lint!(
impl Rule for NoIdenticalTitle {
fn run_once(&self, ctx: &LintContext) {
let possible_jest_nodes = collect_possible_jest_call_node(ctx);
let mut title_to_span_mapping = HashMap::new();
let mut span_to_parent_mapping = HashMap::new();
let mut title_to_span_mapping = FxHashMap::default();
let mut span_to_parent_mapping = FxHashMap::default();

possible_jest_nodes
.iter()
Expand Down
18 changes: 9 additions & 9 deletions crates/oxc_linter/src/rules/jest/no_standalone_expect.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::collections::HashMap;

use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::NodeId;
use oxc_span::Span;
use rustc_hash::FxHashMap;

use crate::{
context::LintContext,
Expand Down Expand Up @@ -76,10 +75,11 @@ impl Rule for NoStandaloneExpect {

fn run_once(&self, ctx: &LintContext<'_>) {
let possible_jest_nodes = collect_possible_jest_call_node(ctx);
let id_nodes_mapping = possible_jest_nodes.iter().fold(HashMap::new(), |mut acc, cur| {
acc.entry(cur.node.id()).or_insert(cur);
acc
});
let id_nodes_mapping =
possible_jest_nodes.iter().fold(FxHashMap::default(), |mut acc, cur| {
acc.entry(cur.node.id()).or_insert(cur);
acc
});

for possible_jest_node in &possible_jest_nodes {
self.run(possible_jest_node, &id_nodes_mapping, ctx);
Expand All @@ -91,7 +91,7 @@ impl NoStandaloneExpect {
fn run<'a>(
&self,
possible_jest_node: &PossibleJestNode<'a, '_>,
id_nodes_mapping: &HashMap<NodeId, &PossibleJestNode<'a, '_>>,
id_nodes_mapping: &FxHashMap<NodeId, &PossibleJestNode<'a, '_>>,
ctx: &LintContext<'a>,
) {
let node = possible_jest_node.node;
Expand Down Expand Up @@ -129,7 +129,7 @@ impl NoStandaloneExpect {
fn is_correct_place_to_call_expect<'a>(
node: &AstNode<'a>,
additional_test_block_functions: &[String],
id_nodes_mapping: &HashMap<NodeId, &PossibleJestNode<'a, '_>>,
id_nodes_mapping: &FxHashMap<NodeId, &PossibleJestNode<'a, '_>>,
ctx: &LintContext<'a>,
) -> Option<()> {
let mut parent = ctx.nodes().parent_node(node.id())?;
Expand Down Expand Up @@ -197,7 +197,7 @@ fn is_correct_place_to_call_expect<'a>(
fn is_var_declarator_or_test_block<'a>(
node: &AstNode<'a>,
additional_test_block_functions: &[String],
id_nodes_mapping: &HashMap<NodeId, &PossibleJestNode<'a, '_>>,
id_nodes_mapping: &FxHashMap<NodeId, &PossibleJestNode<'a, '_>>,
ctx: &LintContext<'a>,
) -> bool {
match node.kind() {
Expand Down
7 changes: 3 additions & 4 deletions crates/oxc_linter/src/rules/jest/prefer_hooks_on_top.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::collections::HashMap;

use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::ScopeId;
use oxc_span::Span;
use rustc_hash::FxHashMap;

use crate::{
context::LintContext,
Expand Down Expand Up @@ -141,7 +140,7 @@ declare_oxc_lint!(

impl Rule for PreferHooksOnTop {
fn run_once(&self, ctx: &LintContext) {
let mut hooks_contexts: HashMap<ScopeId, bool> = HashMap::default();
let mut hooks_contexts: FxHashMap<ScopeId, bool> = FxHashMap::default();
let mut possibles_jest_nodes = collect_possible_jest_call_node(ctx);
possibles_jest_nodes.sort_by_key(|n| n.node.id());

Expand All @@ -154,7 +153,7 @@ impl Rule for PreferHooksOnTop {
impl PreferHooksOnTop {
fn run<'a>(
possible_jest_node: &PossibleJestNode<'a, '_>,
hooks_context: &mut HashMap<ScopeId, bool>,
hooks_context: &mut FxHashMap<ScopeId, bool>,
ctx: &LintContext<'a>,
) {
let node = possible_jest_node.node;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::collections::HashMap;

use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::ScopeId;
use oxc_span::Span;
use rustc_hash::FxHashMap;

use crate::{
context::LintContext,
Expand Down Expand Up @@ -123,7 +122,7 @@ impl Rule for RequireTopLevelDescribe {
}

fn run_once(&self, ctx: &LintContext) {
let mut describe_contexts: HashMap<ScopeId, usize> = HashMap::new();
let mut describe_contexts: FxHashMap<ScopeId, usize> = FxHashMap::default();
let mut possibles_jest_nodes = collect_possible_jest_call_node(ctx);
possibles_jest_nodes.sort_by_key(|n| n.node.id());

Expand All @@ -137,7 +136,7 @@ impl RequireTopLevelDescribe {
fn run<'a>(
&self,
possible_jest_node: &PossibleJestNode<'a, '_>,
describe_contexts: &mut HashMap<ScopeId, usize>,
describe_contexts: &mut FxHashMap<ScopeId, usize>,
ctx: &LintContext<'a>,
) {
let node = possible_jest_node.node;
Expand Down
15 changes: 8 additions & 7 deletions crates/oxc_linter/src/rules/jest/valid_title.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashMap, hash::Hash};
use std::hash::Hash;

use cow_utils::CowUtils;
use oxc_ast::{
Expand All @@ -9,6 +9,7 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use regex::Regex;
use rustc_hash::FxHashMap;

use crate::{
context::LintContext,
Expand All @@ -31,8 +32,8 @@ pub struct ValidTitleConfig {
ignore_type_of_describe_name: bool,
disallowed_words: Vec<String>,
ignore_space: bool,
must_not_match_patterns: HashMap<MatchKind, CompiledMatcherAndMessage>,
must_match_patterns: HashMap<MatchKind, CompiledMatcherAndMessage>,
must_not_match_patterns: FxHashMap<MatchKind, CompiledMatcherAndMessage>,
must_match_patterns: FxHashMap<MatchKind, CompiledMatcherAndMessage>,
}

impl std::ops::Deref for ValidTitle {
Expand Down Expand Up @@ -206,14 +207,14 @@ impl MatchKind {

fn compile_matcher_patterns(
matcher_patterns: &serde_json::Value,
) -> Option<HashMap<MatchKind, CompiledMatcherAndMessage>> {
) -> Option<FxHashMap<MatchKind, CompiledMatcherAndMessage>> {
matcher_patterns
.as_array()
.map_or_else(
|| {
// for `{ "describe": "/pattern/" }`
let obj = matcher_patterns.as_object()?;
let mut map: HashMap<MatchKind, CompiledMatcherAndMessage> = HashMap::new();
let mut map: FxHashMap<MatchKind, CompiledMatcherAndMessage> = FxHashMap::default();
for (key, value) in obj {
let Some(v) = compile_matcher_pattern(MatcherPattern::String(value)) else {
continue;
Expand All @@ -227,7 +228,7 @@ fn compile_matcher_patterns(
},
|value| {
// for `["/pattern/", "message"]`
let mut map: HashMap<MatchKind, CompiledMatcherAndMessage> = HashMap::new();
let mut map: FxHashMap<MatchKind, CompiledMatcherAndMessage> = FxHashMap::default();
let v = &compile_matcher_pattern(MatcherPattern::Vec(value))?;
map.insert(MatchKind::Describe, v.clone());
map.insert(MatchKind::Test, v.clone());
Expand All @@ -239,7 +240,7 @@ fn compile_matcher_patterns(
|| {
// for `"/pattern/"`
let string = matcher_patterns.as_str()?;
let mut map: HashMap<MatchKind, CompiledMatcherAndMessage> = HashMap::new();
let mut map: FxHashMap<MatchKind, CompiledMatcherAndMessage> = FxHashMap::default();
let v = &compile_matcher_pattern(MatcherPattern::String(
&serde_json::Value::String(string.to_string()),
))?;
Expand Down
8 changes: 4 additions & 4 deletions crates/oxc_linter/src/rules/react/no_unknown_property.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{borrow::Cow, collections::hash_map::HashMap};
use std::borrow::Cow;

use cow_utils::CowUtils;
use itertools::Itertools;
Expand All @@ -12,7 +12,7 @@ use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use phf::{phf_map, phf_set, Map, Set};
use regex::Regex;
use rustc_hash::FxHashSet;
use rustc_hash::{FxHashMap, FxHashSet};
use serde::Deserialize;

use crate::{
Expand Down Expand Up @@ -426,11 +426,11 @@ const DOM_PROPERTIES_IGNORE_CASE: [&str; 5] = [
"webkitDirectory",
];

static DOM_PROPERTIES_LOWER_MAP: Lazy<HashMap<String, &'static str>> = Lazy::new(|| {
static DOM_PROPERTIES_LOWER_MAP: Lazy<FxHashMap<String, &'static str>> = Lazy::new(|| {
DOM_PROPERTIES_NAMES
.iter()
.map(|it| (it.cow_to_lowercase().into_owned(), *it))
.collect::<HashMap<_, _>>()
.collect::<FxHashMap<_, _>>()
});

///
Expand Down
Loading

0 comments on commit 2b17003

Please sign in to comment.