Skip to content

Commit b8f8ce5

Browse files
committed
perf(linter): id-length: reduce allocations and add more ASCII checks (#14821)
Previous PR (#14767) implemented an initial ASCII check, but I forgot to add it to the other identifier checks as well. This now adds the fast path ASCII check to all of the branches for this rule. In addition, we no longer need to call `.to_string()` to allocate for each identifier, we can simply do the exceptions check with `&str`. This should greatly benefit large files which have lots of identifiers, but this will pretty much universally improve perf on every file since this rule runs on every identifier and almost every JS file has identifiers. <img width="714" height="535" alt="image" src="https://github.com/user-attachments/assets/f67a43e8-0e91-4f6d-805b-a031f9881c74" />
1 parent bb4347c commit b8f8ce5

File tree

1 file changed

+21
-14
lines changed

1 file changed

+21
-14
lines changed

crates/oxc_linter/src/rules/eslint/id_length.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ impl IdLength {
210210
node: &AstNode,
211211
ctx: &LintContext,
212212
) {
213-
let ident_name = ident.name.to_string();
213+
let ident_name = ident.name;
214214

215215
if self.is_exception(&ident_name) {
216216
return;
@@ -269,17 +269,20 @@ impl IdLength {
269269
}
270270

271271
fn handle_identifier_name(&self, ident: &IdentifierName, node: &AstNode, ctx: &LintContext) {
272-
let ident_name = ident.name.to_string();
272+
let ident_name = ident.name;
273273

274274
if self.is_exception(&ident_name) {
275275
return;
276276
}
277277

278-
let segmenter = GraphemeClusterSegmenter::new();
279-
let graphemes_length = segmenter.segment_str(&ident_name).count() - 1;
280-
281-
let is_too_long = self.is_too_long(graphemes_length);
282-
let is_too_short = self.is_too_short(graphemes_length);
278+
let (is_too_long, is_too_short) = if ident_name.is_ascii() {
279+
let ident_length = ident_name.len();
280+
(self.is_too_long(ident_length), self.is_too_short(ident_length))
281+
} else {
282+
let segmenter = GraphemeClusterSegmenter::new();
283+
let graphemes_length = segmenter.segment_str(&ident_name).count() - 1;
284+
(self.is_too_long(graphemes_length), self.is_too_short(graphemes_length))
285+
};
283286

284287
if !is_too_long && !is_too_short {
285288
return;
@@ -376,16 +379,20 @@ impl IdLength {
376379
node: &AstNode,
377380
ctx: &LintContext,
378381
) {
379-
let ident_name = ident.name.to_string();
382+
let ident_name = ident.name;
380383

381384
if self.is_exception(&ident_name) {
382385
return;
383386
}
384387

385-
let segmenter = GraphemeClusterSegmenter::new();
386-
let graphemes_length = segmenter.segment_str(&ident_name).count() - 1;
387-
let is_too_long = self.is_too_long(graphemes_length);
388-
let is_too_short = self.is_too_short(graphemes_length);
388+
let (is_too_long, is_too_short) = if ident_name.is_ascii() {
389+
let ident_length = ident_name.len();
390+
(self.is_too_long(ident_length), self.is_too_short(ident_length))
391+
} else {
392+
let segmenter = GraphemeClusterSegmenter::new();
393+
let graphemes_length = segmenter.segment_str(&ident_name).count() - 1;
394+
(self.is_too_long(graphemes_length), self.is_too_short(graphemes_length))
395+
};
389396

390397
if is_too_long {
391398
ctx.diagnostic(id_length_is_too_long_diagnostic(node.span(), self.max));
@@ -408,8 +415,8 @@ impl IdLength {
408415
)
409416
}
410417

411-
fn is_exception(&self, identifier: &String) -> bool {
412-
if self.exceptions.contains(identifier) {
418+
fn is_exception(&self, identifier: &str) -> bool {
419+
if self.exceptions.iter().any(|exc| exc == identifier) {
413420
return true;
414421
}
415422
if self.exception_patterns.iter().any(|regex| regex.is_match(identifier)) {

0 commit comments

Comments
 (0)