From 6af5d2b23f6b62a76dc3fa40b425828330fff4db Mon Sep 17 00:00:00 2001 From: Daniel Frederico Lins Leite Date: Wed, 3 Aug 2022 22:40:47 +0100 Subject: [PATCH] feat(rome_js_analyze): no shadow restricted lint rule (#2975) * no shadow restricted lint rule --- Cargo.lock | 110 ++++++++--- Cargo.toml | 1 + crates/rome_analyze/src/rule.rs | 2 +- crates/rome_js_analyze/Cargo.toml | 8 - crates/rome_js_analyze/benches/iai.rs | 32 ---- crates/rome_js_analyze/src/analyzers.rs | 8 +- crates/rome_js_analyze/src/analyzers/js.rs | 3 +- .../js/no_shadow_restricted_names.rs | 147 +++++++++++++++ crates/rome_js_analyze/src/analyzers/jsx.rs | 2 +- crates/rome_js_analyze/src/analyzers/regex.rs | 2 +- crates/rome_js_analyze/src/analyzers/ts.rs | 2 +- crates/rome_js_analyze/src/assists.rs | 2 +- crates/rome_js_analyze/src/assists/js.rs | 2 +- .../rome_js_analyze/src/semantic_analyzers.rs | 2 +- .../src/semantic_analyzers/js.rs | 2 +- .../tests/specs/js/noShadowRestrictedNames.js | 13 ++ .../specs/js/noShadowRestrictedNames.js.snap | 108 +++++++++++ .../src/configuration/linter/rules.rs | 8 +- website/src/docs/lint/rules/index.md | 8 + .../lint/rules/noShadowRestrictedNames.md | 85 +++++++++ xtask/codegen/src/generate_analyzer.rs | 4 +- xtask/codegen/src/main.rs | 26 ++- xtask/libs_bench/Cargo.toml | 34 ++++ xtask/libs_bench/benches/contains.rs | 174 ++++++++++++++++++ .../libs_bench/benches/contains_criterion.rs | 109 +++++++++++ xtask/libs_bench/benches/contains_iai.rs | 25 +++ xtask/libs_bench/benches/to_camel_case.rs | 32 ++++ xtask/libs_bench/bins/contains_iai.rs | 58 ++++++ xtask/libs_bench/src/main.rs | 1 + 29 files changed, 923 insertions(+), 87 deletions(-) delete mode 100644 crates/rome_js_analyze/benches/iai.rs create mode 100644 crates/rome_js_analyze/src/analyzers/js/no_shadow_restricted_names.rs create mode 100644 crates/rome_js_analyze/tests/specs/js/noShadowRestrictedNames.js create mode 100644 crates/rome_js_analyze/tests/specs/js/noShadowRestrictedNames.js.snap create mode 100644 website/src/docs/lint/rules/noShadowRestrictedNames.md create mode 100644 xtask/libs_bench/Cargo.toml create mode 100644 xtask/libs_bench/benches/contains.rs create mode 100644 xtask/libs_bench/benches/contains_criterion.rs create mode 100644 xtask/libs_bench/benches/contains_iai.rs create mode 100644 xtask/libs_bench/benches/to_camel_case.rs create mode 100644 xtask/libs_bench/bins/contains_iai.rs create mode 100644 xtask/libs_bench/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index ec1273c0246..b9bf8d7cfd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,9 +143,9 @@ checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "bytemuck" -version = "1.7.3" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" +checksum = "a5377c8865e74a160d21f29c2d40669f53286db6eab59b88540cbb12ffc8b835" [[package]] name = "byteorder" @@ -466,6 +466,21 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fastbloom-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4344cba847020b5d848f5538f2638a798067b7e31c5517690c35d6a96919619" +dependencies = [ + "fastmurmur3", +] + +[[package]] +name = "fastmurmur3" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d922f481ae01f2a3f1fff7b9e0e789f18f0c755a38ec983a3e6f37762cdcc2a2" + [[package]] name = "filetime" version = "0.2.15" @@ -515,6 +530,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fst" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" + [[package]] name = "futures" version = "0.3.19" @@ -836,9 +857,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.124" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "libgit2-sys" @@ -890,9 +911,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] @@ -927,9 +948,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" @@ -991,6 +1012,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + [[package]] name = "ntapi" version = "0.3.6" @@ -1036,9 +1063,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" [[package]] name = "oorandom" @@ -1191,6 +1218,16 @@ dependencies = [ "unicase", ] +[[package]] +name = "qp-trie" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a075ecba64154fed5429568c9c6a0e0eccc3276209e93e6133206413ea6834b4" +dependencies = [ + "new_debug_unreachable", + "unreachable", +] + [[package]] name = "quickcheck" version = "1.0.3" @@ -1242,9 +1279,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" dependencies = [ "autocfg", "crossbeam-deque", @@ -1254,14 +1291,13 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] @@ -1276,9 +1312,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.5" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -1296,9 +1332,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "retain_mut" @@ -1462,9 +1498,7 @@ dependencies = [ name = "rome_js_analyze" version = "0.0.0" dependencies = [ - "case", "countme", - "iai", "insta", "roaring", "rome_analyze", @@ -1787,9 +1821,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" dependencies = [ "itoa 1.0.1", "ryu", @@ -2274,6 +2308,15 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + [[package]] name = "untrusted" version = "0.7.1" @@ -2328,6 +2371,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "walkdir" version = "2.3.2" @@ -2587,6 +2636,21 @@ dependencies = [ "yastl", ] +[[package]] +name = "xtask_libs_bench" +version = "0.0.0" +dependencies = [ + "case", + "criterion", + "fastbloom-rs", + "fst", + "iai", + "memchr", + "qp-trie", + "regex", + "rome_js_analyze", +] + [[package]] name = "xtask_lintdoc" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index ed683022d66..c2d01f9aff1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ "xtask/codegen", "xtask/coverage", "xtask/lintdoc", + "xtask/libs_bench", ] [profile.release-with-debug] diff --git a/crates/rome_analyze/src/rule.rs b/crates/rome_analyze/src/rule.rs index 4b38f89f2fa..6b101da8313 100644 --- a/crates/rome_analyze/src/rule.rs +++ b/crates/rome_analyze/src/rule.rs @@ -214,7 +214,7 @@ macro_rules! impl_group_language { impl_group_language!( T00, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, - T19 + T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29 ); /// Trait implemented by all analysis rules: declares interest to a certain AstNode type, diff --git a/crates/rome_js_analyze/Cargo.toml b/crates/rome_js_analyze/Cargo.toml index 1d6b6741d13..3938737d02d 100644 --- a/crates/rome_js_analyze/Cargo.toml +++ b/crates/rome_js_analyze/Cargo.toml @@ -5,8 +5,6 @@ edition = "2021" authors = ["Rome Tools Developers and Contributros"] license = "MIT" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] rome_analyze = { path = "../rome_analyze" } rome_control_flow = { path = "../rome_control_flow" } @@ -18,7 +16,6 @@ rome_console = { path = "../rome_console" } rome_diagnostics = { path = "../rome_diagnostics" } roaring = "0.9.0" rustc-hash = "1.1.0" -iai = "0.1.1" [dev-dependencies] tests_macros = { path = "../tests_macros" } @@ -26,8 +23,3 @@ rome_text_edit = { path = "../rome_text_edit" } rome_js_parser = { path = "../rome_js_parser", features = ["tests"] } insta = { version = "1.10.0", features = ["glob"] } countme = { version = "3.0.0", features = ["enable"] } -case = "1.0.0" - -[[bench]] -name = "iai" -harness = false diff --git a/crates/rome_js_analyze/benches/iai.rs b/crates/rome_js_analyze/benches/iai.rs deleted file mode 100644 index 6146d281454..00000000000 --- a/crates/rome_js_analyze/benches/iai.rs +++ /dev/null @@ -1,32 +0,0 @@ -fn rome_all_lowercase() { - let _ = rome_js_analyze::utils::to_camel_case(iai::black_box("lowercase")); -} - -fn case_all_lowercase() { - let _ = case::CaseExt::to_camel(iai::black_box("lowercase")); -} - -fn rome_already_camel_case() { - let _ = rome_js_analyze::utils::to_camel_case(iai::black_box("camelCase")); -} - -fn case_already_camel_case() { - let _ = case::CaseExt::to_camel(iai::black_box("camelCase")); -} - -fn rome_pascal_case() { - let _ = rome_js_analyze::utils::to_camel_case(iai::black_box("CamelCase")); -} - -fn case_pascal_case() { - let _ = case::CaseExt::to_camel(iai::black_box("CamelCase")); -} - -iai::main!( - rome_all_lowercase, - case_all_lowercase, - rome_already_camel_case, - case_already_camel_case, - rome_pascal_case, - case_pascal_case -); diff --git a/crates/rome_js_analyze/src/analyzers.rs b/crates/rome_js_analyze/src/analyzers.rs index 50a19cc1a3c..0dbb51a6d95 100644 --- a/crates/rome_js_analyze/src/analyzers.rs +++ b/crates/rome_js_analyze/src/analyzers.rs @@ -1,10 +1,10 @@ //! Generated file, do not edit by hand, see `xtask/codegen` mod js; -pub(super) use js::Js; +pub(super) use self::js::Js; mod jsx; -pub(super) use jsx::Jsx; +pub(super) use self::jsx::Jsx; mod regex; -pub(super) use regex::Regex; +pub(super) use self::regex::Regex; mod ts; -pub(super) use ts::Ts; +pub(super) use self::ts::Ts; diff --git a/crates/rome_js_analyze/src/analyzers/js.rs b/crates/rome_js_analyze/src/analyzers/js.rs index b296cb2af84..0dbfccea325 100644 --- a/crates/rome_js_analyze/src/analyzers/js.rs +++ b/crates/rome_js_analyze/src/analyzers/js.rs @@ -10,6 +10,7 @@ mod no_double_equals; mod no_empty_pattern; mod no_extra_boolean_cast; mod no_negation_else; +mod no_shadow_restricted_names; mod no_sparse_array; mod no_unnecessary_continue; mod no_unsafe_negation; @@ -21,4 +22,4 @@ mod use_single_var_declarator; mod use_template; mod use_valid_typeof; mod use_while; -declare_group! { pub (crate) Js { name : "js" , rules : [no_async_promise_executor :: NoAsyncPromiseExecutor , no_compare_neg_zero :: NoCompareNegZero , no_dead_code :: NoDeadCode , no_debugger :: NoDebugger , no_delete :: NoDelete , no_double_equals :: NoDoubleEquals , no_empty_pattern :: NoEmptyPattern , no_extra_boolean_cast :: NoExtraBooleanCast , no_negation_else :: NoNegationElse , no_sparse_array :: NoSparseArray , no_unnecessary_continue :: NoUnnecessaryContinue , no_unsafe_negation :: NoUnsafeNegation , no_unused_template_literal :: NoUnusedTemplateLiteral , use_block_statements :: UseBlockStatements , use_simplified_logic_expression :: UseSimplifiedLogicExpression , use_single_case_statement :: UseSingleCaseStatement , use_single_var_declarator :: UseSingleVarDeclarator , use_template :: UseTemplate , use_valid_typeof :: UseValidTypeof , use_while :: UseWhile ,] } } +declare_group! { pub (crate) Js { name : "js" , rules : [self :: no_async_promise_executor :: NoAsyncPromiseExecutor , self :: no_compare_neg_zero :: NoCompareNegZero , self :: no_dead_code :: NoDeadCode , self :: no_debugger :: NoDebugger , self :: no_delete :: NoDelete , self :: no_double_equals :: NoDoubleEquals , self :: no_empty_pattern :: NoEmptyPattern , self :: no_extra_boolean_cast :: NoExtraBooleanCast , self :: no_negation_else :: NoNegationElse , self :: no_shadow_restricted_names :: NoShadowRestrictedNames , self :: no_sparse_array :: NoSparseArray , self :: no_unnecessary_continue :: NoUnnecessaryContinue , self :: no_unsafe_negation :: NoUnsafeNegation , self :: no_unused_template_literal :: NoUnusedTemplateLiteral , self :: use_block_statements :: UseBlockStatements , self :: use_simplified_logic_expression :: UseSimplifiedLogicExpression , self :: use_single_case_statement :: UseSingleCaseStatement , self :: use_single_var_declarator :: UseSingleVarDeclarator , self :: use_template :: UseTemplate , self :: use_valid_typeof :: UseValidTypeof , self :: use_while :: UseWhile ,] } } diff --git a/crates/rome_js_analyze/src/analyzers/js/no_shadow_restricted_names.rs b/crates/rome_js_analyze/src/analyzers/js/no_shadow_restricted_names.rs new file mode 100644 index 00000000000..2ead8af28b5 --- /dev/null +++ b/crates/rome_js_analyze/src/analyzers/js/no_shadow_restricted_names.rs @@ -0,0 +1,147 @@ +use rome_analyze::{context::RuleContext, declare_rule, Ast, Rule, RuleCategory, RuleDiagnostic}; +use rome_console::markup; +use rome_js_syntax::JsIdentifierBinding; +use rome_rowan::AstNode; + +declare_rule! { + /// Disallow identifiers from shadowing restricted names. + /// + /// ## Examples + /// + /// ### Invalid + /// + /// ```js,expect_diagnostic + /// function NaN() {} + /// ``` + /// + /// ```js,expect_diagnostic + /// let Set; + /// ``` + /// + /// ```js,expect_diagnostic + /// try { } catch(Object) {} + /// ``` + /// + /// ```js,expect_diagnostic + /// function Array() {} + /// ``` + /// + /// ```js,expect_diagnostic + /// function test(JSON) {console.log(JSON)} + /// ``` + pub(crate) NoShadowRestrictedNames { + version: "0.9.0", + name: "noShadowRestrictedNames", + recommended: true, + } +} + +const RESTRICTED_NAMES: [&str; 65] = [ + "Array", + "ArrayBuffer", + "Atomics", + "BigInt", + "BigInt64Array", + "BigUint64Array", + "Boolean", + "constructor", + "DataView", + "Date", + "decodeURI", + "decodeURIComponent", + "encodeURI", + "encodeURIComponent", + "Error", + "escape", + "eval", + "EvalError", + "FinalizationRegistry", + "Float32Array", + "Float64Array", + "Function", + "globalThis", + "hasOwnProperty", + "Infinity", + "Int16Array", + "Int32Array", + "Int8Array", + "isFinite", + "isNaN", + "isPrototypeOf", + "JSON", + "Map", + "Math", + "NaN", + "Number", + "Object", + "parseFloat", + "parseInt", + "Promise", + "propertyIsEnumerable", + "Proxy", + "RangeError", + "ReferenceError", + "Reflect", + "RegExp", + "Set", + "SharedArrayBuffer", + "String", + "Symbol", + "SyntaxError", + "toLocaleString", + "toString", + "TypeError", + "Uint16Array", + "Uint32Array", + "Uint8Array", + "Uint8ClampedArray", + "undefined", + "unescape", + "URIError", + "valueOf", + "WeakMap", + "WeakRef", + "WeakSet", +]; + +pub struct State { + shadowed_name: String, +} + +impl Rule for NoShadowRestrictedNames { + const CATEGORY: RuleCategory = RuleCategory::Lint; + + type Query = Ast; + type State = State; + type Signals = Option; + + fn run(ctx: &RuleContext) -> Option { + let binding = ctx.query(); + let name = binding.name_token().ok()?; + let name = name.text_trimmed(); + + if RESTRICTED_NAMES.contains(&name) { + Some(State { + shadowed_name: name.to_string(), + }) + } else { + None + } + } + + fn diagnostic(ctx: &RuleContext, state: &Self::State) -> Option { + let binding = ctx.query(); + + let diag = RuleDiagnostic::warning( + binding.syntax().text_trimmed_range(), + markup! { + "Do not shadow the global \"" {state.shadowed_name} "\" property." + }, + ) + .footer_note( + markup! {"Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global."}, + ); + + Some(diag) + } +} diff --git a/crates/rome_js_analyze/src/analyzers/jsx.rs b/crates/rome_js_analyze/src/analyzers/jsx.rs index 6962ee86966..3148dc4812f 100644 --- a/crates/rome_js_analyze/src/analyzers/jsx.rs +++ b/crates/rome_js_analyze/src/analyzers/jsx.rs @@ -4,4 +4,4 @@ use rome_analyze::declare_group; mod no_comment_text; mod no_implicit_boolean; mod use_self_closing_elements; -declare_group! { pub (crate) Jsx { name : "jsx" , rules : [no_comment_text :: NoCommentText , no_implicit_boolean :: NoImplicitBoolean , use_self_closing_elements :: UseSelfClosingElements ,] } } +declare_group! { pub (crate) Jsx { name : "jsx" , rules : [self :: no_comment_text :: NoCommentText , self :: no_implicit_boolean :: NoImplicitBoolean , self :: use_self_closing_elements :: UseSelfClosingElements ,] } } diff --git a/crates/rome_js_analyze/src/analyzers/regex.rs b/crates/rome_js_analyze/src/analyzers/regex.rs index fef7c34d482..6dfc870eced 100644 --- a/crates/rome_js_analyze/src/analyzers/regex.rs +++ b/crates/rome_js_analyze/src/analyzers/regex.rs @@ -2,4 +2,4 @@ use rome_analyze::declare_group; mod no_multiple_spaces_in_regular_expression_literals; -declare_group! { pub (crate) Regex { name : "regex" , rules : [no_multiple_spaces_in_regular_expression_literals :: NoMultipleSpacesInRegularExpressionLiterals ,] } } +declare_group! { pub (crate) Regex { name : "regex" , rules : [self :: no_multiple_spaces_in_regular_expression_literals :: NoMultipleSpacesInRegularExpressionLiterals ,] } } diff --git a/crates/rome_js_analyze/src/analyzers/ts.rs b/crates/rome_js_analyze/src/analyzers/ts.rs index b07d2ac04a1..832cff5d9ea 100644 --- a/crates/rome_js_analyze/src/analyzers/ts.rs +++ b/crates/rome_js_analyze/src/analyzers/ts.rs @@ -2,4 +2,4 @@ use rome_analyze::declare_group; mod use_shorthand_array_type; -declare_group! { pub (crate) Ts { name : "ts" , rules : [use_shorthand_array_type :: UseShorthandArrayType ,] } } +declare_group! { pub (crate) Ts { name : "ts" , rules : [self :: use_shorthand_array_type :: UseShorthandArrayType ,] } } diff --git a/crates/rome_js_analyze/src/assists.rs b/crates/rome_js_analyze/src/assists.rs index debee3dc56f..32a6ba28111 100644 --- a/crates/rome_js_analyze/src/assists.rs +++ b/crates/rome_js_analyze/src/assists.rs @@ -1,4 +1,4 @@ //! Generated file, do not edit by hand, see `xtask/codegen` mod js; -pub(super) use js::Js; +pub(super) use self::js::Js; diff --git a/crates/rome_js_analyze/src/assists/js.rs b/crates/rome_js_analyze/src/assists/js.rs index 5f075fe8b55..bedb4e149ab 100644 --- a/crates/rome_js_analyze/src/assists/js.rs +++ b/crates/rome_js_analyze/src/assists/js.rs @@ -2,4 +2,4 @@ use rome_analyze::declare_group; mod flip_bin_exp; -declare_group! { pub (crate) Js { name : "js" , rules : [flip_bin_exp :: FlipBinExp ,] } } +declare_group! { pub (crate) Js { name : "js" , rules : [self :: flip_bin_exp :: FlipBinExp ,] } } diff --git a/crates/rome_js_analyze/src/semantic_analyzers.rs b/crates/rome_js_analyze/src/semantic_analyzers.rs index debee3dc56f..32a6ba28111 100644 --- a/crates/rome_js_analyze/src/semantic_analyzers.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers.rs @@ -1,4 +1,4 @@ //! Generated file, do not edit by hand, see `xtask/codegen` mod js; -pub(super) use js::Js; +pub(super) use self::js::Js; diff --git a/crates/rome_js_analyze/src/semantic_analyzers/js.rs b/crates/rome_js_analyze/src/semantic_analyzers/js.rs index 207463ba657..84fd3e19d16 100644 --- a/crates/rome_js_analyze/src/semantic_analyzers/js.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers/js.rs @@ -9,4 +9,4 @@ mod no_label_var; mod no_shouty_constants; mod no_unused_variables; mod use_camel_case; -declare_group! { pub (crate) Js { name : "js" , rules : [no_arguments :: NoArguments , no_catch_assign :: NoCatchAssign , no_function_assign :: NoFunctionAssign , no_import_assign :: NoImportAssign , no_label_var :: NoLabelVar , no_shouty_constants :: NoShoutyConstants , no_unused_variables :: NoUnusedVariables , use_camel_case :: UseCamelCase ,] } } +declare_group! { pub (crate) Js { name : "js" , rules : [self :: no_arguments :: NoArguments , self :: no_catch_assign :: NoCatchAssign , self :: no_function_assign :: NoFunctionAssign , self :: no_import_assign :: NoImportAssign , self :: no_label_var :: NoLabelVar , self :: no_shouty_constants :: NoShoutyConstants , self :: no_unused_variables :: NoUnusedVariables , self :: use_camel_case :: UseCamelCase ,] } } diff --git a/crates/rome_js_analyze/tests/specs/js/noShadowRestrictedNames.js b/crates/rome_js_analyze/tests/specs/js/noShadowRestrictedNames.js new file mode 100644 index 00000000000..23b42a92b37 --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/js/noShadowRestrictedNames.js @@ -0,0 +1,13 @@ +function NaN() {} +function undefined() {} +function Infinity() {} +//function arguments() {} +//function eval() {} +function Array() {} + +function test(JSON) { + console.log(JSON); +} +let Set; +try { +} catch (Object) {} diff --git a/crates/rome_js_analyze/tests/specs/js/noShadowRestrictedNames.js.snap b/crates/rome_js_analyze/tests/specs/js/noShadowRestrictedNames.js.snap new file mode 100644 index 00000000000..afd9347d8d0 --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/js/noShadowRestrictedNames.js.snap @@ -0,0 +1,108 @@ +--- +source: crates/rome_js_analyze/tests/spec_tests.rs +expression: noShadowRestrictedNames.js +--- +# Input +```js +function NaN() {} +function undefined() {} +function Infinity() {} +//function arguments() {} +//function eval() {} +function Array() {} + +function test(JSON) { + console.log(JSON); +} +let Set; +try { +} catch (Object) {} + +``` + +# Diagnostics +``` +warning[js/noShadowRestrictedNames]: Do not shadow the global "NaN" property. + ┌─ noShadowRestrictedNames.js:1:10 + │ +1 │ function NaN() {} + │ --- + += note: Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global. + + +``` + +``` +warning[js/noShadowRestrictedNames]: Do not shadow the global "undefined" property. + ┌─ noShadowRestrictedNames.js:2:10 + │ +2 │ function undefined() {} + │ --------- + += note: Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global. + + +``` + +``` +warning[js/noShadowRestrictedNames]: Do not shadow the global "Infinity" property. + ┌─ noShadowRestrictedNames.js:3:10 + │ +3 │ function Infinity() {} + │ -------- + += note: Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global. + + +``` + +``` +warning[js/noShadowRestrictedNames]: Do not shadow the global "Array" property. + ┌─ noShadowRestrictedNames.js:6:10 + │ +6 │ function Array() {} + │ ----- + += note: Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global. + + +``` + +``` +warning[js/noShadowRestrictedNames]: Do not shadow the global "JSON" property. + ┌─ noShadowRestrictedNames.js:8:15 + │ +8 │ function test(JSON) { + │ ---- + += note: Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global. + + +``` + +``` +warning[js/noShadowRestrictedNames]: Do not shadow the global "Set" property. + ┌─ noShadowRestrictedNames.js:11:5 + │ +11 │ let Set; + │ --- + += note: Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global. + + +``` + +``` +warning[js/noShadowRestrictedNames]: Do not shadow the global "Object" property. + ┌─ noShadowRestrictedNames.js:13:10 + │ +13 │ } catch (Object) {} + │ ------ + += note: Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global. + + +``` + + diff --git a/crates/rome_service/src/configuration/linter/rules.rs b/crates/rome_service/src/configuration/linter/rules.rs index d2a46ca6c51..225dbbe65e5 100644 --- a/crates/rome_service/src/configuration/linter/rules.rs +++ b/crates/rome_service/src/configuration/linter/rules.rs @@ -131,7 +131,7 @@ pub struct Js { } impl Js { const GROUP_NAME: &'static str = "js"; - pub(crate) const GROUP_RULES: [&'static str; 28] = [ + pub(crate) const GROUP_RULES: [&'static str; 29] = [ "noArguments", "noAsyncPromiseExecutor", "noCatchAssign", @@ -146,6 +146,7 @@ impl Js { "noImportAssign", "noLabelVar", "noNegationElse", + "noShadowRestrictedNames", "noShoutyConstants", "noSparseArray", "noUnnecessaryContinue", @@ -161,7 +162,7 @@ impl Js { "useValidTypeof", "useWhile", ]; - const RECOMMENDED_RULES: [RuleFilter<'static>; 26] = [ + const RECOMMENDED_RULES: [RuleFilter<'static>; 27] = [ RuleFilter::Rule("js", Self::GROUP_RULES[0]), RuleFilter::Rule("js", Self::GROUP_RULES[1]), RuleFilter::Rule("js", Self::GROUP_RULES[2]), @@ -182,12 +183,13 @@ impl Js { RuleFilter::Rule("js", Self::GROUP_RULES[18]), RuleFilter::Rule("js", Self::GROUP_RULES[19]), RuleFilter::Rule("js", Self::GROUP_RULES[20]), - RuleFilter::Rule("js", Self::GROUP_RULES[22]), + RuleFilter::Rule("js", Self::GROUP_RULES[21]), RuleFilter::Rule("js", Self::GROUP_RULES[23]), RuleFilter::Rule("js", Self::GROUP_RULES[24]), RuleFilter::Rule("js", Self::GROUP_RULES[25]), RuleFilter::Rule("js", Self::GROUP_RULES[26]), RuleFilter::Rule("js", Self::GROUP_RULES[27]), + RuleFilter::Rule("js", Self::GROUP_RULES[28]), ]; pub(crate) fn is_recommended(&self) -> bool { matches!(self.recommended, Some(true)) } pub(crate) fn get_enabled_rules(&self) -> IndexSet { diff --git a/website/src/docs/lint/rules/index.md b/website/src/docs/lint/rules/index.md index 199fefea3ac..2b1cef2ff71 100644 --- a/website/src/docs/lint/rules/index.md +++ b/website/src/docs/lint/rules/index.md @@ -125,6 +125,14 @@ Disallow labels that share a name with a variable Disallow negation in the condition of an if statement if it has an else clause
+

+ noShadowRestrictedNames (since v0.9.0) + + recommended +

+Disallow identifiers from shadowing restricted names. +
+

noShoutyConstants (since v0.7.0) diff --git a/website/src/docs/lint/rules/noShadowRestrictedNames.md b/website/src/docs/lint/rules/noShadowRestrictedNames.md new file mode 100644 index 00000000000..585270a1a35 --- /dev/null +++ b/website/src/docs/lint/rules/noShadowRestrictedNames.md @@ -0,0 +1,85 @@ +--- +title: Lint Rule noShadowRestrictedNames +layout: layouts/rule.liquid +--- + +# noShadowRestrictedNames (since v0.9.0) + +> This rule is recommended by Rome. + +Disallow identifiers from shadowing restricted names. + +## Examples + +### Invalid + +```jsx +function NaN() {} +``` + +{% raw %}
warning[js/noShadowRestrictedNames]: Do not shadow the global "NaN" property.
+   js/noShadowRestrictedNames.js:1:10
+  
+1  function NaN() {}
+            ---
+
+=  note: Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.
+
+
{% endraw %} + +```jsx +let Set; +``` + +{% raw %}
warning[js/noShadowRestrictedNames]: Do not shadow the global "Set" property.
+   js/noShadowRestrictedNames.js:1:5
+  
+1  let Set;
+       ---
+
+=  note: Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.
+
+
{% endraw %} + +```jsx +try { } catch(Object) {} +``` + +{% raw %}
warning[js/noShadowRestrictedNames]: Do not shadow the global "Object" property.
+   js/noShadowRestrictedNames.js:1:15
+  
+1  try {   } catch(Object) {}
+                   ------
+
+=  note: Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.
+
+
{% endraw %} + +```jsx +function Array() {} +``` + +{% raw %}
warning[js/noShadowRestrictedNames]: Do not shadow the global "Array" property.
+   js/noShadowRestrictedNames.js:1:10
+  
+1  function Array() {}
+            -----
+
+=  note: Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.
+
+
{% endraw %} + +```jsx +function test(JSON) {console.log(JSON)} +``` + +{% raw %}
warning[js/noShadowRestrictedNames]: Do not shadow the global "JSON" property.
+   js/noShadowRestrictedNames.js:1:15
+  
+1  function test(JSON) {console.log(JSON)}
+                 ----
+
+=  note: Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.
+
+
{% endraw %} + diff --git a/xtask/codegen/src/generate_analyzer.rs b/xtask/codegen/src/generate_analyzer.rs index 8976859b065..b552ae5fee4 100644 --- a/xtask/codegen/src/generate_analyzer.rs +++ b/xtask/codegen/src/generate_analyzer.rs @@ -55,7 +55,7 @@ fn generate_category( file_name.to_string(), quote! { mod #module_name; - pub(super) use #module_name::#group_name; + pub(super) use self::#module_name::#group_name; }, ); } @@ -103,7 +103,7 @@ fn generate_group(category: &'static str, group: &str) -> Result<()> { mod #module_name; }, quote! { - #module_name::#rule_name + self::#module_name::#rule_name }, ), ); diff --git a/xtask/codegen/src/main.rs b/xtask/codegen/src/main.rs index bc9127c0c47..c96ad0445db 100644 --- a/xtask/codegen/src/main.rs +++ b/xtask/codegen/src/main.rs @@ -15,12 +15,7 @@ fn main() -> Result<()> { let command = args.subcommand()?.unwrap_or_default(); match command.as_str() { "grammar" => { - let arg_list = args.finish(); - let language_list = arg_list - .into_iter() - .filter_map(|arg| arg.to_str().map(|item| item.to_string())) - .collect::>(); - generate_ast(Mode::Overwrite, language_list)?; + generate_grammar(args); Ok(()) } "formatter" => { @@ -43,6 +38,15 @@ fn main() -> Result<()> { generate_rules_configuration(Mode::Overwrite)?; Ok(()) } + "all" => { + generate_tables()?; + generate_grammar(args); + generate_parser_tests(Mode::Overwrite)?; + generate_formatter(); + generate_analyzer()?; + generate_rules_configuration(Mode::Overwrite)?; + Ok(()) + } _ => { eprintln!( "\ @@ -57,9 +61,19 @@ SUBCOMMANDS: formatter Generates formatters for each language test Extracts parser inline comments into test files unicode Generates unicode table inside lexer + all Run all generators " ); Ok(()) } } } + +fn generate_grammar(args: Arguments) { + let arg_list = args.finish(); + let language_list = arg_list + .into_iter() + .filter_map(|arg| arg.to_str().map(|item| item.to_string())) + .collect::>(); + let _ = generate_ast(Mode::Overwrite, language_list); +} diff --git a/xtask/libs_bench/Cargo.toml b/xtask/libs_bench/Cargo.toml new file mode 100644 index 00000000000..19b452f163a --- /dev/null +++ b/xtask/libs_bench/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "xtask_libs_bench" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +rome_js_analyze = { path = "../../crates/rome_js_analyze" } +case = "1.0.0" +fastbloom-rs = "0.3.0" +qp-trie = "0.8.0" +fst = "0.4.7" +criterion = "0.3.5" +memchr = "2.5.0" +regex = { version = "1.6.0" } +iai = "0.1.1" + +[[bench]] +name = "to_camel_case" +harness = false + +[[bench]] +name = "contains_iai" +harness = false + +[[bench]] +name = "contains_criterion" +harness = false + +[[bin]] +name = "contains_iai" +path = "bins/contains_iai.rs" +test = false +bench = false diff --git a/xtask/libs_bench/benches/contains.rs b/xtask/libs_bench/benches/contains.rs new file mode 100644 index 00000000000..a2574600459 --- /dev/null +++ b/xtask/libs_bench/benches/contains.rs @@ -0,0 +1,174 @@ +#![allow(dead_code)] + +use std::collections::{BTreeSet, HashSet}; + +use fastbloom_rs::{BloomFilter, FilterBuilder, Membership}; +use qp_trie::Trie; + +pub fn keywords() -> Vec { + let repeat = std::env::var("ROME_BENCH_CONTAINS_REPEAT") + .unwrap_or_else(|_| "1".to_string()) + .parse() + .unwrap(); + let v = &["undefined", "NaN", "Infinity", "arguments", "eval"].repeat(repeat); + v.iter() + .enumerate() + .map(|(i, x)| format!("{}{}", x, i)) + .collect() +} + +pub fn search_for() -> &'static [&'static str] { + &[ + "undefined", + "a", + "NaN", + "longVariableName", + "Infinity", + "xxxxxxxx", + "arguments", + "eval", + ][..] +} + +pub fn contains_slice_setup() -> Vec { + keywords() +} + +pub fn contains_slice() -> usize { + let set = contains_slice_setup(); + let mut count = 0; + for k in search_for() { + count += set.iter().position(|x| x == k).unwrap_or(0); + } + count +} + +pub fn contains_binary_search_setup() -> Vec { + let mut words = keywords(); + words.sort(); + words +} + +pub fn contains_binary_search() -> usize { + let set = contains_binary_search_setup(); + let mut count = 0; + for k in search_for() { + count += set.binary_search_by(|v| (*k).cmp(v.as_str())).unwrap_or(1); + } + count +} + +pub fn contains_hashset_setup() -> HashSet { + let mut set = HashSet::new(); + for k in keywords() { + set.insert(k.to_string()); + } + set +} + +pub fn contains_hashset() -> i32 { + let set = contains_hashset_setup(); + let mut count = 0; + for k in search_for() { + count += if set.contains(*k) { 1 } else { 0 }; + } + count +} + +pub fn contains_btreeset_setup() -> BTreeSet { + let mut set = BTreeSet::new(); + for k in keywords() { + set.insert(k.to_string()); + } + set +} + +pub fn contains_btreeset() -> i32 { + let set = contains_btreeset_setup(); + let mut count = 0; + for k in search_for() { + count = if set.contains(*k) { 1 } else { 0 }; + } + count +} + +pub fn contains_bloom_setup() -> BloomFilter { + let builder = FilterBuilder::new(100_000_000, 0.01); + let mut set = BloomFilter::new(builder); + + for k in keywords() { + set.add(k.as_bytes()); + } + + set +} + +pub fn contains_bloom() -> i32 { + let set = contains_bloom_setup(); + let mut count = 0; + for k in search_for() { + count += if set.contains(k.as_bytes()) { 1 } else { 0 }; + } + count +} + +pub fn contains_trie_setup() -> Trie, i32> { + let mut set = Trie::new(); + + for k in keywords() { + set.insert(k.into_bytes(), 0); + } + + set +} + +pub fn contains_trie() -> i32 { + let set = contains_trie_setup(); + let mut count = 0; + for k in search_for() { + count += if set.contains_key(k.as_bytes()) { 1 } else { 0 }; + } + count +} + +pub fn contains_fst_setup() -> fst::Set> { + let w = vec![]; + let mut set = fst::SetBuilder::new(w).unwrap(); + + let mut keywords = keywords().to_vec(); + keywords.sort(); + + for k in keywords { + let _ = set.insert(k); + } + set.into_set() +} + +pub fn contains_fst() -> i32 { + let set = contains_fst_setup(); + let mut count = 0; + for k in search_for() { + count += if set.contains(k) { 1 } else { 0 }; + } + count +} + +pub fn contains_memchr_setup() -> Vec { + contains_binary_search_setup() +} + +pub fn contains_memchr() -> i32 { + let set = contains_memchr_setup(); + + let mut count = 0; + for k in search_for() { + for item in set.iter() { + count += if memchr::memmem::find(k.as_bytes(), item.as_str().as_bytes()).is_some() { + 1 + } else { + 0 + }; + } + } + count +} diff --git a/xtask/libs_bench/benches/contains_criterion.rs b/xtask/libs_bench/benches/contains_criterion.rs new file mode 100644 index 00000000000..2b02b595ae1 --- /dev/null +++ b/xtask/libs_bench/benches/contains_criterion.rs @@ -0,0 +1,109 @@ +mod contains; + +use contains::*; +use criterion::{criterion_group, criterion_main, Criterion}; +use fastbloom_rs::Membership; + +fn criterion_benchmark(c: &mut Criterion) { + let set = contains_hashset_setup(); + c.bench_function("contains_hashset", |b| { + b.iter(|| { + let mut count = 0; + for k in search_for() { + count += if set.contains(*k) { 1 } else { 0 }; + } + count + }) + }); + + let set = contains_btreeset_setup(); + c.bench_function("contains_btreeset", |b| { + b.iter(|| { + let mut count = 0; + for k in search_for() { + count = if set.contains(*k) { 1 } else { 0 }; + } + count + }) + }); + + let set = contains_bloom_setup(); + c.bench_function("contains_bloom", |b| { + b.iter(|| { + let mut count = 0; + for k in search_for() { + count += if set.contains(k.as_bytes()) { 1 } else { 0 }; + } + count + }) + }); + + let set = contains_trie_setup(); + c.bench_function("contains_trie", |b| { + b.iter(|| { + let mut count = 0; + for k in search_for() { + count += if set.contains_key(k.as_bytes()) { 1 } else { 0 }; + } + count + }) + }); + + let set = contains_slice_setup(); + c.bench_function("contains_slice", |b| { + b.iter(|| { + let mut count = 0; + for k in search_for() { + count += set.iter().position(|x| x == k).unwrap_or(0); + } + count + }) + }); + + let set = contains_fst_setup(); + c.bench_function("contains_fst", |b| { + b.iter(|| { + let mut count = 0; + for k in search_for() { + count += if set.contains(k) { 1 } else { 0 }; + } + count + }) + }); + + let mut set = keywords(); + set.sort(); + c.bench_function("contains_binary_search", |b| { + b.iter(|| { + let mut count = 0; + for k in search_for() { + count += set.binary_search_by(|v| (*k).cmp(v.as_str())).unwrap_or(1); + } + count + }) + }); + + let set = contains_memchr_setup(); + c.bench_function("contains_memchr", |b| { + b.iter(|| { + { + let mut count = 0; + for k in search_for() { + for item in set.iter() { + count += if memchr::memmem::find(k.as_bytes(), item.as_str().as_bytes()) + .is_some() + { + 1 + } else { + 0 + }; + } + } + count + }; + }) + }); +} + +criterion_group!(contains, criterion_benchmark); +criterion_main!(contains); diff --git a/xtask/libs_bench/benches/contains_iai.rs b/xtask/libs_bench/benches/contains_iai.rs new file mode 100644 index 00000000000..c83b602ed24 --- /dev/null +++ b/xtask/libs_bench/benches/contains_iai.rs @@ -0,0 +1,25 @@ +mod contains; +use contains::*; + +// iai do not support setup, so we basically run the setup and +// the whole setup + test. To see the difference. +// https://github.com/bheisler/iai/pull/24 + +iai::main!( + contains_hashset_setup, + contains_hashset, + contains_btreeset_setup, + contains_btreeset, + contains_bloom_setup, + contains_bloom, + contains_trie_setup, + contains_trie, + contains_slice_setup, + contains_slice, + contains_fst_setup, + contains_fst, + contains_binary_search_setup, + contains_binary_search, + contains_memchr_setup, + contains_memchr, +); diff --git a/xtask/libs_bench/benches/to_camel_case.rs b/xtask/libs_bench/benches/to_camel_case.rs new file mode 100644 index 00000000000..fa6fb3b4379 --- /dev/null +++ b/xtask/libs_bench/benches/to_camel_case.rs @@ -0,0 +1,32 @@ +fn to_camel_case_rome_all_lowercase() { + let _ = rome_js_analyze::utils::to_camel_case(iai::black_box("lowercase")); +} + +fn to_camel_case_case_all_lowercase() { + let _ = case::CaseExt::to_camel(iai::black_box("lowercase")); +} + +fn to_camel_case_rome_already_camel_case() { + let _ = rome_js_analyze::utils::to_camel_case(iai::black_box("camelCase")); +} + +fn to_camel_case_case_already_camel_case() { + let _ = case::CaseExt::to_camel(iai::black_box("camelCase")); +} + +fn to_camel_case_rome_pascal_case() { + let _ = rome_js_analyze::utils::to_camel_case(iai::black_box("CamelCase")); +} + +fn to_camel_case_case_pascal_case() { + let _ = case::CaseExt::to_camel(iai::black_box("CamelCase")); +} + +iai::main!( + to_camel_case_rome_all_lowercase, + to_camel_case_case_all_lowercase, + to_camel_case_rome_already_camel_case, + to_camel_case_case_already_camel_case, + to_camel_case_rome_pascal_case, + to_camel_case_case_pascal_case, +); diff --git a/xtask/libs_bench/bins/contains_iai.rs b/xtask/libs_bench/bins/contains_iai.rs new file mode 100644 index 00000000000..6c4d71a99af --- /dev/null +++ b/xtask/libs_bench/bins/contains_iai.rs @@ -0,0 +1,58 @@ +use regex::Regex; +use std::{collections::HashMap, process::Command}; + +fn main() { + let result = Command::new("cargo") + .args(["bench", "-p", "xtask_libs_bench"]) + .output(); + let re = Regex::new(r#"(?P\w*?)\s*Instructions:\s*(?P\d*).*\n\s*L1 Accesses:\s*(?P\d*).*\n\s*L2 Accesses:\s*(?P\d*).*\n\s*RAM Accesses:\s*(?P\d*).*\n\s*Estimated Cycles:\s*(?P\d*).*"#).unwrap(); + let stdout = String::from_utf8(result.unwrap().stdout).unwrap(); + let mut tests: HashMap<&str, (isize, isize, isize, isize, isize)> = HashMap::new(); + + for capture in re.captures_iter(stdout.as_str()) { + let name = capture.name("NAME").unwrap().as_str(); + let inst = capture.name("INST").unwrap().as_str().parse().unwrap(); + let l1 = capture.name("L1").unwrap().as_str().parse().unwrap(); + let l2 = capture.name("L2").unwrap().as_str().parse().unwrap(); + let ram = capture.name("RAM").unwrap().as_str().parse().unwrap(); + let cycles = capture.name("CYCLES").unwrap().as_str().parse().unwrap(); + tests.insert(name, (inst, l1, l2, ram, cycles)); + } + + for (k, v_setup) in tests.iter() { + if let Some(name) = k.strip_suffix("_setup") { + let v_all = tests[name]; + println!("{}", name); + println!( + "\tdiff inst: {} is {} - {}", + v_all.0 - v_setup.0, + v_all.0, + v_setup.0 + ); + println!( + "\tdiff l1: {} is {} - {}", + v_all.1 - v_setup.1, + v_all.1, + v_setup.1 + ); + println!( + "\tdiff l2: {} is {} - {}", + v_all.2 - v_setup.2, + v_all.2, + v_setup.2 + ); + println!( + "\tdiff ram: {} is {} - {}", + v_all.3 - v_setup.3, + v_all.3, + v_setup.3 + ); + println!( + "\tdiff cycles: {} is {} - {}", + v_all.4 - v_setup.4, + v_all.4, + v_setup.4 + ); + } + } +} diff --git a/xtask/libs_bench/src/main.rs b/xtask/libs_bench/src/main.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/xtask/libs_bench/src/main.rs @@ -0,0 +1 @@ +fn main() {}