mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
perf(linter/import/no-cycle): reuse module records in diagnostic stack (#27480)
Instead of storing copies of paths, we store a reference to the original module record, which has the path we need. By doing this, we don't need to repeatedly clone lots of paths, but we now need to do a lot more reference counting, but I think it's a good tradeoff. Running on `vscode`: Metric | Before | After | Change -- | -- | -- | -- Allocation calls | 19,051,530 | 16,807,784 | -11.8% Allocated bytes | 1,700,223,977 B | 1,506,926,944 B | -11.4% Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
73e877c43c
commit
fd5edb71b5
1 file changed
+11
-7
@@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
path::{Component, Path, PathBuf},
|
||||
path::{Component, Path},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
@@ -20,7 +20,11 @@ use crate::{
|
||||
rule::{DefaultRuleConfig, Rule},
|
||||
};
|
||||
|
||||
fn no_cycle_diagnostic(span: Span, stack: &[(CompactStr, PathBuf)], cwd: &Path) -> OxcDiagnostic {
|
||||
fn no_cycle_diagnostic(
|
||||
span: Span,
|
||||
stack: &[(CompactStr, Arc<ModuleRecord>)],
|
||||
cwd: &Path,
|
||||
) -> OxcDiagnostic {
|
||||
let cycle_description = format_cycle(stack, cwd);
|
||||
OxcDiagnostic::warn("Dependency cycle detected")
|
||||
.with_help("Refactor to remove the cycle. Consider extracting shared code into a separate module that both files can import.")
|
||||
@@ -38,10 +42,11 @@ fn self_referencing_cycle_diagnostic(span: Span, is_import: bool) -> OxcDiagnost
|
||||
.with_label(span.primary_label("this module references itself"))
|
||||
}
|
||||
|
||||
fn format_cycle(stack: &[(CompactStr, PathBuf)], cwd: &Path) -> String {
|
||||
fn format_cycle(stack: &[(CompactStr, Arc<ModuleRecord>)], cwd: &Path) -> String {
|
||||
let mut lines = Vec::with_capacity(stack.len() * 2 + 1);
|
||||
|
||||
for (i, (specifier, path)) in stack.iter().enumerate() {
|
||||
for (i, (specifier, module_record)) in stack.iter().enumerate() {
|
||||
let path = &module_record.resolved_absolute_path;
|
||||
let relative_path = path
|
||||
.strip_prefix(cwd)
|
||||
.unwrap_or(path)
|
||||
@@ -169,8 +174,7 @@ impl Rule for NoCycle {
|
||||
|
||||
let requested_module = module_record.requested_modules[&key][0];
|
||||
let span = requested_module.span;
|
||||
let mut stack =
|
||||
vec![(key.clone(), loaded_module_record.resolved_absolute_path.clone())];
|
||||
let mut stack = vec![(key.clone(), Arc::clone(&loaded_module_record))];
|
||||
|
||||
if loaded_module_record.resolved_absolute_path == *needle {
|
||||
ctx.diagnostic(self_referencing_cycle_diagnostic(span, requested_module.is_import));
|
||||
@@ -182,7 +186,7 @@ impl Rule for NoCycle {
|
||||
.filter(|(key, val), parent| self.should_traverse_module(key, val, parent))
|
||||
.event(|event, (key, val), _| match event {
|
||||
ModuleGraphVisitorEvent::Enter => {
|
||||
stack.push((key.clone(), val.resolved_absolute_path.clone()));
|
||||
stack.push((key.clone(), Arc::clone(val)));
|
||||
}
|
||||
ModuleGraphVisitorEvent::Leave => {
|
||||
stack.pop();
|
||||
|
||||
Reference in new issue
Block a user