Skip to content

Commit d18c896

Browse files
shulaodaBoshen
andauthoredSep 11, 2024··
perf(rust): use cow_utils instead (#5664)
Related to #5586 and #5662 --------- Co-authored-by: Boshen <boshenc@gmail.com>
1 parent a729b64 commit d18c896

40 files changed

+146
-78
lines changed
 

‎.clippy.toml

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
ignore-interior-mutability = ["oxc_linter::rule::RuleWithSeverity"]
22

33
disallowed-methods = [
4-
{ path = "str::to_ascii_lowercase", reason = "Avoid memory allocation. Use `cow_utils::CowUtils::cow_to_ascii_lowercase` instead." },
5-
{ path = "str::to_ascii_uppercase", reason = "Avoid memory allocation. Use `cow_utils::CowUtils::cow_to_ascii_uppercase` instead." },
4+
{ path = "str::to_ascii_lowercase", reason = "To avoid memory allocation, use `cow_utils::CowUtils::cow_to_ascii_lowercase` instead." },
5+
{ path = "str::to_ascii_uppercase", reason = "To avoid memory allocation, use `cow_utils::CowUtils::cow_to_ascii_uppercase` instead." },
6+
{ path = "str::to_lowercase", reason = "To avoid memory allocation, use `cow_utils::CowUtils::cow_to_lowercase` instead." },
7+
{ path = "str::to_uppercase", reason = "To avoid memory allocation, use `cow_utils::CowUtils::cow_to_uppercase` instead." },
8+
{ path = "str::replace", reason = "To avoid memory allocation, use `cow_utils::CowUtils::replace` instead." },
9+
{ path = "str::replacen", reason = "To avoid memory allocation, use `cow_utils::CowUtils::replacen` instead." },
610
]

‎Cargo.lock

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎crates/oxc_codegen/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ workspace = true
2020
doctest = false
2121

2222
[dependencies]
23+
cow-utils = { workspace = true }
2324
oxc_allocator = { workspace = true }
2425
oxc_ast = { workspace = true }
2526
oxc_index = { workspace = true }

‎crates/oxc_codegen/src/gen.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{borrow::Cow, ops::Not};
22

3+
use cow_utils::CowUtils;
34
use oxc_allocator::{Box, Vec};
45
#[allow(clippy::wildcard_imports)]
56
use oxc_ast::ast::*;
@@ -1232,7 +1233,7 @@ impl<'a> Gen for RegExpLiteral<'a> {
12321233
);
12331234
// Avoid forming a single-line comment or "</script" sequence
12341235
if Some('/') == last
1235-
|| (Some('<') == last && pattern_text.to_lowercase().starts_with("script"))
1236+
|| (Some('<') == last && pattern_text.cow_to_lowercase().starts_with("script"))
12361237
{
12371238
p.print_hard_space();
12381239
}

‎crates/oxc_linter/src/fixer/mod.rs

+13-12
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ impl<'a> Fixer<'a> {
318318

319319
#[cfg(test)]
320320
mod test {
321+
use cow_utils::CowUtils;
321322
use std::borrow::Cow;
322323

323324
use oxc_diagnostics::OxcDiagnostic;
@@ -417,7 +418,7 @@ mod test {
417418
get_fix_result(vec![create_message(insert_at_middle(), Some(INSERT_AT_MIDDLE))]);
418419
assert_eq!(
419420
result.fixed_code,
420-
TEST_CODE.replace("6 *", &format!("{}{}", INSERT_AT_MIDDLE.content, "6 *"))
421+
TEST_CODE.cow_replace("6 *", &format!("{}{}", INSERT_AT_MIDDLE.content, "6 *"))
421422
);
422423
assert_eq!(result.messages.len(), 0);
423424
}
@@ -435,7 +436,7 @@ mod test {
435436
format!(
436437
"{}{}{}",
437438
INSERT_AT_START.content,
438-
TEST_CODE.replace("6 *", &format!("{}{}", INSERT_AT_MIDDLE.content, "6 *")),
439+
TEST_CODE.cow_replace("6 *", &format!("{}{}", INSERT_AT_MIDDLE.content, "6 *")),
439440
INSERT_AT_END.content
440441
)
441442
);
@@ -452,23 +453,23 @@ mod test {
452453
#[test]
453454
fn replace_at_the_start() {
454455
let result = get_fix_result(vec![create_message(replace_var(), Some(REPLACE_VAR))]);
455-
assert_eq!(result.fixed_code, TEST_CODE.replace("var", "let"));
456+
assert_eq!(result.fixed_code, TEST_CODE.cow_replace("var", "let"));
456457
assert_eq!(result.messages.len(), 0);
457458
assert!(result.fixed);
458459
}
459460

460461
#[test]
461462
fn replace_at_the_middle() {
462463
let result = get_fix_result(vec![create_message(replace_id(), Some(REPLACE_ID))]);
463-
assert_eq!(result.fixed_code, TEST_CODE.replace("answer", "foo"));
464+
assert_eq!(result.fixed_code, TEST_CODE.cow_replace("answer", "foo"));
464465
assert_eq!(result.messages.len(), 0);
465466
assert!(result.fixed);
466467
}
467468

468469
#[test]
469470
fn replace_at_the_end() {
470471
let result = get_fix_result(vec![create_message(replace_num(), Some(REPLACE_NUM))]);
471-
assert_eq!(result.fixed_code, TEST_CODE.replace('6', "5"));
472+
assert_eq!(result.fixed_code, TEST_CODE.cow_replace('6', "5"));
472473
assert_eq!(result.messages.len(), 0);
473474
assert!(result.fixed);
474475
}
@@ -489,7 +490,7 @@ mod test {
489490
#[test]
490491
fn remove_at_the_start() {
491492
let result = get_fix_result(vec![create_message(remove_start(), Some(REMOVE_START))]);
492-
assert_eq!(result.fixed_code, TEST_CODE.replace("var ", ""));
493+
assert_eq!(result.fixed_code, TEST_CODE.cow_replace("var ", ""));
493494
assert_eq!(result.messages.len(), 0);
494495
assert!(result.fixed);
495496
}
@@ -500,15 +501,15 @@ mod test {
500501
remove_middle(Span::default()),
501502
Some(REMOVE_MIDDLE),
502503
)]);
503-
assert_eq!(result.fixed_code, TEST_CODE.replace("answer", "a"));
504+
assert_eq!(result.fixed_code, TEST_CODE.cow_replace("answer", "a"));
504505
assert_eq!(result.messages.len(), 0);
505506
assert!(result.fixed);
506507
}
507508

508509
#[test]
509510
fn remove_at_the_end() {
510511
let result = get_fix_result(vec![create_message(remove_end(), Some(REMOVE_END))]);
511-
assert_eq!(result.fixed_code, TEST_CODE.replace(" * 7", ""));
512+
assert_eq!(result.fixed_code, TEST_CODE.cow_replace(" * 7", ""));
512513
assert_eq!(result.messages.len(), 0);
513514
assert!(result.fixed);
514515
}
@@ -531,7 +532,7 @@ mod test {
531532
create_message(remove_middle(Span::default()), Some(REMOVE_MIDDLE)),
532533
create_message(replace_id(), Some(REPLACE_ID)),
533534
]);
534-
assert_eq!(result.fixed_code, TEST_CODE.replace("answer", "foo"));
535+
assert_eq!(result.fixed_code, TEST_CODE.cow_replace("answer", "foo"));
535536
assert_eq!(result.messages.len(), 1);
536537
assert_eq!(result.messages[0].error.to_string(), "removemiddle");
537538
assert!(result.fixed);
@@ -543,7 +544,7 @@ mod test {
543544
create_message(remove_start(), Some(REMOVE_START)),
544545
create_message(replace_id(), Some(REPLACE_ID)),
545546
]);
546-
assert_eq!(result.fixed_code, TEST_CODE.replace("var answer", "foo"));
547+
assert_eq!(result.fixed_code, TEST_CODE.cow_replace("var answer", "foo"));
547548
assert_eq!(result.messages.len(), 0);
548549
assert!(result.fixed);
549550
}
@@ -555,7 +556,7 @@ mod test {
555556
create_message(replace_id(), Some(REPLACE_ID)),
556557
create_message(no_fix(Span::default()), None),
557558
]);
558-
assert_eq!(result.fixed_code, TEST_CODE.replace("answer", "foo"));
559+
assert_eq!(result.fixed_code, TEST_CODE.cow_replace("answer", "foo"));
559560
assert_eq!(result.messages.len(), 2);
560561
assert_eq!(result.messages[0].error.to_string(), "nofix");
561562
assert_eq!(result.messages[1].error.to_string(), "removemiddle");
@@ -591,7 +592,7 @@ mod test {
591592
Message::new(no_fix_2(Span::new(1, 7)), None),
592593
Message::new(no_fix_1(Span::new(1, 3)), None),
593594
]);
594-
assert_eq!(result.fixed_code, TEST_CODE.replace("answer", "foo"));
595+
assert_eq!(result.fixed_code, TEST_CODE.cow_replace("answer", "foo"));
595596
assert_eq!(result.messages.len(), 2);
596597
assert_eq!(result.messages[0].error.to_string(), "nofix1");
597598
assert_eq!(result.messages[1].error.to_string(), "nofix2");

‎crates/oxc_linter/src/rules/eslint/no_loss_of_precision.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ impl NoLossOfPrecision {
196196
} else {
197197
format!("{value:o}")
198198
};
199-
!raw.ends_with(&suffix.to_uppercase())
199+
!raw.ends_with(&suffix.cow_to_uppercase().as_ref())
200200
}
201201

202202
fn base_ten_loses_precision(node: &'_ NumericLiteral) -> bool {

‎crates/oxc_linter/src/rules/eslint/no_unused_vars/diagnostic.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use cow_utils::CowUtils;
12
use oxc_diagnostics::OxcDiagnostic;
23
use oxc_semantic::SymbolFlags;
34
use oxc_span::{GetSpan, Span};
@@ -32,7 +33,7 @@ pub fn used_ignored(symbol: &Symbol<'_, '_>) -> OxcDiagnostic {
3233

3334
OxcDiagnostic::warn(format!("{pronoun} '{name}' is marked as ignored but is used."))
3435
.with_label(symbol.span().label(format!("'{name}' is declared here")))
35-
.with_help(format!("Consider renaming this {}.", pronoun.to_lowercase()))
36+
.with_help(format!("Consider renaming this {}.", pronoun.cow_to_lowercase()))
3637
}
3738
/// Variable 'x' is declared but never used.
3839
pub fn declared(symbol: &Symbol<'_, '_>) -> OxcDiagnostic {

‎crates/oxc_linter/src/rules/eslint/sort_imports.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::{
44
str::FromStr,
55
};
66

7+
use cow_utils::CowUtils;
78
use itertools::Itertools;
89
use oxc_ast::{
910
ast::{ImportDeclaration, ImportDeclarationSpecifier, Statement},
@@ -210,10 +211,10 @@ impl SortImports {
210211
let mut previous_local_member_name = get_first_local_member_name(previous);
211212

212213
if self.ignore_case {
213-
current_local_member_name =
214-
current_local_member_name.map(|name| name.to_lowercase().into());
215-
previous_local_member_name =
216-
previous_local_member_name.map(|name| name.to_lowercase().into());
214+
current_local_member_name = current_local_member_name
215+
.map(|name| Cow::Owned(name.cow_to_lowercase().into_owned()));
216+
previous_local_member_name = previous_local_member_name
217+
.map(|name| Cow::Owned(name.cow_to_lowercase().into_owned()));
217218
}
218219

219220
// "memberSyntaxSortOrder": ["none", "all", "multiple", "single"]
@@ -283,7 +284,7 @@ impl SortImports {
283284
let b = window[1].local.name.as_str();
284285

285286
if self.ignore_case {
286-
a.to_lowercase() > b.to_lowercase()
287+
a.cow_to_lowercase() > b.cow_to_lowercase()
287288
} else {
288289
a > b
289290
}
@@ -330,7 +331,7 @@ impl SortImports {
330331
let b = b.local.name.as_str();
331332

332333
if self.ignore_case {
333-
a.to_lowercase().cmp(&b.to_lowercase())
334+
a.cow_to_lowercase().cmp(&b.cow_to_lowercase())
334335
} else {
335336
a.cmp(b)
336337
}

‎crates/oxc_linter/src/rules/eslint/sort_vars.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{borrow::Cow, cmp::Ordering};
22

3+
use cow_utils::CowUtils;
34
use oxc_ast::{
45
ast::{BindingPatternKind, VariableDeclarator},
56
AstKind,
@@ -93,7 +94,7 @@ impl SortVars {
9394
};
9495

9596
if self.ignore_case {
96-
return Cow::Owned(ident.name.to_lowercase());
97+
return ident.name.as_str().cow_to_lowercase();
9798
}
9899

99100
Cow::Borrowed(ident.name.as_str()) // avoid string allocs in the default case

‎crates/oxc_linter/src/rules/import/no_cycle.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![allow(clippy::cast_possible_truncation)]
22
use std::{ffi::OsStr, path::Component, sync::Arc};
33

4+
use cow_utils::CowUtils;
45
use oxc_diagnostics::OxcDiagnostic;
56
use oxc_macros::declare_oxc_lint;
67
use oxc_span::{CompactStr, Span};
@@ -142,12 +143,13 @@ impl Rule for NoCycle {
142143
let help = stack
143144
.iter()
144145
.map(|(specifier, path)| {
145-
let path = path
146-
.strip_prefix(&cwd)
147-
.unwrap_or(path)
148-
.to_string_lossy()
149-
.replace('\\', "/");
150-
format!("-> {specifier} - {path}")
146+
format!(
147+
"-> {specifier} - {}",
148+
path.strip_prefix(&cwd)
149+
.unwrap_or(path)
150+
.to_string_lossy()
151+
.cow_replace('\\', "/")
152+
)
151153
})
152154
.collect::<Vec<_>>()
153155
.join("\n");

‎crates/oxc_linter/src/rules/jest/expect_expect.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use cow_utils::CowUtils;
12
use oxc_ast::{
23
ast::{CallExpression, Expression, Statement},
34
AstKind,
@@ -273,7 +274,13 @@ fn convert_pattern(pattern: &str) -> String {
273274
// request.**.expect* -> request.[a-z\\d\\.]*.expect[a-z\\d]*
274275
let pattern = pattern
275276
.split('.')
276-
.map(|p| if p == "**" { String::from("[a-z\\d\\.]*") } else { p.replace('*', "[a-z\\d]*") })
277+
.map(|p| {
278+
if p == "**" {
279+
String::from("[a-z\\d\\.]*")
280+
} else {
281+
p.cow_replace('*', "[a-z\\d]*").into_owned()
282+
}
283+
})
277284
.collect::<Vec<_>>()
278285
.join("\\.");
279286

‎crates/oxc_linter/src/rules/jest/valid_title.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{collections::HashMap, hash::Hash};
22

3+
use cow_utils::CowUtils;
34
use oxc_ast::{
45
ast::{Argument, BinaryExpression, Expression},
56
AstKind,
@@ -281,7 +282,7 @@ fn validate_title(
281282
if !valid_title.disallowed_words.is_empty() {
282283
let Ok(disallowed_words_reg) = regex::Regex::new(&format!(
283284
r#"(?iu)\b(?:{})\b"#,
284-
valid_title.disallowed_words.join("|").replace('.', r"\.")
285+
valid_title.disallowed_words.join("|").cow_replace('.', r"\.")
285286
)) else {
286287
return;
287288
};

‎crates/oxc_linter/src/rules/jsx_a11y/aria_props.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use cow_utils::CowUtils;
12
use oxc_ast::{ast::JSXAttributeItem, AstKind};
23
use oxc_diagnostics::OxcDiagnostic;
34
use oxc_macros::declare_oxc_lint;
@@ -52,7 +53,8 @@ declare_oxc_lint!(
5253
impl Rule for AriaProps {
5354
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
5455
if let AstKind::JSXAttributeItem(JSXAttributeItem::Attribute(attr)) = node.kind() {
55-
let name = get_jsx_attribute_name(&attr.name).to_lowercase();
56+
let name = get_jsx_attribute_name(&attr.name);
57+
let name = name.cow_to_lowercase();
5658
if name.starts_with("aria-") && !VALID_ARIA_PROPS.contains(&name) {
5759
let suggestion = COMMON_TYPOS.get(&name).copied();
5860
let diagnostic = aria_props_diagnostic(attr.span, &name, suggestion);

‎crates/oxc_linter/src/rules/jsx_a11y/aria_unsupported_elements.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use cow_utils::CowUtils;
12
use oxc_ast::{ast::JSXAttributeItem, AstKind};
23
use oxc_diagnostics::OxcDiagnostic;
34
use oxc_macros::declare_oxc_lint;
@@ -57,7 +58,8 @@ impl Rule for AriaUnsupportedElements {
5758
JSXAttributeItem::Attribute(attr) => attr,
5859
JSXAttributeItem::SpreadAttribute(_) => continue,
5960
};
60-
let attr_name = get_jsx_attribute_name(&attr.name).to_lowercase();
61+
let attr_name = get_jsx_attribute_name(&attr.name);
62+
let attr_name = attr_name.cow_to_lowercase();
6163
if INVALID_ATTRIBUTES.contains(&attr_name) {
6264
ctx.diagnostic_with_fix(
6365
aria_unsupported_elements_diagnostic(attr.span, &attr_name),

‎crates/oxc_linter/src/rules/jsx_a11y/role_supports_aria_props.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use cow_utils::CowUtils;
12
use oxc_ast::{
23
ast::{JSXAttributeItem, JSXOpeningElement},
34
AstKind,
@@ -84,8 +85,9 @@ impl Rule for RoleSupportsAriaProps {
8485
let invalid_props = get_invalid_aria_props_for_role(role_value);
8586
for attr in &jsx_el.attributes {
8687
if let JSXAttributeItem::Attribute(attr) = attr {
87-
let name = get_jsx_attribute_name(&attr.name).to_lowercase();
88-
if invalid_props.contains(&&name.as_str()) {
88+
let name = get_jsx_attribute_name(&attr.name);
89+
let name = name.cow_to_lowercase();
90+
if invalid_props.contains(&&name.as_ref()) {
8991
ctx.diagnostic(if is_implicit {
9092
is_implicit_diagnostic(attr.span, &name, role_value, &el_type)
9193
} else {

‎crates/oxc_linter/src/rules/react/jsx_key.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use cow_utils::CowUtils;
12
use oxc_ast::{
23
ast::{Expression, JSXAttributeItem, JSXAttributeName, JSXElement, JSXFragment, Statement},
34
AstKind,
@@ -91,7 +92,7 @@ pub fn import_matcher<'a>(
9192
actual_local_name: &'a str,
9293
expected_module_name: &'a str,
9394
) -> bool {
94-
let expected_module_name = expected_module_name.to_lowercase();
95+
let expected_module_name = expected_module_name.cow_to_lowercase();
9596
ctx.semantic().module_record().import_entries.iter().any(|import| {
9697
import.module_request.name().as_str() == expected_module_name
9798
&& import.local_name.name().as_str() == actual_local_name

0 commit comments

Comments
 (0)
Please sign in to comment.