From 0b0865ab226d57c88e22b6b395d033f68f2c11af Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 14 Jul 2020 14:01:54 +0200 Subject: Generaize annotation extraction --- crates/test_utils/src/lib.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index e4aa894ac..4c89ed87b 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -180,7 +180,7 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { let mut prev_line_start: Option = None; let mut line_start: TextSize = 0.into(); for line in lines_with_ends(text) { - if let Some(idx) = line.find("//^") { + if let Some(idx) = line.find("//") { let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]); for (line_range, text) in extract_line_annotations(&line[idx + "//".len()..]) { res.push((line_range + offset, text)) @@ -195,7 +195,15 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { fn extract_line_annotations(mut line: &str) -> Vec<(TextRange, String)> { let mut res = Vec::new(); let mut offset: TextSize = 0.into(); - while !line.is_empty() { + loop { + match line.find('^') { + Some(idx) => { + offset += TextSize::try_from(idx).unwrap(); + line = &line[idx..]; + } + None => break, + }; + let len = line.chars().take_while(|&it| it == '^').count(); assert!(len > 0); let range = TextRange::at(offset, len.try_into().unwrap()); -- cgit v1.2.3 From abeb003df47de4a1b7aa36a7c4d7987d8cf40ace Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 14 Jul 2020 14:57:33 +0200 Subject: Allow multiline annotations --- crates/ra_hir_ty/src/diagnostics.rs | 3 +- crates/ra_hir_ty/src/diagnostics/match_check.rs | 2 + crates/test_utils/src/lib.rs | 67 +++++++++++++++++++++---- 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 3016ca3bd..3870c6d9c 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs @@ -261,8 +261,7 @@ fn check_diagnostics(ra_fixture: &str) { // FXIME: macros... let file_id = d.source().file_id.original_file(&db); let range = d.syntax_node(&db).text_range(); - // FIXME: support multi-line messages in annotations - let message = d.message().lines().next().unwrap().to_owned(); + let message = d.message().to_owned(); actual.entry(file_id).or_default().push((range, message)); }); actual.values_mut().for_each(|diags| diags.sort_by_key(|it| it.0.start())); diff --git a/crates/ra_hir_ty/src/diagnostics/match_check.rs b/crates/ra_hir_ty/src/diagnostics/match_check.rs index ba48b51b5..95f272811 100644 --- a/crates/ra_hir_ty/src/diagnostics/match_check.rs +++ b/crates/ra_hir_ty/src/diagnostics/match_check.rs @@ -1162,12 +1162,14 @@ fn main() { match a { Either::A { } => (), //^^^ Missing structure fields: + // | - foo Either::B => (), } match a { //^ Missing match arm Either::A { } => (), } //^^^ Missing structure fields: + // | - foo match a { Either::A { foo: true } => (), diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 4c89ed87b..ad586c882 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -179,24 +179,51 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { let mut res = Vec::new(); let mut prev_line_start: Option = None; let mut line_start: TextSize = 0.into(); + let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); for line in lines_with_ends(text) { + let mut this_line_annotations = Vec::new(); if let Some(idx) = line.find("//") { - let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]); - for (line_range, text) in extract_line_annotations(&line[idx + "//".len()..]) { - res.push((line_range + offset, text)) + let annotation_offset = TextSize::of(&line[..idx + "//".len()]); + for annotation in extract_line_annotations(&line[idx + "//".len()..]) { + match annotation { + LineAnnotation::Annotation { mut range, content } => { + range += annotation_offset; + this_line_annotations.push((range.end(), res.len())); + res.push((range + prev_line_start.unwrap(), content)) + } + LineAnnotation::Continuation { mut offset, content } => { + offset += annotation_offset; + let &(_, idx) = prev_line_annotations + .iter() + .find(|&&(off, _idx)| off == offset) + .unwrap(); + res[idx].1.push('\n'); + res[idx].1.push_str(&content); + res[idx].1.push('\n'); + } + } } } + prev_line_start = Some(line_start); line_start += TextSize::of(line); + + prev_line_annotations = this_line_annotations; } res } -fn extract_line_annotations(mut line: &str) -> Vec<(TextRange, String)> { +enum LineAnnotation { + Annotation { range: TextRange, content: String }, + Continuation { offset: TextSize, content: String }, +} + +fn extract_line_annotations(mut line: &str) -> Vec { let mut res = Vec::new(); let mut offset: TextSize = 0.into(); + let marker: fn(char) -> bool = if line.contains('^') { |c| c == '^' } else { |c| c == '|' }; loop { - match line.find('^') { + match line.find(marker) { Some(idx) => { offset += TextSize::try_from(idx).unwrap(); line = &line[idx..]; @@ -204,14 +231,28 @@ fn extract_line_annotations(mut line: &str) -> Vec<(TextRange, String)> { None => break, }; - let len = line.chars().take_while(|&it| it == '^').count(); - assert!(len > 0); + let mut len = line.chars().take_while(|&it| it == '^').count(); + let mut continuation = false; + if len == 0 { + assert!(line.starts_with('|')); + continuation = true; + len = 1; + } let range = TextRange::at(offset, len.try_into().unwrap()); - let next = line[len..].find('^').map_or(line.len(), |it| it + len); - res.push((range, line[len..][..next - len].trim().to_string())); + let next = line[len..].find(marker).map_or(line.len(), |it| it + len); + let content = line[len..][..next - len].trim().to_string(); + + let annotation = if continuation { + LineAnnotation::Continuation { offset: range.end(), content } + } else { + LineAnnotation::Annotation { range, content } + }; + res.push(annotation); + line = &line[next..]; offset += TextSize::try_from(next).unwrap(); } + res } @@ -223,14 +264,18 @@ fn main() { let (x, y) = (9, 2); //^ def ^ def zoo + 1 -} //^^^ i32 +} //^^^ type: + // | i32 "#, ); let res = extract_annotations(&text) .into_iter() .map(|(range, ann)| (&text[range], ann)) .collect::>(); - assert_eq!(res, vec![("x", "def".into()), ("y", "def".into()), ("zoo", "i32".into()),]); + assert_eq!( + res, + vec![("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\n".into()),] + ); } // Comparison functionality borrowed from cargo: -- cgit v1.2.3