Skip to content

Commit

Permalink
refactor(semantic)!: remove ModuleRecord from Semantic (#7548)
Browse files Browse the repository at this point in the history
`ModuleRecord` will eventually be moved to be linter specific thing for cross module data sharing, which means we can add more data to it.
  • Loading branch information
Boshen committed Nov 29, 2024
1 parent 8a788b8 commit 0be5233
Show file tree
Hide file tree
Showing 18 changed files with 91 additions and 55 deletions.
3 changes: 2 additions & 1 deletion crates/oxc_language_server/src/linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,9 +290,10 @@ impl IsolatedLintHandler {
return Some(Self::wrap_diagnostics(path, &source_text, reports, start));
};

let module_record = Arc::new(ret.module_record);
let mut semantic = semantic_ret.semantic;
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
.into_iter()
Expand Down
18 changes: 15 additions & 3 deletions crates/oxc_linter/src/context/host.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{cell::RefCell, path::Path, rc::Rc, sync::Arc};

use oxc_semantic::Semantic;
use oxc_span::SourceType;
use std::{cell::RefCell, path::Path, rc::Rc, sync::Arc};
use oxc_syntax::module_record::ModuleRecord;

use crate::{
config::{LintConfig, LintPlugins},
Expand Down Expand Up @@ -37,6 +39,8 @@ pub(crate) struct ContextHost<'a> {
/// Shared semantic information about the file being linted, which includes scopes, symbols
/// and AST nodes. See [`Semantic`].
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
/// `eslint-disable` or `eslint-disable-next-line`.
pub(super) disable_directives: DisableDirectives<'a>,
Expand Down Expand Up @@ -67,6 +71,7 @@ impl<'a> ContextHost<'a> {
pub fn new<P: AsRef<Path>>(
file_path: P,
semantic: Rc<Semantic<'a>>,
module_record: Arc<ModuleRecord>,
options: LintOptions,
config: Arc<LintConfig>,
) -> Self {
Expand All @@ -87,6 +92,7 @@ impl<'a> ContextHost<'a> {

Self {
semantic,
module_record,
disable_directives,
diagnostics: RefCell::new(Vec::with_capacity(DIAGNOSTICS_INITIAL_CAPACITY)),
fix: options.fix,
Expand Down Expand Up @@ -119,6 +125,12 @@ impl<'a> ContextHost<'a> {
&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.
///
/// When created from a [`LintService`](`crate::service::LintService`), this
Expand Down Expand Up @@ -214,9 +226,9 @@ impl<'a> ContextHost<'a> {
if self.plugins.has_test() {
// 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)
|| 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::Jest, jest_like);
Expand Down
6 changes: 6 additions & 0 deletions crates/oxc_linter/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use oxc_cfg::ControlFlowGraph;
use oxc_diagnostics::{OxcDiagnostic, Severity};
use oxc_semantic::Semantic;
use oxc_span::{GetSpan, Span};
use oxc_syntax::module_record::ModuleRecord;

#[cfg(debug_assertions)]
use crate::rule::RuleFixMeta;
Expand Down Expand Up @@ -105,6 +106,11 @@ impl<'a> LintContext<'a> {
&self.parent.semantic
}

#[inline]
pub fn module_record(&self) -> &ModuleRecord {
self.parent.module_record()
}

/// Get the control flow graph for the current program.
#[inline]
pub fn cfg(&self) -> &ControlFlowGraph {
Expand Down
23 changes: 15 additions & 8 deletions crates/oxc_linter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,10 @@ mod utils;
pub mod loader;
pub mod table;

use crate::config::ResolvedLinterState;
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 utils::iter_possible_jest_call_node;
use oxc_syntax::module_record::ModuleRecord;

pub use crate::{
builder::{LinterBuilder, LinterBuilderError},
Expand All @@ -41,10 +37,15 @@ pub use crate::{
service::{LintService, LintServiceOptions},
};
use crate::{
config::{OxlintEnv, OxlintGlobals, OxlintSettings},
config::{
ConfigStore, LintConfig, OxlintEnv, OxlintGlobals, OxlintSettings, ResolvedLinterState,
},
context::ContextHost,
fixer::{Fixer, Message},
options::LintOptions,
rules::RuleEnum,
table::RuleTable,
utils::iter_possible_jest_call_node,
};

#[cfg(target_pointer_width = "64")]
Expand Down Expand Up @@ -110,10 +111,16 @@ impl Linter {
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.
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
.iter()
Expand Down
4 changes: 3 additions & 1 deletion crates/oxc_linter/src/rules/eslint/no_unused_vars/allowed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! consider variables ignored by name pattern, but by where they are declared.
use oxc_ast::{ast::*, AstKind};
use oxc_semantic::{NodeId, Semantic};
use oxc_syntax::module_record::ModuleRecord;

use super::{options::ArgsOption, NoUnusedVars, Symbol};
use crate::rules::eslint::no_unused_vars::binding_pattern::{BindingContext, HasAnyUsedBinding};
Expand Down Expand Up @@ -120,6 +121,7 @@ impl NoUnusedVars {
pub(super) fn is_allowed_argument<'a>(
&self,
semantic: &Semantic<'a>,
module_record: &ModuleRecord,
symbol: &Symbol<'_, 'a>,
param: &FormalParameter<'a>,
) -> bool {
Expand Down Expand Up @@ -178,7 +180,7 @@ impl NoUnusedVars {
return false;
}

let ctx = BindingContext { options: self, semantic };
let ctx = BindingContext { options: self, semantic, module_record };
params
.items
.iter()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
use oxc_ast::ast::*;
use oxc_semantic::{Semantic, SymbolId};
use oxc_syntax::module_record::ModuleRecord;

use super::{symbol::Symbol, NoUnusedVars};

#[derive(Clone, Copy)]
pub(super) struct BindingContext<'s, 'a> {
pub options: &'s NoUnusedVars,
pub semantic: &'s Semantic<'a>,
pub module_record: &'s ModuleRecord,
}

impl<'s, 'a> BindingContext<'s, 'a> {
#[inline]
pub fn symbol(&self, symbol_id: SymbolId) -> Symbol<'s, 'a> {
Symbol::new(self.semantic, symbol_id)
pub fn symbol(&self, module_record: &'s ModuleRecord, symbol_id: SymbolId) -> Symbol<'s, 'a> {
Symbol::new(self.semantic, module_record, symbol_id)
}

#[inline]
pub fn has_usages(&self, symbol_id: SymbolId) -> bool {
self.symbol(symbol_id).has_usages(self.options)
pub fn has_usages(&self, symbol_id: SymbolId, module_record: &'s ModuleRecord) -> bool {
self.symbol(module_record, symbol_id).has_usages(self.options)
}
}

Expand Down Expand Up @@ -44,7 +47,7 @@ impl<'a> HasAnyUsedBinding<'a> for BindingPatternKind<'a> {

impl<'a> HasAnyUsedBinding<'a> for BindingIdentifier<'a> {
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> {
Expand Down
9 changes: 7 additions & 2 deletions crates/oxc_linter/src/rules/eslint/no_unused_vars/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ impl Rule for NoUnusedVars {
}

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) {
return;
}
Expand Down Expand Up @@ -294,7 +294,12 @@ impl NoUnusedVars {
});
}
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;
}
ctx.diagnostic(diagnostic::param(symbol, &self.args_ignore_pattern));
Expand Down
12 changes: 9 additions & 3 deletions crates/oxc_linter/src/rules/eslint/no_unused_vars/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ use oxc_semantic::{
SymbolTable,
};
use oxc_span::{GetSpan, Span};
use oxc_syntax::module_record::ModuleRecord;

#[derive(Clone)]
pub(super) struct Symbol<'s, 'a> {
semantic: &'s Semantic<'a>,
module_record: &'s ModuleRecord,
id: SymbolId,
flags: SymbolFlags,
span: OnceCell<Span>,
Expand All @@ -29,9 +31,13 @@ impl PartialEq for Symbol<'_, '_> {

// constructor and simple getters
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);
Self { semantic, id: symbol_id, flags, span: OnceCell::new() }
Self { semantic, module_record, id: symbol_id, flags, span: OnceCell::new() }
}

#[inline]
Expand Down Expand Up @@ -172,7 +178,7 @@ impl<'a> Symbol<'_, 'a> {
pub fn is_exported(&self) -> bool {
let is_in_exportable_scope = self.is_root() || self.is_in_ts_namespace();
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())
}

Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/rules/import/named.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl Rule for Named {
return;
}

let module_record = semantic.module_record();
let module_record = ctx.module_record();

for import_entry in &module_record.import_entries {
// Get named import
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/rules/import/unambiguous.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ declare_oxc_lint!(
/// <https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/docs/rules/unambiguous.md>
impl Rule for Unambiguous {
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()));
}
}
Expand Down
3 changes: 1 addition & 2 deletions crates/oxc_linter/src/rules/oxc/no_barrel_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ impl Rule for NoBarrelFile {
}

fn run_once(&self, ctx: &LintContext<'_>) {
let semantic = ctx.semantic();
let module_record = semantic.module_record();
let module_record = ctx.module_record();

if module_record.not_esm {
return;
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_linter/src/rules/react/jsx_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub fn import_matcher<'a>(
expected_module_name: &'a str,
) -> bool {
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.local_name.name().as_str() == actual_local_name
})
Expand All @@ -109,7 +109,7 @@ pub fn is_import<'a>(
expected_local_name: &'a str,
expected_module_name: &'a str,
) -> 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()
{
return actual_local_name == expected_local_name;
Expand Down
3 changes: 1 addition & 2 deletions crates/oxc_linter/src/service/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,8 @@ impl Runtime {
};

let mut semantic = semantic_ret.semantic;
semantic.set_module_record(&module_record);
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 {
Expand Down
2 changes: 2 additions & 0 deletions crates/oxc_linter/src/utils/jest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,10 +321,12 @@ mod test {
SemanticBuilder::new().with_cfg(true).build(&parser_ret.program).semantic;
let semantic_ret = Rc::new(semantic_ret);

let module_record = Arc::new(parser_ret.module_record);
let build_ctx = |path: &'static str| {
Rc::new(ContextHost::new(
path,
Rc::clone(&semantic_ret),
Arc::clone(&module_record),
LintOptions::default(),
Arc::default(),
))
Expand Down
6 changes: 1 addition & 5 deletions crates/oxc_semantic/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
//! Semantic Builder
use std::{
cell::{Cell, RefCell},
sync::Arc,
};
use std::cell::{Cell, RefCell};

use rustc_hash::FxHashMap;

Expand Down Expand Up @@ -289,7 +286,6 @@ impl<'a> SemanticBuilder<'a> {
source_type: self.source_type,
comments,
irregular_whitespaces: [].into(),
module_record: Arc::new(oxc_syntax::module_record::ModuleRecord::default()),
nodes: self.nodes,
scopes: self.scope,
symbols: self.symbols,
Expand Down
Loading

0 comments on commit 0be5233

Please sign in to comment.