Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
use oncelock/threadlocal where possible
Browse files Browse the repository at this point in the history
  • Loading branch information
addisoncrump committed Jun 28, 2023
1 parent 90111a0 commit 9ea7125
Showing 1 changed file with 57 additions and 52 deletions.
109 changes: 57 additions & 52 deletions fuzz/fuzz_targets/rome_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use rome_json_parser::parse_json;
use rome_service::Rules;
use similar::TextDiff;
use std::fmt::{Display, Formatter};
use std::sync::OnceLock;

pub fn fuzz_js_parser_with_source_type(data: &[u8], source: JsFileSource) -> Corpus {
let Ok(code1) = std::str::from_utf8(data) else { return Corpus::Reject; };
Expand All @@ -32,9 +33,13 @@ pub fn fuzz_js_parser_with_source_type(data: &[u8], source: JsFileSource) -> Cor
Corpus::Keep
}

static mut ANALYSIS_RULES: Option<Rules> = None;
static mut ANALYSIS_RULE_FILTERS: Option<Vec<RuleFilter>> = None;
static mut ANALYSIS_OPTIONS: Option<AnalyzerOptions> = None;
static ANALYSIS_RULES: OnceLock<Rules> = OnceLock::new();
static ANALYSIS_RULE_FILTERS: OnceLock<Vec<RuleFilter>> = OnceLock::new();

// have to use thread local because AnalyzerOptions contains a Box<dyn Any>, which isn't thread-safe
thread_local! {
static ANALYSIS_OPTIONS: AnalyzerOptions = AnalyzerOptions::default();
}

struct DiagnosticDescriptionExtractor<'a, D> {
diagnostic: &'a D,
Expand All @@ -58,43 +63,36 @@ where
pub fn fuzz_js_formatter_with_source_type(data: &[u8], source: JsFileSource) -> Corpus {
let Ok(code1) = std::str::from_utf8(data) else { return Corpus::Reject; };

// TODO: replace with OnceLock when upgrading to 1.70
let rule_filters = if let Some(rules) = unsafe { ANALYSIS_RULE_FILTERS.as_ref() } {
rules
} else {
let rules = unsafe {
ANALYSIS_RULES.get_or_insert_with(|| Rules {
all: Some(true),
..Default::default()
})
};
let rules = rules.as_enabled_rules().into_iter().collect::<Vec<_>>();
unsafe {
ANALYSIS_RULE_FILTERS = Some(rules);
ANALYSIS_RULE_FILTERS.as_ref().unwrap_unchecked()
}
};
let options = unsafe { ANALYSIS_OPTIONS.get_or_insert_with(AnalyzerOptions::default) };
let rules = ANALYSIS_RULES.get_or_init(|| Rules {
all: Some(true),
..Default::default()
});
let rule_filters = ANALYSIS_RULE_FILTERS
.get_or_init(|| rules.as_enabled_rules().into_iter().collect::<Vec<_>>());

let parse1 = parse(code1, source);
if !parse1.has_errors() {
let language = JsFormatLanguage::new(JsFormatOptions::new(source));
let tree1 = parse1.tree();
let mut linter_errors = Vec::new();
let _ = analyze(
&tree1,
AnalysisFilter::from_enabled_rules(Some(rule_filters)),
options,
source,
|e| -> ControlFlow<()> {
if let Some(diagnostic) = e.diagnostic() {
linter_errors
.push(DiagnosticDescriptionExtractor::new(&diagnostic).to_string());
}
let _ = ANALYSIS_OPTIONS
.try_with(|options| {
analyze(
&tree1,
AnalysisFilter::from_enabled_rules(Some(rule_filters)),
options,
source,
|e| -> ControlFlow<()> {
if let Some(diagnostic) = e.diagnostic() {
linter_errors
.push(DiagnosticDescriptionExtractor::new(&diagnostic).to_string());
}

ControlFlow::Continue(())
},
);
ControlFlow::Continue(())
},
)
})
.unwrap();
let syntax1 = parse1.syntax();
if let Ok(formatted1) = format_node(&syntax1, language.clone()) {
if let Ok(printed1) = formatted1.print() {
Expand All @@ -108,25 +106,32 @@ pub fn fuzz_js_formatter_with_source_type(data: &[u8], source: JsFileSource) ->
.header("original code", "formatted")
);
let tree2 = parse2.tree();
let (maybe_diagnostic, _) = analyze(
&tree2,
AnalysisFilter::from_enabled_rules(Some(rule_filters)),
options,
source,
|e| {
if let Some(diagnostic) = e.diagnostic() {
let new_error =
DiagnosticDescriptionExtractor::new(&diagnostic).to_string();
if let Some(idx) = linter_errors.iter().position(|e| *e == new_error) {
linter_errors.remove(idx);
} else {
return ControlFlow::Break(new_error);
}
}

ControlFlow::Continue(())
},
);
let (maybe_diagnostic, _) = ANALYSIS_OPTIONS
.try_with(|options| {
analyze(
&tree2,
AnalysisFilter::from_enabled_rules(Some(rule_filters)),
options,
source,
|e| {
if let Some(diagnostic) = e.diagnostic() {
let new_error =
DiagnosticDescriptionExtractor::new(&diagnostic)
.to_string();
if let Some(idx) =
linter_errors.iter().position(|e| *e == new_error)
{
linter_errors.remove(idx);
} else {
return ControlFlow::Break(new_error);
}
}

ControlFlow::Continue(())
},
)
})
.unwrap();
if let Some(diagnostic) = maybe_diagnostic {
panic!(
"formatter introduced linter failure: {} (expected one of: {})\n{}",
Expand Down

0 comments on commit 9ea7125

Please sign in to comment.