diff options
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics/match_check.rs | 2 | ||||
-rw-r--r-- | crates/test_utils/src/lib.rs | 77 |
3 files changed, 68 insertions, 14 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) { | |||
261 | // FXIME: macros... | 261 | // FXIME: macros... |
262 | let file_id = d.source().file_id.original_file(&db); | 262 | let file_id = d.source().file_id.original_file(&db); |
263 | let range = d.syntax_node(&db).text_range(); | 263 | let range = d.syntax_node(&db).text_range(); |
264 | // FIXME: support multi-line messages in annotations | 264 | let message = d.message().to_owned(); |
265 | let message = d.message().lines().next().unwrap().to_owned(); | ||
266 | actual.entry(file_id).or_default().push((range, message)); | 265 | actual.entry(file_id).or_default().push((range, message)); |
267 | }); | 266 | }); |
268 | actual.values_mut().for_each(|diags| diags.sort_by_key(|it| it.0.start())); | 267 | 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() { | |||
1162 | match a { | 1162 | match a { |
1163 | Either::A { } => (), | 1163 | Either::A { } => (), |
1164 | //^^^ Missing structure fields: | 1164 | //^^^ Missing structure fields: |
1165 | // | - foo | ||
1165 | Either::B => (), | 1166 | Either::B => (), |
1166 | } | 1167 | } |
1167 | match a { | 1168 | match a { |
1168 | //^ Missing match arm | 1169 | //^ Missing match arm |
1169 | Either::A { } => (), | 1170 | Either::A { } => (), |
1170 | } //^^^ Missing structure fields: | 1171 | } //^^^ Missing structure fields: |
1172 | // | - foo | ||
1171 | 1173 | ||
1172 | match a { | 1174 | match a { |
1173 | Either::A { foo: true } => (), | 1175 | Either::A { foo: true } => (), |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index e4aa894ac..ad586c882 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -179,31 +179,80 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { | |||
179 | let mut res = Vec::new(); | 179 | let mut res = Vec::new(); |
180 | let mut prev_line_start: Option<TextSize> = None; | 180 | let mut prev_line_start: Option<TextSize> = None; |
181 | let mut line_start: TextSize = 0.into(); | 181 | let mut line_start: TextSize = 0.into(); |
182 | let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); | ||
182 | for line in lines_with_ends(text) { | 183 | for line in lines_with_ends(text) { |
183 | if let Some(idx) = line.find("//^") { | 184 | let mut this_line_annotations = Vec::new(); |
184 | let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]); | 185 | if let Some(idx) = line.find("//") { |
185 | for (line_range, text) in extract_line_annotations(&line[idx + "//".len()..]) { | 186 | let annotation_offset = TextSize::of(&line[..idx + "//".len()]); |
186 | res.push((line_range + offset, text)) | 187 | for annotation in extract_line_annotations(&line[idx + "//".len()..]) { |
188 | match annotation { | ||
189 | LineAnnotation::Annotation { mut range, content } => { | ||
190 | range += annotation_offset; | ||
191 | this_line_annotations.push((range.end(), res.len())); | ||
192 | res.push((range + prev_line_start.unwrap(), content)) | ||
193 | } | ||
194 | LineAnnotation::Continuation { mut offset, content } => { | ||
195 | offset += annotation_offset; | ||
196 | let &(_, idx) = prev_line_annotations | ||
197 | .iter() | ||
198 | .find(|&&(off, _idx)| off == offset) | ||
199 | .unwrap(); | ||
200 | res[idx].1.push('\n'); | ||
201 | res[idx].1.push_str(&content); | ||
202 | res[idx].1.push('\n'); | ||
203 | } | ||
204 | } | ||
187 | } | 205 | } |
188 | } | 206 | } |
207 | |||
189 | prev_line_start = Some(line_start); | 208 | prev_line_start = Some(line_start); |
190 | line_start += TextSize::of(line); | 209 | line_start += TextSize::of(line); |
210 | |||
211 | prev_line_annotations = this_line_annotations; | ||
191 | } | 212 | } |
192 | res | 213 | res |
193 | } | 214 | } |
194 | 215 | ||
195 | fn extract_line_annotations(mut line: &str) -> Vec<(TextRange, String)> { | 216 | enum LineAnnotation { |
217 | Annotation { range: TextRange, content: String }, | ||
218 | Continuation { offset: TextSize, content: String }, | ||
219 | } | ||
220 | |||
221 | fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> { | ||
196 | let mut res = Vec::new(); | 222 | let mut res = Vec::new(); |
197 | let mut offset: TextSize = 0.into(); | 223 | let mut offset: TextSize = 0.into(); |
198 | while !line.is_empty() { | 224 | let marker: fn(char) -> bool = if line.contains('^') { |c| c == '^' } else { |c| c == '|' }; |
199 | let len = line.chars().take_while(|&it| it == '^').count(); | 225 | loop { |
200 | assert!(len > 0); | 226 | match line.find(marker) { |
227 | Some(idx) => { | ||
228 | offset += TextSize::try_from(idx).unwrap(); | ||
229 | line = &line[idx..]; | ||
230 | } | ||
231 | None => break, | ||
232 | }; | ||
233 | |||
234 | let mut len = line.chars().take_while(|&it| it == '^').count(); | ||
235 | let mut continuation = false; | ||
236 | if len == 0 { | ||
237 | assert!(line.starts_with('|')); | ||
238 | continuation = true; | ||
239 | len = 1; | ||
240 | } | ||
201 | let range = TextRange::at(offset, len.try_into().unwrap()); | 241 | let range = TextRange::at(offset, len.try_into().unwrap()); |
202 | let next = line[len..].find('^').map_or(line.len(), |it| it + len); | 242 | let next = line[len..].find(marker).map_or(line.len(), |it| it + len); |
203 | res.push((range, line[len..][..next - len].trim().to_string())); | 243 | let content = line[len..][..next - len].trim().to_string(); |
244 | |||
245 | let annotation = if continuation { | ||
246 | LineAnnotation::Continuation { offset: range.end(), content } | ||
247 | } else { | ||
248 | LineAnnotation::Annotation { range, content } | ||
249 | }; | ||
250 | res.push(annotation); | ||
251 | |||
204 | line = &line[next..]; | 252 | line = &line[next..]; |
205 | offset += TextSize::try_from(next).unwrap(); | 253 | offset += TextSize::try_from(next).unwrap(); |
206 | } | 254 | } |
255 | |||
207 | res | 256 | res |
208 | } | 257 | } |
209 | 258 | ||
@@ -215,14 +264,18 @@ fn main() { | |||
215 | let (x, y) = (9, 2); | 264 | let (x, y) = (9, 2); |
216 | //^ def ^ def | 265 | //^ def ^ def |
217 | zoo + 1 | 266 | zoo + 1 |
218 | } //^^^ i32 | 267 | } //^^^ type: |
268 | // | i32 | ||
219 | "#, | 269 | "#, |
220 | ); | 270 | ); |
221 | let res = extract_annotations(&text) | 271 | let res = extract_annotations(&text) |
222 | .into_iter() | 272 | .into_iter() |
223 | .map(|(range, ann)| (&text[range], ann)) | 273 | .map(|(range, ann)| (&text[range], ann)) |
224 | .collect::<Vec<_>>(); | 274 | .collect::<Vec<_>>(); |
225 | assert_eq!(res, vec![("x", "def".into()), ("y", "def".into()), ("zoo", "i32".into()),]); | 275 | assert_eq!( |
276 | res, | ||
277 | vec![("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\n".into()),] | ||
278 | ); | ||
226 | } | 279 | } |
227 | 280 | ||
228 | // Comparison functionality borrowed from cargo: | 281 | // Comparison functionality borrowed from cargo: |