Skip to content
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

perf(linter): reduce the RuleEnum enum size from 168 to 16 bytes #1783

Merged
merged 2 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 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_linter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ oxc_macros = { workspace = true }
oxc_semantic = { workspace = true }
oxc_syntax = { workspace = true }
oxc_formatter = { workspace = true }
oxc_index = { workspace = true }
oxc_resolver = { version = "1.0.1" }

rayon = { workspace = true }
Expand Down
11 changes: 11 additions & 0 deletions crates/oxc_linter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ pub use crate::{
};
pub(crate) use rules::{RuleEnum, RULES};

#[cfg(target_pointer_width = "64")]
#[test]
fn size_asserts() {
use oxc_index::assert_eq_size;

// `RuleEnum` runs in a really tight loop, make sure it is small for CPU cache.
// A reduction from 168 bytes to 16 results 15% performance improvement.
// See codspeed in https://github.com/oxc-project/oxc/pull/1783
assert_eq_size!(RuleEnum, [u8; 16]);
}

#[derive(Debug, Clone)]
pub struct LintSettings {
jsx_a11y: JsxA11y,
Expand Down
17 changes: 14 additions & 3 deletions crates/oxc_linter/src/rules/eslint/no_bitwise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,22 @@ use crate::{context::LintContext, rule::Rule, AstNode};
struct NoBitwiseDiagnostic(&'static str, #[label] pub Span);

#[derive(Debug, Default, Clone)]
pub struct NoBitwise {
pub struct NoBitwise(Box<NoBitwiseConfig>);

#[derive(Debug, Default, Clone)]
pub struct NoBitwiseConfig {
allow: Vec<String>,
int32_hint: bool,
}

impl std::ops::Deref for NoBitwise {
type Target = NoBitwiseConfig;

fn deref(&self) -> &Self::Target {
&self.0
}
}

declare_oxc_lint!(
/// ### What it does
///
Expand All @@ -46,7 +57,7 @@ impl Rule for NoBitwise {
fn from_configuration(value: serde_json::Value) -> Self {
let obj = value.get(0);

Self {
Self(Box::new(NoBitwiseConfig {
allow: obj
.and_then(|v| v.get("allow"))
.and_then(serde_json::Value::as_array)
Expand All @@ -61,7 +72,7 @@ impl Rule for NoBitwise {
.and_then(|v| v.get("int32Hint"))
.and_then(serde_json::Value::as_bool)
.unwrap_or_default(),
}
}))
}

fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
Expand Down
17 changes: 14 additions & 3 deletions crates/oxc_linter/src/rules/eslint/no_console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ use crate::{context::LintContext, rule::Rule, AstNode};
struct NoConsoleDiagnostic(#[label] pub Span);

#[derive(Debug, Default, Clone)]
pub struct NoConsole {
pub struct NoConsole(Box<NoConsoleConfig>);

#[derive(Debug, Default, Clone)]
pub struct NoConsoleConfig {
/// A list of methods allowed to be used.
///
/// ```javascript
Expand All @@ -25,6 +28,14 @@ pub struct NoConsole {
pub allow: Vec<String>,
}

impl std::ops::Deref for NoConsole {
type Target = NoConsoleConfig;

fn deref(&self) -> &Self::Target {
&self.0
}
}

declare_oxc_lint!(
/// ### What it does
/// Disallows using the global console object.
Expand All @@ -45,7 +56,7 @@ declare_oxc_lint!(

impl Rule for NoConsole {
fn from_configuration(value: serde_json::Value) -> Self {
Self {
Self(Box::new(NoConsoleConfig {
allow: value
.get(0)
.and_then(|v| v.get("allow"))
Expand All @@ -57,7 +68,7 @@ impl Rule for NoConsole {
.collect()
})
.unwrap_or_default(),
}
}))
}

fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
Expand Down
17 changes: 14 additions & 3 deletions crates/oxc_linter/src/rules/eslint/no_global_assign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,21 @@ struct NoGlobalAssignDiagnostic(
);

#[derive(Debug, Default, Clone)]
pub struct NoGlobalAssign {
pub struct NoGlobalAssign(Box<NoGlobalAssignConfig>);

#[derive(Debug, Default, Clone)]
pub struct NoGlobalAssignConfig {
excludes: Vec<Atom>,
}

impl std::ops::Deref for NoGlobalAssign {
type Target = NoGlobalAssignConfig;

fn deref(&self) -> &Self::Target {
&self.0
}
}

declare_oxc_lint!(
/// ### What it does
/// Disallow modifications to read-only global variables.
Expand All @@ -39,7 +50,7 @@ impl Rule for NoGlobalAssign {
fn from_configuration(value: serde_json::Value) -> Self {
let obj = value.get(0);

Self {
Self(Box::new(NoGlobalAssignConfig {
excludes: obj
.and_then(|v| v.get("exceptions"))
.and_then(serde_json::Value::as_array)
Expand All @@ -49,7 +60,7 @@ impl Rule for NoGlobalAssign {
.filter(std::option::Option::is_some)
.map(|x| Atom::from(x.unwrap().to_string()))
.collect::<Vec<Atom>>(),
}
}))
}

fn run_once(&self, ctx: &LintContext) {
Expand Down
24 changes: 19 additions & 5 deletions crates/oxc_linter/src/rules/eslint/no_mixed_operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,26 @@ struct NoMixedOperatorsDiagnostic(
#[label] pub Span, /*Span of the parent operator */
);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NoMixedOperators {
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct NoMixedOperators(Box<NoMixedOperatorsConfig>);

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct NoMixedOperatorsConfig {
/// Disallow Mixed operators within one group.
groups: Vec<Vec<&'static str>>,
/// Allow operators of the same precedence to be mixed.
allow_same_precedence: bool,
}

impl Default for NoMixedOperators {
impl std::ops::Deref for NoMixedOperators {
type Target = NoMixedOperatorsConfig;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl Default for NoMixedOperatorsConfig {
fn default() -> Self {
Self { groups: default_groups(), allow_same_precedence: true }
}
Expand Down Expand Up @@ -116,7 +127,7 @@ impl NoMixedOperators {
let allow_same_precedence =
config.get("allowSamePrecedence").map_or(true, |val| val.as_bool().unwrap_or_default());

Some(Self { groups, allow_same_precedence })
Some(Self(Box::new(NoMixedOperatorsConfig { groups, allow_same_precedence })))
}

fn is_mixed_with_parent(node: AstKind, parent: AstKind) -> bool {
Expand Down Expand Up @@ -356,7 +367,10 @@ mod internal_tests {
]);
let rule = NoMixedOperators::try_from_configuration(&config);
// missing groups should fall back to default
let expected = NoMixedOperators { groups: default_groups(), allow_same_precedence: false };
let expected = NoMixedOperators(Box::new(NoMixedOperatorsConfig {
groups: default_groups(),
allow_same_precedence: false,
}));
assert_eq!(Some(expected), rule);
}
}
20 changes: 17 additions & 3 deletions crates/oxc_linter/src/rules/jest/expect_expect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,24 @@ use crate::{
#[diagnostic(severity(warning), help("Add assertion(s) in this Test"))]
struct ExpectExpectDiagnostic(#[label] pub Span);

#[derive(Debug, Default, Clone)]
pub struct ExpectExpect(Box<ExpectExpectConfig>);

#[derive(Debug, Clone)]
pub struct ExpectExpect {
pub struct ExpectExpectConfig {
assert_function_names: Vec<String>,
additional_test_block_functions: Vec<String>,
}

impl Default for ExpectExpect {
impl std::ops::Deref for ExpectExpect {
type Target = ExpectExpectConfig;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl Default for ExpectExpectConfig {
fn default() -> Self {
Self {
assert_function_names: vec![String::from("expect")],
Expand Down Expand Up @@ -81,7 +92,10 @@ impl Rule for ExpectExpect {
})
.unwrap_or_default();

Self { assert_function_names, additional_test_block_functions }
Self(Box::new(ExpectExpectConfig {
assert_function_names,
additional_test_block_functions,
}))
}
fn run_once(&self, ctx: &LintContext) {
for possible_jest_node in &collect_possible_jest_call_node(ctx) {
Expand Down
21 changes: 17 additions & 4 deletions crates/oxc_linter/src/rules/jest/no_deprecated_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,23 @@ pub struct DeprecatedFunction(pub String, pub String, #[label] pub Span);

#[derive(Debug, Default, Clone)]
pub struct JestConfig {
pub version: String,
version: String,
}

#[derive(Debug, Default, Clone)]
pub struct NoDeprecatedFunctions {
pub jest: JestConfig,
pub struct NoDeprecatedFunctions(Box<NoDeprecatedFunctionsConfig>);

#[derive(Debug, Default, Clone)]
pub struct NoDeprecatedFunctionsConfig {
jest: JestConfig,
}

impl std::ops::Deref for NoDeprecatedFunctions {
type Target = NoDeprecatedFunctionsConfig;

fn deref(&self) -> &Self::Target {
&self.0
}
}

declare_oxc_lint!(
Expand Down Expand Up @@ -91,7 +102,9 @@ impl Rule for NoDeprecatedFunctions {

let major: Vec<&str> = version.split('.').collect();

Self { jest: JestConfig { version: major[0].to_string() } }
Self(Box::new(NoDeprecatedFunctionsConfig {
jest: JestConfig { version: major[0].to_string() },
}))
}

fn run<'a>(&self, node: &oxc_semantic::AstNode<'a>, ctx: &LintContext<'a>) {
Expand Down
17 changes: 14 additions & 3 deletions crates/oxc_linter/src/rules/jest/no_hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,19 @@ use crate::{
pub struct UnexpectedHookDiagonsitc(#[label] pub Span);

#[derive(Debug, Default, Clone)]
pub struct NoHooks {
pub allow: Vec<String>,
pub struct NoHooks(Box<NoHooksConfig>);

#[derive(Debug, Default, Clone)]
pub struct NoHooksConfig {
allow: Vec<String>,
}

impl std::ops::Deref for NoHooks {
type Target = NoHooksConfig;

fn deref(&self) -> &Self::Target {
&self.0
}
}

declare_oxc_lint!(
Expand Down Expand Up @@ -84,7 +95,7 @@ impl Rule for NoHooks {
})
.unwrap_or_default();

Self { allow }
Self(Box::new(NoHooksConfig { allow }))
}

fn run_once(&self, ctx: &LintContext) {
Expand Down
15 changes: 13 additions & 2 deletions crates/oxc_linter/src/rules/jest/no_standalone_expect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,21 @@ struct NoStandaloneExpectDiagnostic(#[label] pub Span);

/// <https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-standalone-expect.md>
#[derive(Debug, Default, Clone)]
pub struct NoStandaloneExpect {
pub struct NoStandaloneExpect(Box<NoStandaloneExpectConfig>);

#[derive(Debug, Default, Clone)]
pub struct NoStandaloneExpectConfig {
additional_test_block_functions: Vec<String>,
}

impl std::ops::Deref for NoStandaloneExpect {
type Target = NoStandaloneExpectConfig;

fn deref(&self) -> &Self::Target {
&self.0
}
}

declare_oxc_lint!(
/// ### What it does
///
Expand Down Expand Up @@ -62,7 +73,7 @@ impl Rule for NoStandaloneExpect {
})
.unwrap_or_default();

Self { additional_test_block_functions }
Self(Box::new(NoStandaloneExpectConfig { additional_test_block_functions }))
}
fn run_once(&self, ctx: &LintContext<'_>) {
let possible_jest_nodes = collect_possible_jest_call_node(ctx);
Expand Down
17 changes: 14 additions & 3 deletions crates/oxc_linter/src/rules/jest/valid_expect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,26 @@ use crate::{
#[diagnostic(severity(warning), help("{1:?}"))]
struct ValidExpectDiagnostic(pub Atom, pub &'static str, #[label] pub Span);

#[derive(Debug, Default, Clone)]
pub struct ValidExpect(Box<ValidExpectConfig>);

#[derive(Debug, Clone)]
pub struct ValidExpect {
pub struct ValidExpectConfig {
async_matchers: Vec<String>,
min_args: usize,
max_args: usize,
always_await: bool,
}

impl Default for ValidExpect {
impl std::ops::Deref for ValidExpect {
type Target = ValidExpectConfig;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl Default for ValidExpectConfig {
fn default() -> Self {
Self {
async_matchers: vec![String::from("toResolve"), String::from("toReject")],
Expand Down Expand Up @@ -88,7 +99,7 @@ impl Rule for ValidExpect {
.and_then(serde_json::Value::as_bool)
.unwrap_or(false);

Self { async_matchers, min_args, max_args, always_await }
Self(Box::new(ValidExpectConfig { async_matchers, min_args, max_args, always_await }))
}
fn run_once(&self, ctx: &LintContext) {
for possible_jest_node in &collect_possible_jest_call_node(ctx) {
Expand Down
Loading