ra_syntax: fix reparsing merging errors, also now reparse_token() reports errors

This commit is contained in:
Veetaha 2020-02-18 02:11:16 +02:00
parent fc5e7b8807
commit 053ccf4121

View file

@ -27,8 +27,8 @@ pub(crate) fn incremental_reparse(
edit: &AtomTextEdit, edit: &AtomTextEdit,
errors: Vec<SyntaxError>, errors: Vec<SyntaxError>,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
if let Some((green, old_range)) = reparse_token(node, &edit) { if let Some((green, new_errors, old_range)) = reparse_token(node, &edit) {
return Some((green, merge_errors(errors, Vec::new(), old_range, edit), old_range)); return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
} }
if let Some((green, new_errors, old_range)) = reparse_block(node, &edit) { if let Some((green, new_errors, old_range)) = reparse_block(node, &edit) {
@ -40,7 +40,7 @@ pub(crate) fn incremental_reparse(
fn reparse_token<'node>( fn reparse_token<'node>(
root: &'node SyntaxNode, root: &'node SyntaxNode,
edit: &AtomTextEdit, edit: &AtomTextEdit,
) -> Option<(GreenNode, TextRange)> { ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
let prev_token = algo::find_covering_element(root, edit.delete).as_token()?.clone(); let prev_token = algo::find_covering_element(root, edit.delete).as_token()?.clone();
let prev_token_kind = prev_token.kind(); let prev_token_kind = prev_token.kind();
match prev_token_kind { match prev_token_kind {
@ -54,7 +54,7 @@ fn reparse_token<'node>(
} }
let mut new_text = get_text_after_edit(prev_token.clone().into(), &edit); let mut new_text = get_text_after_edit(prev_token.clone().into(), &edit);
let (new_token_kind, _error) = lex_single_syntax_kind(&new_text)?; let (new_token_kind, new_err) = lex_single_syntax_kind(&new_text)?;
if new_token_kind != prev_token_kind if new_token_kind != prev_token_kind
|| (new_token_kind == IDENT && is_contextual_kw(&new_text)) || (new_token_kind == IDENT && is_contextual_kw(&new_text))
@ -76,7 +76,11 @@ fn reparse_token<'node>(
let new_token = let new_token =
GreenToken::new(rowan::SyntaxKind(prev_token_kind.into()), new_text.into()); GreenToken::new(rowan::SyntaxKind(prev_token_kind.into()), new_text.into());
Some((prev_token.replace_with(new_token), prev_token.text_range())) Some((
prev_token.replace_with(new_token),
new_err.into_iter().collect(),
prev_token.text_range(),
))
} }
_ => None, _ => None,
} }
@ -200,9 +204,9 @@ mod tests {
let fully_reparsed = SourceFile::parse(&after); let fully_reparsed = SourceFile::parse(&after);
let incrementally_reparsed: Parse<SourceFile> = { let incrementally_reparsed: Parse<SourceFile> = {
let f = SourceFile::parse(&before); let before = SourceFile::parse(&before);
let (green, new_errors, range) = let (green, new_errors, range) =
incremental_reparse(f.tree().syntax(), &edit, f.errors.to_vec()).unwrap(); incremental_reparse(before.tree().syntax(), &edit, before.errors.to_vec()).unwrap();
assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length"); assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length");
Parse::new(green, new_errors) Parse::new(green, new_errors)
}; };
@ -211,6 +215,7 @@ mod tests {
&format!("{:#?}", fully_reparsed.tree().syntax()), &format!("{:#?}", fully_reparsed.tree().syntax()),
&format!("{:#?}", incrementally_reparsed.tree().syntax()), &format!("{:#?}", incrementally_reparsed.tree().syntax()),
); );
assert_eq!(fully_reparsed.errors(), incrementally_reparsed.errors());
} }
#[test] // FIXME: some test here actually test token reparsing #[test] // FIXME: some test here actually test token reparsing
@ -409,4 +414,42 @@ enum Foo {
4, 4,
); );
} }
#[test]
fn reparse_str_token_with_error_unchanged() {
do_check(r#""<|>Unclosed<|> string literal"#, "Still unclosed", 24);
}
#[test]
fn reparse_str_token_with_error_fixed() {
do_check(r#""unterinated<|><|>"#, "\"", 12);
}
#[test]
fn reparse_block_with_error_in_middle_unchanged() {
do_check(
r#"fn main() {
if {}
32 + 4<|><|>
return
if {}
}"#,
"23",
105,
)
}
#[test]
fn reparse_block_with_error_in_middle_fixed() {
do_check(
r#"fn main() {
if {}
32 + 4<|><|>
return
if {}
}"#,
";",
105,
)
}
} }