Skip to content

Commit 1f2301d

Browse files
committed
refactor(linter): remove RulesCache
1 parent 54582cb commit 1f2301d

File tree

2 files changed

+40
-119
lines changed

2 files changed

+40
-119
lines changed

crates/oxc_linter/src/config/config_builder.rs

Lines changed: 39 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::{
2-
cell::{Ref, RefCell},
32
fmt::{self, Debug, Display},
43
path::PathBuf,
54
};
@@ -23,7 +22,6 @@ pub struct ConfigStoreBuilder {
2322
config: LintConfig,
2423
categories: OxlintCategories,
2524
overrides: OxlintOverrides,
26-
cache: RulesCache,
2725

2826
// Collect all `extends` file paths for the language server.
2927
// The server will tell the clients to watch for the extends files.
@@ -46,10 +44,9 @@ impl ConfigStoreBuilder {
4644
let rules = FxHashMap::default();
4745
let categories: OxlintCategories = OxlintCategories::default();
4846
let overrides = OxlintOverrides::default();
49-
let cache = RulesCache::new(config.plugins);
5047
let extended_paths = Vec::new();
5148

52-
Self { rules, config, categories, overrides, cache, extended_paths }
49+
Self { rules, config, categories, overrides, extended_paths }
5350
}
5451

5552
/// Warn on all rules in all plugins and categories, including those in `nursery`.
@@ -60,10 +57,9 @@ impl ConfigStoreBuilder {
6057
let config = LintConfig { plugins: LintPlugins::all(), ..LintConfig::default() };
6158
let overrides = OxlintOverrides::default();
6259
let categories: OxlintCategories = OxlintCategories::default();
63-
let cache = RulesCache::new(config.plugins);
6460
let rules = RULES.iter().map(|rule| (rule.clone(), AllowWarnDeny::Warn)).collect();
6561
let extended_paths = Vec::new();
66-
Self { rules, config, categories, overrides, cache, extended_paths }
62+
Self { rules, config, categories, overrides, extended_paths }
6763
}
6864

6965
/// Create a [`ConfigStoreBuilder`] from a loaded or manually built [`Oxlintrc`].
@@ -154,25 +150,18 @@ impl ConfigStoreBuilder {
154150
globals: oxlintrc.globals,
155151
path: Some(oxlintrc.path),
156152
};
157-
let cache = RulesCache::new(config.plugins);
158-
159-
let mut builder = Self {
160-
rules,
161-
config,
162-
categories,
163-
overrides: oxlintrc.overrides,
164-
cache,
165-
extended_paths,
166-
};
153+
154+
let mut builder =
155+
Self { rules, config, categories, overrides: oxlintrc.overrides, extended_paths };
167156

168157
for filter in oxlintrc.categories.filters() {
169158
builder = builder.with_filter(&filter);
170159
}
171160

172161
{
173-
let all_rules = builder.cache.borrow();
162+
let all_rules = builder.get_all_rules();
174163

175-
oxlintrc.rules.override_rules(&mut builder.rules, all_rules.as_slice());
164+
oxlintrc.rules.override_rules(&mut builder.rules, &all_rules);
176165
}
177166

178167
Ok(builder)
@@ -194,7 +183,6 @@ impl ConfigStoreBuilder {
194183
#[inline]
195184
pub fn with_plugins(mut self, plugins: LintPlugins) -> Self {
196185
self.config.plugins = plugins;
197-
self.cache.set_plugins(plugins);
198186
self
199187
}
200188

@@ -210,7 +198,6 @@ impl ConfigStoreBuilder {
210198
#[inline]
211199
pub fn and_plugins(mut self, plugins: LintPlugins, enabled: bool) -> Self {
212200
self.config.plugins.set(plugins, enabled);
213-
self.cache.set_plugins(self.config.plugins);
214201
self
215202
}
216203

@@ -272,11 +259,30 @@ impl ConfigStoreBuilder {
272259
/// Warn/Deny a let of rules based on some predicate. Rules already in `self.rules` get
273260
/// re-configured, while those that are not are added. Affects rules where `query` returns
274261
/// `true`.
262+
fn get_all_rules(&self) -> Vec<RuleEnum> {
263+
if self.config.plugins.is_all() {
264+
RULES.clone()
265+
} else {
266+
let mut plugins = self.config.plugins;
267+
268+
// we need to include some jest rules when vitest is enabled, see [`VITEST_COMPATIBLE_JEST_RULES`]
269+
if plugins.contains(LintPlugins::VITEST) {
270+
plugins = plugins.union(LintPlugins::JEST);
271+
}
272+
273+
RULES
274+
.iter()
275+
.filter(|rule| plugins.contains(LintPlugins::from(rule.plugin_name())))
276+
.cloned()
277+
.collect()
278+
}
279+
}
280+
275281
fn upsert_where<F>(&mut self, severity: AllowWarnDeny, query: F)
276282
where
277283
F: Fn(&&RuleEnum) -> bool,
278284
{
279-
let all_rules = self.cache.borrow();
285+
let all_rules = self.get_all_rules();
280286
// NOTE: we may want to warn users if they're configuring a rule that does not exist.
281287
let rules_to_configure = all_rules.iter().filter(query);
282288
for rule in rules_to_configure {
@@ -295,15 +301,18 @@ impl ConfigStoreBuilder {
295301
// When a plugin gets disabled before build(), rules for that plugin aren't removed until
296302
// with_filters() gets called. If the user never calls it, those now-undesired rules need
297303
// to be taken out.
298-
let plugins = self.plugins();
299-
let mut rules = if self.cache.is_stale() {
300-
self.rules
301-
.into_iter()
302-
.filter(|(r, _)| plugins.contains(r.plugin_name().into()))
303-
.collect()
304-
} else {
305-
self.rules.into_iter().collect::<Vec<_>>()
306-
};
304+
let mut plugins = self.plugins();
305+
306+
// Apply the same Vitest->Jest logic as in get_all_rules()
307+
if plugins.contains(LintPlugins::VITEST) {
308+
plugins = plugins.union(LintPlugins::JEST);
309+
}
310+
311+
let mut rules: Vec<_> = self
312+
.rules
313+
.into_iter()
314+
.filter(|(r, _)| plugins.contains(r.plugin_name().into()))
315+
.collect();
307316
rules.sort_unstable_by_key(|(r, _)| r.id());
308317
Config::new(rules, self.categories, self.config, self.overrides)
309318
}
@@ -411,94 +420,6 @@ impl Display for ConfigBuilderError {
411420

412421
impl std::error::Error for ConfigBuilderError {}
413422

414-
struct RulesCache {
415-
all_rules: RefCell<Option<Vec<RuleEnum>>>,
416-
plugins: LintPlugins,
417-
last_fresh_plugins: LintPlugins,
418-
}
419-
420-
impl RulesCache {
421-
#[inline]
422-
#[must_use]
423-
pub fn new(plugins: LintPlugins) -> Self {
424-
Self { all_rules: RefCell::new(None), plugins, last_fresh_plugins: plugins }
425-
}
426-
427-
pub fn set_plugins(&mut self, plugins: LintPlugins) {
428-
if self.plugins == plugins {
429-
return;
430-
}
431-
self.last_fresh_plugins = self.plugins;
432-
self.plugins = plugins;
433-
self.clear();
434-
}
435-
436-
pub fn is_stale(&self) -> bool {
437-
// NOTE: After all_rules cache has been initialized _at least once_ (e.g. its borrowed, or
438-
// initialize() is called), all_rules will be some if and only if last_fresh_plugins ==
439-
// plugins. Right before creation, (::new()) and before initialize() is called, these two
440-
// fields will be equal _but all_rules will be none_. This is OK for this function, but is
441-
// a possible future foot-gun. ConfigBuilder uses this to re-build its rules list in
442-
// ::build(). If cache is created but never made stale (by changing plugins),
443-
// ConfigBuilder's rule list won't need updating anyways, meaning its sound for this to
444-
// return `false`.
445-
self.last_fresh_plugins != self.plugins
446-
}
447-
448-
#[must_use]
449-
fn borrow(&self) -> Ref<'_, Vec<RuleEnum>> {
450-
let cached = self.all_rules.borrow();
451-
if cached.is_some() {
452-
Ref::map(cached, |cached| cached.as_ref().unwrap())
453-
} else {
454-
drop(cached);
455-
self.initialize();
456-
Ref::map(self.all_rules.borrow(), |cached| cached.as_ref().unwrap())
457-
}
458-
}
459-
460-
/// # Panics
461-
/// If the cache cell is currently borrowed.
462-
fn clear(&self) {
463-
*self.all_rules.borrow_mut() = None;
464-
}
465-
466-
/// Forcefully initialize this cache with all rules in all plugins currently
467-
/// enabled.
468-
///
469-
/// This will clobber whatever value is currently stored. It should only be
470-
/// called when the cache is not populated, either because it has not been
471-
/// initialized yet or it was cleared with [`Self::clear`].
472-
///
473-
/// # Panics
474-
/// If the cache cell is currently borrowed.
475-
fn initialize(&self) {
476-
debug_assert!(
477-
self.all_rules.borrow().is_none(),
478-
"Cannot re-initialize a populated rules cache. It must be cleared first."
479-
);
480-
481-
let all_rules: Vec<_> = if self.plugins.is_all() {
482-
RULES.clone()
483-
} else {
484-
let mut plugins = self.plugins;
485-
486-
// we need to include some jest rules when vitest is enabled, see [`VITEST_COMPATIBLE_JEST_RULES`]
487-
if plugins.contains(LintPlugins::VITEST) {
488-
plugins = plugins.union(LintPlugins::JEST);
489-
}
490-
491-
RULES
492-
.iter()
493-
.filter(|rule| plugins.contains(LintPlugins::from(rule.plugin_name())))
494-
.cloned()
495-
.collect()
496-
};
497-
498-
*self.all_rules.borrow_mut() = Some(all_rules);
499-
}
500-
}
501-
502423
#[cfg(test)]
503424
mod test {
504425
use std::path::PathBuf;

crates/oxc_linter/src/tester.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ impl Tester {
510510
ConfigStoreBuilder::from_oxlintrc(true, Oxlintrc::deserialize(v).unwrap())
511511
.unwrap()
512512
})
513-
.with_plugins(self.plugins)
513+
.with_plugins(self.plugins.union(LintPlugins::from(self.plugin_name)))
514514
.with_rule(rule, AllowWarnDeny::Warn)
515515
.build(),
516516
FxHashMap::default(),

0 commit comments

Comments
 (0)