refactor(semantic)!: remove ModuleRecord from Semantic (#7548)

`ModuleRecord` will eventually be moved to be linter specific thing for cross module data sharing, which means we can add more data to it.
This commit is contained in:
Boshen 2024-11-29 16:30:54 +00:00
parent 8a788b8f4b
commit 0be5233c84
18 changed files with 91 additions and 55 deletions

View file

@ -290,9 +290,10 @@ impl IsolatedLintHandler {
return Some(Self::wrap_diagnostics(path, &source_text, reports, start)); return Some(Self::wrap_diagnostics(path, &source_text, reports, start));
}; };
let module_record = Arc::new(ret.module_record);
let mut semantic = semantic_ret.semantic; let mut semantic = semantic_ret.semantic;
semantic.set_irregular_whitespaces(ret.irregular_whitespaces); semantic.set_irregular_whitespaces(ret.irregular_whitespaces);
let result = self.linter.run(path, Rc::new(semantic)); let result = self.linter.run(path, Rc::new(semantic), module_record);
let reports = result let reports = result
.into_iter() .into_iter()

View file

@ -1,6 +1,8 @@
use std::{cell::RefCell, path::Path, rc::Rc, sync::Arc};
use oxc_semantic::Semantic; use oxc_semantic::Semantic;
use oxc_span::SourceType; use oxc_span::SourceType;
use std::{cell::RefCell, path::Path, rc::Rc, sync::Arc}; use oxc_syntax::module_record::ModuleRecord;
use crate::{ use crate::{
config::{LintConfig, LintPlugins}, config::{LintConfig, LintPlugins},
@ -37,6 +39,8 @@ pub(crate) struct ContextHost<'a> {
/// Shared semantic information about the file being linted, which includes scopes, symbols /// Shared semantic information about the file being linted, which includes scopes, symbols
/// and AST nodes. See [`Semantic`]. /// and AST nodes. See [`Semantic`].
pub(super) semantic: Rc<Semantic<'a>>, pub(super) semantic: Rc<Semantic<'a>>,
/// Cross module information.
pub(super) module_record: Arc<ModuleRecord>,
/// Information about specific rules that should be disabled or enabled, via comment directives like /// Information about specific rules that should be disabled or enabled, via comment directives like
/// `eslint-disable` or `eslint-disable-next-line`. /// `eslint-disable` or `eslint-disable-next-line`.
pub(super) disable_directives: DisableDirectives<'a>, pub(super) disable_directives: DisableDirectives<'a>,
@ -67,6 +71,7 @@ impl<'a> ContextHost<'a> {
pub fn new<P: AsRef<Path>>( pub fn new<P: AsRef<Path>>(
file_path: P, file_path: P,
semantic: Rc<Semantic<'a>>, semantic: Rc<Semantic<'a>>,
module_record: Arc<ModuleRecord>,
options: LintOptions, options: LintOptions,
config: Arc<LintConfig>, config: Arc<LintConfig>,
) -> Self { ) -> Self {
@ -87,6 +92,7 @@ impl<'a> ContextHost<'a> {
Self { Self {
semantic, semantic,
module_record,
disable_directives, disable_directives,
diagnostics: RefCell::new(Vec::with_capacity(DIAGNOSTICS_INITIAL_CAPACITY)), diagnostics: RefCell::new(Vec::with_capacity(DIAGNOSTICS_INITIAL_CAPACITY)),
fix: options.fix, fix: options.fix,
@ -119,6 +125,12 @@ impl<'a> ContextHost<'a> {
&self.semantic &self.semantic
} }
/// Shared reference to the [`ModuleRecord`] of the file.
#[inline]
pub fn module_record(&self) -> &ModuleRecord {
&self.module_record
}
/// Path to the file being linted. /// Path to the file being linted.
/// ///
/// When created from a [`LintService`](`crate::service::LintService`), this /// When created from a [`LintService`](`crate::service::LintService`), this
@ -214,9 +226,9 @@ impl<'a> ContextHost<'a> {
if self.plugins.has_test() { if self.plugins.has_test() {
// let mut test_flags = FrameworkFlags::empty(); // let mut test_flags = FrameworkFlags::empty();
let vitest_like = frameworks::has_vitest_imports(self.semantic.module_record()); let vitest_like = frameworks::has_vitest_imports(self.module_record());
let jest_like = frameworks::is_jestlike_file(&self.file_path) let jest_like = frameworks::is_jestlike_file(&self.file_path)
|| frameworks::has_jest_imports(self.semantic.module_record()); || frameworks::has_jest_imports(self.module_record());
self.frameworks.set(FrameworkFlags::Vitest, vitest_like); self.frameworks.set(FrameworkFlags::Vitest, vitest_like);
self.frameworks.set(FrameworkFlags::Jest, jest_like); self.frameworks.set(FrameworkFlags::Jest, jest_like);

View file

@ -7,6 +7,7 @@ use oxc_cfg::ControlFlowGraph;
use oxc_diagnostics::{OxcDiagnostic, Severity}; use oxc_diagnostics::{OxcDiagnostic, Severity};
use oxc_semantic::Semantic; use oxc_semantic::Semantic;
use oxc_span::{GetSpan, Span}; use oxc_span::{GetSpan, Span};
use oxc_syntax::module_record::ModuleRecord;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
use crate::rule::RuleFixMeta; use crate::rule::RuleFixMeta;
@ -105,6 +106,11 @@ impl<'a> LintContext<'a> {
&self.parent.semantic &self.parent.semantic
} }
#[inline]
pub fn module_record(&self) -> &ModuleRecord {
self.parent.module_record()
}
/// Get the control flow graph for the current program. /// Get the control flow graph for the current program.
#[inline] #[inline]
pub fn cfg(&self) -> &ControlFlowGraph { pub fn cfg(&self) -> &ControlFlowGraph {

View file

@ -21,14 +21,10 @@ mod utils;
pub mod loader; pub mod loader;
pub mod table; pub mod table;
use crate::config::ResolvedLinterState;
use std::{io::Write, path::Path, rc::Rc, sync::Arc}; use std::{io::Write, path::Path, rc::Rc, sync::Arc};
use config::{ConfigStore, LintConfig};
use context::ContextHost;
use options::LintOptions;
use oxc_semantic::{AstNode, Semantic}; use oxc_semantic::{AstNode, Semantic};
use utils::iter_possible_jest_call_node; use oxc_syntax::module_record::ModuleRecord;
pub use crate::{ pub use crate::{
builder::{LinterBuilder, LinterBuilderError}, builder::{LinterBuilder, LinterBuilderError},
@ -41,10 +37,15 @@ pub use crate::{
service::{LintService, LintServiceOptions}, service::{LintService, LintServiceOptions},
}; };
use crate::{ use crate::{
config::{OxlintEnv, OxlintGlobals, OxlintSettings}, config::{
ConfigStore, LintConfig, OxlintEnv, OxlintGlobals, OxlintSettings, ResolvedLinterState,
},
context::ContextHost,
fixer::{Fixer, Message}, fixer::{Fixer, Message},
options::LintOptions,
rules::RuleEnum, rules::RuleEnum,
table::RuleTable, table::RuleTable,
utils::iter_possible_jest_call_node,
}; };
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
@ -110,10 +111,16 @@ impl Linter {
self.config.rules() self.config.rules()
} }
pub fn run<'a>(&self, path: &Path, semantic: Rc<Semantic<'a>>) -> Vec<Message<'a>> { pub fn run<'a>(
&self,
path: &Path,
semantic: Rc<Semantic<'a>>,
module_record: Arc<ModuleRecord>,
) -> Vec<Message<'a>> {
// Get config + rules for this file. Takes base rules and applies glob-based overrides. // Get config + rules for this file. Takes base rules and applies glob-based overrides.
let ResolvedLinterState { rules, config } = self.config.resolve(path); let ResolvedLinterState { rules, config } = self.config.resolve(path);
let ctx_host = Rc::new(ContextHost::new(path, semantic, self.options, config)); let ctx_host =
Rc::new(ContextHost::new(path, semantic, module_record, self.options, config));
let rules = rules let rules = rules
.iter() .iter()

View file

@ -2,6 +2,7 @@
//! consider variables ignored by name pattern, but by where they are declared. //! consider variables ignored by name pattern, but by where they are declared.
use oxc_ast::{ast::*, AstKind}; use oxc_ast::{ast::*, AstKind};
use oxc_semantic::{NodeId, Semantic}; use oxc_semantic::{NodeId, Semantic};
use oxc_syntax::module_record::ModuleRecord;
use super::{options::ArgsOption, NoUnusedVars, Symbol}; use super::{options::ArgsOption, NoUnusedVars, Symbol};
use crate::rules::eslint::no_unused_vars::binding_pattern::{BindingContext, HasAnyUsedBinding}; use crate::rules::eslint::no_unused_vars::binding_pattern::{BindingContext, HasAnyUsedBinding};
@ -120,6 +121,7 @@ impl NoUnusedVars {
pub(super) fn is_allowed_argument<'a>( pub(super) fn is_allowed_argument<'a>(
&self, &self,
semantic: &Semantic<'a>, semantic: &Semantic<'a>,
module_record: &ModuleRecord,
symbol: &Symbol<'_, 'a>, symbol: &Symbol<'_, 'a>,
param: &FormalParameter<'a>, param: &FormalParameter<'a>,
) -> bool { ) -> bool {
@ -178,7 +180,7 @@ impl NoUnusedVars {
return false; return false;
} }
let ctx = BindingContext { options: self, semantic }; let ctx = BindingContext { options: self, semantic, module_record };
params params
.items .items
.iter() .iter()

View file

@ -1,5 +1,6 @@
use oxc_ast::ast::*; use oxc_ast::ast::*;
use oxc_semantic::{Semantic, SymbolId}; use oxc_semantic::{Semantic, SymbolId};
use oxc_syntax::module_record::ModuleRecord;
use super::{symbol::Symbol, NoUnusedVars}; use super::{symbol::Symbol, NoUnusedVars};
@ -7,16 +8,18 @@ use super::{symbol::Symbol, NoUnusedVars};
pub(super) struct BindingContext<'s, 'a> { pub(super) struct BindingContext<'s, 'a> {
pub options: &'s NoUnusedVars, pub options: &'s NoUnusedVars,
pub semantic: &'s Semantic<'a>, pub semantic: &'s Semantic<'a>,
pub module_record: &'s ModuleRecord,
} }
impl<'s, 'a> BindingContext<'s, 'a> { impl<'s, 'a> BindingContext<'s, 'a> {
#[inline] #[inline]
pub fn symbol(&self, symbol_id: SymbolId) -> Symbol<'s, 'a> { pub fn symbol(&self, module_record: &'s ModuleRecord, symbol_id: SymbolId) -> Symbol<'s, 'a> {
Symbol::new(self.semantic, symbol_id) Symbol::new(self.semantic, module_record, symbol_id)
} }
#[inline] #[inline]
pub fn has_usages(&self, symbol_id: SymbolId) -> bool { pub fn has_usages(&self, symbol_id: SymbolId, module_record: &'s ModuleRecord) -> bool {
self.symbol(symbol_id).has_usages(self.options) self.symbol(module_record, symbol_id).has_usages(self.options)
} }
} }
@ -44,7 +47,7 @@ impl<'a> HasAnyUsedBinding<'a> for BindingPatternKind<'a> {
impl<'a> HasAnyUsedBinding<'a> for BindingIdentifier<'a> { impl<'a> HasAnyUsedBinding<'a> for BindingIdentifier<'a> {
fn has_any_used_binding(&self, ctx: BindingContext<'_, 'a>) -> bool { fn has_any_used_binding(&self, ctx: BindingContext<'_, 'a>) -> bool {
ctx.has_usages(self.symbol_id()) ctx.has_usages(self.symbol_id(), ctx.module_record)
} }
} }
impl<'a> HasAnyUsedBinding<'a> for ObjectPattern<'a> { impl<'a> HasAnyUsedBinding<'a> for ObjectPattern<'a> {

View file

@ -205,7 +205,7 @@ impl Rule for NoUnusedVars {
} }
fn run_on_symbol(&self, symbol_id: SymbolId, ctx: &LintContext<'_>) { fn run_on_symbol(&self, symbol_id: SymbolId, ctx: &LintContext<'_>) {
let symbol = Symbol::new(ctx.semantic().as_ref(), symbol_id); let symbol = Symbol::new(ctx.semantic().as_ref(), ctx.module_record(), symbol_id);
if Self::should_skip_symbol(&symbol) { if Self::should_skip_symbol(&symbol) {
return; return;
} }
@ -294,7 +294,12 @@ impl NoUnusedVars {
}); });
} }
AstKind::FormalParameter(param) => { AstKind::FormalParameter(param) => {
if self.is_allowed_argument(ctx.semantic().as_ref(), symbol, param) { if self.is_allowed_argument(
ctx.semantic().as_ref(),
ctx.module_record(),
symbol,
param,
) {
return; return;
} }
ctx.diagnostic(diagnostic::param(symbol, &self.args_ignore_pattern)); ctx.diagnostic(diagnostic::param(symbol, &self.args_ignore_pattern));

View file

@ -12,10 +12,12 @@ use oxc_semantic::{
SymbolTable, SymbolTable,
}; };
use oxc_span::{GetSpan, Span}; use oxc_span::{GetSpan, Span};
use oxc_syntax::module_record::ModuleRecord;
#[derive(Clone)] #[derive(Clone)]
pub(super) struct Symbol<'s, 'a> { pub(super) struct Symbol<'s, 'a> {
semantic: &'s Semantic<'a>, semantic: &'s Semantic<'a>,
module_record: &'s ModuleRecord,
id: SymbolId, id: SymbolId,
flags: SymbolFlags, flags: SymbolFlags,
span: OnceCell<Span>, span: OnceCell<Span>,
@ -29,9 +31,13 @@ impl PartialEq for Symbol<'_, '_> {
// constructor and simple getters // constructor and simple getters
impl<'s, 'a> Symbol<'s, 'a> { impl<'s, 'a> Symbol<'s, 'a> {
pub fn new(semantic: &'s Semantic<'a>, symbol_id: SymbolId) -> Self { pub fn new(
semantic: &'s Semantic<'a>,
module_record: &'s ModuleRecord,
symbol_id: SymbolId,
) -> Self {
let flags = semantic.symbols().get_flags(symbol_id); let flags = semantic.symbols().get_flags(symbol_id);
Self { semantic, id: symbol_id, flags, span: OnceCell::new() } Self { semantic, module_record, id: symbol_id, flags, span: OnceCell::new() }
} }
#[inline] #[inline]
@ -172,7 +178,7 @@ impl<'a> Symbol<'_, 'a> {
pub fn is_exported(&self) -> bool { pub fn is_exported(&self) -> bool {
let is_in_exportable_scope = self.is_root() || self.is_in_ts_namespace(); let is_in_exportable_scope = self.is_root() || self.is_in_ts_namespace();
is_in_exportable_scope is_in_exportable_scope
&& (self.semantic.module_record().exported_bindings.contains_key(self.name()) && (self.module_record.exported_bindings.contains_key(self.name())
|| self.in_export_node()) || self.in_export_node())
} }

View file

@ -86,7 +86,7 @@ impl Rule for Named {
return; return;
} }
let module_record = semantic.module_record(); let module_record = ctx.module_record();
for import_entry in &module_record.import_entries { for import_entry in &module_record.import_entries {
// Get named import // Get named import

View file

@ -48,7 +48,7 @@ declare_oxc_lint!(
/// <https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/docs/rules/unambiguous.md> /// <https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/docs/rules/unambiguous.md>
impl Rule for Unambiguous { impl Rule for Unambiguous {
fn run_once(&self, ctx: &LintContext<'_>) { fn run_once(&self, ctx: &LintContext<'_>) {
if ctx.semantic().module_record().not_esm { if ctx.module_record().not_esm {
ctx.diagnostic(unambiguous_diagnostic(Span::default())); ctx.diagnostic(unambiguous_diagnostic(Span::default()));
} }
} }

View file

@ -69,8 +69,7 @@ impl Rule for NoBarrelFile {
} }
fn run_once(&self, ctx: &LintContext<'_>) { fn run_once(&self, ctx: &LintContext<'_>) {
let semantic = ctx.semantic(); let module_record = ctx.module_record();
let module_record = semantic.module_record();
if module_record.not_esm { if module_record.not_esm {
return; return;

View file

@ -97,7 +97,7 @@ pub fn import_matcher<'a>(
expected_module_name: &'a str, expected_module_name: &'a str,
) -> bool { ) -> bool {
let expected_module_name = expected_module_name.cow_to_lowercase(); let expected_module_name = expected_module_name.cow_to_lowercase();
ctx.semantic().module_record().import_entries.iter().any(|import| { ctx.module_record().import_entries.iter().any(|import| {
import.module_request.name().as_str() == expected_module_name import.module_request.name().as_str() == expected_module_name
&& import.local_name.name().as_str() == actual_local_name && import.local_name.name().as_str() == actual_local_name
}) })
@ -109,7 +109,7 @@ pub fn is_import<'a>(
expected_local_name: &'a str, expected_local_name: &'a str,
expected_module_name: &'a str, expected_module_name: &'a str,
) -> bool { ) -> bool {
if ctx.semantic().module_record().requested_modules.is_empty() if ctx.module_record().requested_modules.is_empty()
&& ctx.scopes().get_bindings(ctx.scopes().root_scope_id()).is_empty() && ctx.scopes().get_bindings(ctx.scopes().root_scope_id()).is_empty()
{ {
return actual_local_name == expected_local_name; return actual_local_name == expected_local_name;

View file

@ -297,9 +297,8 @@ impl Runtime {
}; };
let mut semantic = semantic_ret.semantic; let mut semantic = semantic_ret.semantic;
semantic.set_module_record(&module_record);
semantic.set_irregular_whitespaces(ret.irregular_whitespaces); semantic.set_irregular_whitespaces(ret.irregular_whitespaces);
self.linter.run(path, Rc::new(semantic)) self.linter.run(path, Rc::new(semantic), Arc::clone(&module_record))
} }
pub(super) fn init_cache_state(&self, path: &Path) -> bool { pub(super) fn init_cache_state(&self, path: &Path) -> bool {

View file

@ -321,10 +321,12 @@ mod test {
SemanticBuilder::new().with_cfg(true).build(&parser_ret.program).semantic; SemanticBuilder::new().with_cfg(true).build(&parser_ret.program).semantic;
let semantic_ret = Rc::new(semantic_ret); let semantic_ret = Rc::new(semantic_ret);
let module_record = Arc::new(parser_ret.module_record);
let build_ctx = |path: &'static str| { let build_ctx = |path: &'static str| {
Rc::new(ContextHost::new( Rc::new(ContextHost::new(
path, path,
Rc::clone(&semantic_ret), Rc::clone(&semantic_ret),
Arc::clone(&module_record),
LintOptions::default(), LintOptions::default(),
Arc::default(), Arc::default(),
)) ))

View file

@ -1,9 +1,6 @@
//! Semantic Builder //! Semantic Builder
use std::{ use std::cell::{Cell, RefCell};
cell::{Cell, RefCell},
sync::Arc,
};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@ -289,7 +286,6 @@ impl<'a> SemanticBuilder<'a> {
source_type: self.source_type, source_type: self.source_type,
comments, comments,
irregular_whitespaces: [].into(), irregular_whitespaces: [].into(),
module_record: Arc::new(oxc_syntax::module_record::ModuleRecord::default()),
nodes: self.nodes, nodes: self.nodes,
scopes: self.scope, scopes: self.scope,
symbols: self.symbols, symbols: self.symbols,

View file

@ -6,14 +6,12 @@
//! ``` //! ```
use std::ops::RangeBounds; use std::ops::RangeBounds;
use std::sync::Arc;
use oxc_ast::{ use oxc_ast::{
ast::IdentifierReference, comments_range, has_comments_between, AstKind, Comment, CommentsRange, ast::IdentifierReference, comments_range, has_comments_between, AstKind, Comment, CommentsRange,
}; };
use oxc_cfg::ControlFlowGraph; use oxc_cfg::ControlFlowGraph;
use oxc_span::{GetSpan, SourceType, Span}; use oxc_span::{GetSpan, SourceType, Span};
use oxc_syntax::module_record::ModuleRecord;
pub use oxc_syntax::{ pub use oxc_syntax::{
scope::{ScopeFlags, ScopeId}, scope::{ScopeFlags, ScopeId},
symbol::{SymbolFlags, SymbolId}, symbol::{SymbolFlags, SymbolId},
@ -81,8 +79,6 @@ pub struct Semantic<'a> {
comments: &'a oxc_allocator::Vec<'a, Comment>, comments: &'a oxc_allocator::Vec<'a, Comment>,
irregular_whitespaces: Box<[Span]>, irregular_whitespaces: Box<[Span]>,
module_record: Arc<ModuleRecord>,
/// Parsed JSDoc comments. /// Parsed JSDoc comments.
jsdoc: JSDocFinder<'a>, jsdoc: JSDocFinder<'a>,
@ -134,10 +130,6 @@ impl<'a> Semantic<'a> {
self.irregular_whitespaces = irregular_whitespaces; self.irregular_whitespaces = irregular_whitespaces;
} }
pub fn set_module_record(&mut self, module_record: &Arc<ModuleRecord>) {
self.module_record = Arc::clone(module_record);
}
/// Trivias (comments) found while parsing /// Trivias (comments) found while parsing
pub fn comments(&self) -> &[Comment] { pub fn comments(&self) -> &[Comment] {
self.comments self.comments
@ -165,11 +157,6 @@ impl<'a> Semantic<'a> {
&self.jsdoc &self.jsdoc
} }
/// ESM module record containing imports and exports.
pub fn module_record(&self) -> &ModuleRecord {
self.module_record.as_ref()
}
/// [`SymbolTable`] containing all symbols in the program and their /// [`SymbolTable`] containing all symbols in the program and their
/// [`Reference`]s. /// [`Reference`]s.
pub fn symbols(&self) -> &SymbolTable { pub fn symbols(&self) -> &SymbolTable {

View file

@ -7,6 +7,7 @@ use std::{
cell::{Cell, RefCell}, cell::{Cell, RefCell},
path::{Path, PathBuf}, path::{Path, PathBuf},
rc::Rc, rc::Rc,
sync::Arc,
}; };
use oxc::{ use oxc::{
@ -20,6 +21,7 @@ use oxc::{
ScopeFlags, ScopeId, ScopeTree, SemanticBuilder, SymbolTable, ScopeFlags, ScopeId, ScopeTree, SemanticBuilder, SymbolTable,
}, },
span::SourceType, span::SourceType,
syntax::module_record::ModuleRecord,
transformer::{TransformOptions, Transformer}, transformer::{TransformOptions, Transformer},
}; };
use oxc_index::Idx; use oxc_index::Idx;
@ -198,7 +200,7 @@ impl Oxc {
.preserve_parens .preserve_parens
.unwrap_or(default_parser_options.preserve_parens), .unwrap_or(default_parser_options.preserve_parens),
}; };
let ParserReturn { mut program, errors, .. } = let ParserReturn { mut program, errors, module_record, .. } =
Parser::new(&allocator, source_text, source_type) Parser::new(&allocator, source_text, source_type)
.with_options(oxc_parser_options) .with_options(oxc_parser_options)
.parse(); .parse();
@ -227,7 +229,8 @@ impl Oxc {
); );
} }
self.run_linter(&run_options, &path, &program); let module_record = Arc::new(module_record);
self.run_linter(&run_options, &path, &program, &module_record);
self.run_prettier(&run_options, source_text, source_type); self.run_prettier(&run_options, source_text, source_type);
@ -296,12 +299,19 @@ impl Oxc {
Ok(()) Ok(())
} }
fn run_linter(&mut self, run_options: &OxcRunOptions, path: &Path, program: &Program) { fn run_linter(
&mut self,
run_options: &OxcRunOptions,
path: &Path,
program: &Program,
module_record: &Arc<ModuleRecord>,
) {
// Only lint if there are no syntax errors // Only lint if there are no syntax errors
if run_options.lint.unwrap_or_default() && self.diagnostics.borrow().is_empty() { if run_options.lint.unwrap_or_default() && self.diagnostics.borrow().is_empty() {
let semantic_ret = SemanticBuilder::new().with_cfg(true).build(program); let semantic_ret = SemanticBuilder::new().with_cfg(true).build(program);
let semantic = Rc::new(semantic_ret.semantic); let semantic = Rc::new(semantic_ret.semantic);
let linter_ret = Linter::default().run(path, Rc::clone(&semantic)); let linter_ret =
Linter::default().run(path, Rc::clone(&semantic), Arc::clone(module_record));
let diagnostics = linter_ret.into_iter().map(|e| e.error).collect(); let diagnostics = linter_ret.into_iter().map(|e| e.error).collect();
self.save_diagnostics(diagnostics); self.save_diagnostics(diagnostics);
} }

View file

@ -1,4 +1,4 @@
use std::{env, path::Path, rc::Rc}; use std::{env, path::Path, rc::Rc, sync::Arc};
use oxc_allocator::Allocator; use oxc_allocator::Allocator;
use oxc_benchmark::{criterion_group, criterion_main, BenchmarkId, Criterion}; use oxc_benchmark::{criterion_group, criterion_main, BenchmarkId, Criterion};
@ -39,7 +39,8 @@ fn bench_linter(criterion: &mut Criterion) {
.build(&ret.program); .build(&ret.program);
let linter = LinterBuilder::all().with_fix(FixKind::All).build(); let linter = LinterBuilder::all().with_fix(FixKind::All).build();
let semantic = Rc::new(semantic_ret.semantic); let semantic = Rc::new(semantic_ret.semantic);
b.iter(|| linter.run(path, Rc::clone(&semantic))); let module_record = Arc::new(ret.module_record);
b.iter(|| linter.run(path, Rc::clone(&semantic), Arc::clone(&module_record)));
}, },
); );
} }