]> git.lizzy.rs Git - rust.git/commitdiff
Allow multiline annotations
authorAleksey Kladov <aleksey.kladov@gmail.com>
Tue, 14 Jul 2020 12:57:33 +0000 (14:57 +0200)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Tue, 14 Jul 2020 12:58:10 +0000 (14:58 +0200)
crates/ra_hir_ty/src/diagnostics.rs
crates/ra_hir_ty/src/diagnostics/match_check.rs
crates/test_utils/src/lib.rs

index 3016ca3bd5839294392992aa0f75cab3282bdef3..3870c6d9c3f433b5866dea1985b358ab470f3adc 100644 (file)
@@ -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()));
index ba48b51b5ea85538ccc3c6bbb0fccf6666143e85..95f272811fcec06411299cb287e92f2ce0350c68 100644 (file)
@@ -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 } => (),
index 4c89ed87b0038160e3be8df207042c7cbda5cdab..ad586c882bec6c60cf28ea82cc961a286caae5f7 100644 (file)
@@ -179,24 +179,51 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
     let mut res = Vec::new();
     let mut prev_line_start: Option<TextSize> = 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<LineAnnotation> {
     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::<Vec<_>>();
-    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: