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

fix(rome_js_semantic): semantic model considering static init block as scope #4071

Merged
merged 2 commits into from
Dec 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/rome_js_semantic/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ impl SemanticEventExtractor {
| JS_CLASS_EXPORT_DEFAULT_DECLARATION
| JS_CLASS_EXPRESSION
| JS_FUNCTION_BODY
| JS_STATIC_INITIALIZATION_BLOCK_CLASS_MEMBER
| TS_MODULE_DECLARATION
| TS_INTERFACE_DECLARATION
| TS_ENUM_DECLARATION
Expand Down Expand Up @@ -557,6 +558,7 @@ impl SemanticEventExtractor {
| JS_FOR_IN_STATEMENT
| JS_SWITCH_STATEMENT
| JS_CATCH_CLAUSE
| JS_STATIC_INITIALIZATION_BLOCK_CLASS_MEMBER
| TS_DECLARE_FUNCTION_DECLARATION
| TS_FUNCTION_TYPE
| TS_INTERFACE_DECLARATION
Expand Down
131 changes: 89 additions & 42 deletions crates/rome_js_semantic/src/tests/assertions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ impl SemanticAssertions {
}

// Check every read assertion is ok
let is_read_assertion = |e: &SemanticEvent| matches!(e, SemanticEvent::Read { .. });

for assertion in self.read_assertions.iter() {
let decl = match self
Expand All @@ -493,8 +494,8 @@ impl SemanticAssertions {
let events = match events_by_pos.get(&assertion.range.start()) {
Some(events) => events,
None => {
println!("Assertion: {:?}", assertion);
println!("Events: {:#?}", events_by_pos);
show_all_events(test_name, code, events_by_pos, is_read_assertion);
show_unmatched_assertion(test_name, code, assertion, assertion.range);
panic!("No read event found at this range");
}
};
Expand Down Expand Up @@ -593,35 +594,52 @@ impl SemanticAssertions {
}
}

// Check every at scope assertion is ok
let is_scope_event = |e: &SemanticEvent| {
matches!(
e,
SemanticEvent::ScopeStarted { .. } | SemanticEvent::ScopeEnded { .. }
)
};

for assertion in self.at_scope_assertions.iter() {
if let Some(events) = events_by_pos.get(&assertion.range.start()) {
// Check every at scope assertion is ok
for at_scope_assertion in self.at_scope_assertions.iter() {
if let Some(events) = events_by_pos.get(&at_scope_assertion.range.start()) {
// Needs to be a unique event for now
match &events[0] {
SemanticEvent::DeclarationFound {
scope_started_at, ..
} => match self.scope_start_assertions.get(&assertion.scope_name) {
} => match self
.scope_start_assertions
.get(&at_scope_assertion.scope_name)
{
Some(scope_start_assertion) => {
if scope_start_assertion.range.start() != *scope_started_at {
error_declaration_pointing_to_unknown_scope(
code,
assertion.range,
show_all_events(test_name, code, events_by_pos, is_scope_event);
show_unmatched_assertion(
test_name,
code,
at_scope_assertion,
at_scope_assertion.range,
);
panic!("Assertion pointing to a wrong scope");
}
assert_eq!(scope_start_assertion.range.start(), *scope_started_at);
}
None => error_declaration_pointing_to_unknown_scope(
code,
assertion.range,
test_name,
),
None => {
show_all_events(test_name, code, events_by_pos, is_scope_event);
show_unmatched_assertion(
test_name,
code,
at_scope_assertion,
at_scope_assertion.range,
);
panic!("Assertion pointing to a wrong scope");
}
},
_ => {
error_assertion_not_attached_to_a_declaration(
code,
assertion.range,
at_scope_assertion.range,
test_name,
);
}
Expand All @@ -630,9 +648,8 @@ impl SemanticAssertions {
}

// Check every scope start assertion is ok

for assertion in self.scope_start_assertions.values() {
if let Some(events) = events_by_pos.get(&assertion.range.start()) {
for scope_assertion in self.scope_start_assertions.values() {
if let Some(events) = events_by_pos.get(&scope_assertion.range.start()) {
let is_at_least_one_scope_start = events
.iter()
.any(|e| matches!(e, SemanticEvent::ScopeStarted { .. }));
Expand All @@ -641,12 +658,13 @@ impl SemanticAssertions {
panic!("error_scope_assertion_not_attached_to_a_scope_event");
}
} else {
panic!("No scope event found: assertion: {assertion:?}");
show_all_events(test_name, code, events_by_pos, is_scope_event);
show_unmatched_assertion(test_name, code, scope_assertion, scope_assertion.range);
panic!("No scope event found!");
}
}

// Check every scope end assertion is ok

for scope_end_assertion in self.scope_end_assertions.iter() {
// Check we have a scope start with the same label.
let scope_start_assertions_range = match self
Expand Down Expand Up @@ -762,9 +780,31 @@ fn show_unmatched_assertion(
assertion: &impl std::fmt::Debug,
assertion_range: TextRange,
) {
let assertion_code = &code[assertion_range];

// eat all trivia at the start
let mut start: usize = assertion_range.start().into();
for chr in assertion_code.chars() {
if chr.is_ascii_whitespace() {
start += chr.len_utf8();
} else {
break;
}
}

// eat all trivia at the end
let mut end: usize = assertion_range.end().into();
for chr in assertion_code.chars().rev() {
if chr.is_ascii_whitespace() {
end -= chr.len_utf8();
} else {
break;
}
}

let diagnostic = TestSemanticDiagnostic::new(
format!("This assertion was not matched: {assertion:?}"),
assertion_range,
start..end,
);
let error = diagnostic
.with_file_path((test_name.to_string(), FileId::zero()))
Expand Down Expand Up @@ -797,7 +837,34 @@ fn show_all_events<F>(
all_events.sort_by_key(|l| l.range().start());

for e in all_events {
let diagnostic = TestSemanticDiagnostic::new(format!("{e:?}"), e.range());
let diagnostic = match e {
SemanticEvent::ScopeStarted { range, .. } => {
let mut start: usize = range.start().into();
let code = &code[range];
for chr in code.chars() {
if chr.is_ascii_whitespace() {
start += chr.len_utf8();
} else {
break;
}
}
TestSemanticDiagnostic::new(format!("{e:?}"), start..start + 1)
}
SemanticEvent::ScopeEnded { range, .. } => {
let mut start: usize = range.end().into();
let code = &code[range];
for chr in code.chars().rev() {
if chr.is_ascii_whitespace() {
start -= chr.len_utf8();
} else {
break;
}
}
TestSemanticDiagnostic::new(format!("{e:?}"), start - 1..start)
}
_ => TestSemanticDiagnostic::new(format!("{e:?}"), e.range()),
};

let error = diagnostic
.with_file_path((test_name.to_string(), FileId::zero()))
.with_file_source_code(code);
Expand Down Expand Up @@ -828,26 +895,6 @@ fn error_assertion_not_attached_to_a_declaration(
panic!("This assertion must be attached to a SemanticEvent::DeclarationFound.");
}

fn error_declaration_pointing_to_unknown_scope(
code: &str,
assertion_range: TextRange,
test_name: &str,
) {
let diagnostic = TestSemanticDiagnostic::new(
"Declaration assertions is pointing to the wrong scope",
assertion_range,
);

let error = diagnostic
.with_file_path((test_name.to_string(), FileId::zero()))
.with_file_source_code(code);

let mut console = EnvConsole::default();
console.log(markup! {
{PrintDiagnostic::verbose(&error)}
});
}

fn error_assertion_name_clash(
token: &JsSyntaxToken,
code: &str,
Expand Down
18 changes: 17 additions & 1 deletion crates/rome_js_semantic/src/tests/references.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,24 @@ assert_semantics! {
"class C { static { () => a/*READ A*/; let a/*#A*/ = 1; } };",
}

// Typescript types
// Static Initialization Block
assert_semantics! {
ok_reference_static_initialization_block,
"const a/*#A1*/ = 1;
console.log(a/*READ A1*/);

class A {
static {
console.log(a/*READ A2*/);
const a/*#A2*/ = 2;
console.log(a/*READ A2*/);
}
};

console.log(a/*READ A1*/);",
}

// Typescript types
assert_semantics! {
ok_typescript_function_type,
"function f (a/*#A1*/, b: (a/*#A2*/) => any) { return b(a/*READ A1*/); };",
Expand Down
10 changes: 10 additions & 0 deletions crates/rome_js_semantic/src/tests/scopes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ assert_semantics! {
ok_scope_class_setter, ";class A { set/*START A*/ name(v) {}/*END A*/ }",
}

// Static Initialization Block
assert_semantics! {
ok_scope_static_initialization_block,
"class A {
static/*START A*/ {
const a/*@ A*/ = 2;
}/*END A*/
};",
}

// Type parameters
assert_semantics! {
ok_type_parameter, "export type /*START A*/ EventHandler<Event /*# Event */ /*@ A */ extends string> = `on${ Event /*READ Event */ }` /*END A*/",
Expand Down
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载