Skip to content

Commit 98e8ad5

Browse files
committed
Handle diagnostics with multiple primary spans
1 parent 637c795 commit 98e8ad5

11 files changed

+554
-527
lines changed

crates/ra_cargo_watch/src/conv.rs

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,13 @@ pub(crate) struct MappedRustDiagnostic {
180180
pub(crate) fn map_rust_diagnostic_to_lsp(
181181
rd: &RustDiagnostic,
182182
workspace_root: &PathBuf,
183-
) -> Option<MappedRustDiagnostic> {
184-
let primary_span = rd.spans.iter().find(|s| s.is_primary)?;
185-
186-
let location = map_span_to_location(&primary_span, workspace_root);
183+
) -> Vec<MappedRustDiagnostic> {
184+
let primary_spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect();
185+
if primary_spans.is_empty() {
186+
return vec![];
187+
}
187188

188189
let severity = map_level_to_severity(rd.level);
189-
let mut primary_span_label = primary_span.label.as_ref();
190190

191191
let mut source = String::from("rustc");
192192
let mut code = rd.code.as_ref().map(|c| c.code.clone());
@@ -199,19 +199,10 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
199199
}
200200
}
201201

202+
let mut needs_primary_span_label = true;
202203
let mut related_information = vec![];
203204
let mut tags = vec![];
204205

205-
// If error occurs from macro expansion, add related info pointing to
206-
// where the error originated
207-
if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() {
208-
let def_loc = map_span_to_location_naive(&primary_span, workspace_root);
209-
related_information.push(DiagnosticRelatedInformation {
210-
location: def_loc,
211-
message: "Error originated from macro here".to_string(),
212-
});
213-
}
214-
215206
for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) {
216207
let related = map_secondary_span_to_related(secondary_span, workspace_root);
217208
if let Some(related) = related {
@@ -231,15 +222,11 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
231222

232223
// These secondary messages usually duplicate the content of the
233224
// primary span label.
234-
primary_span_label = None;
225+
needs_primary_span_label = false;
235226
}
236227
}
237228
}
238229

239-
if let Some(primary_span_label) = primary_span_label {
240-
write!(&mut message, "\n{}", primary_span_label).unwrap();
241-
}
242-
243230
if is_unused_or_unnecessary(rd) {
244231
tags.push(DiagnosticTag::Unnecessary);
245232
}
@@ -248,21 +235,45 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
248235
tags.push(DiagnosticTag::Deprecated);
249236
}
250237

251-
let diagnostic = Diagnostic {
252-
range: location.range,
253-
severity,
254-
code: code.map(NumberOrString::String),
255-
source: Some(source),
256-
message,
257-
related_information: if !related_information.is_empty() {
258-
Some(related_information)
259-
} else {
260-
None
261-
},
262-
tags: if !tags.is_empty() { Some(tags) } else { None },
263-
};
264-
265-
Some(MappedRustDiagnostic { location, diagnostic, fixes })
238+
primary_spans
239+
.iter()
240+
.map(|primary_span| {
241+
let location = map_span_to_location(&primary_span, workspace_root);
242+
243+
let mut message = message.clone();
244+
if needs_primary_span_label {
245+
if let Some(primary_span_label) = &primary_span.label {
246+
write!(&mut message, "\n{}", primary_span_label).unwrap();
247+
}
248+
}
249+
250+
// If error occurs from macro expansion, add related info pointing to
251+
// where the error originated
252+
if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() {
253+
let def_loc = map_span_to_location_naive(&primary_span, workspace_root);
254+
related_information.push(DiagnosticRelatedInformation {
255+
location: def_loc,
256+
message: "Error originated from macro here".to_string(),
257+
});
258+
}
259+
260+
let diagnostic = Diagnostic {
261+
range: location.range,
262+
severity,
263+
code: code.clone().map(NumberOrString::String),
264+
source: Some(source.clone()),
265+
message,
266+
related_information: if !related_information.is_empty() {
267+
Some(related_information.clone())
268+
} else {
269+
None
270+
},
271+
tags: if !tags.is_empty() { Some(tags.clone()) } else { None },
272+
};
273+
274+
MappedRustDiagnostic { location, diagnostic, fixes: fixes.clone() }
275+
})
276+
.collect()
266277
}
267278

268279
/// Returns a `Url` object from a given path, will lowercase drive letters if present.

crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap

Lines changed: 87 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -2,98 +2,100 @@
22
source: crates/ra_cargo_watch/src/conv/test.rs
33
expression: diag
44
---
5-
MappedRustDiagnostic {
6-
location: Location {
7-
uri: "file:///test/compiler/mir/tagset.rs",
8-
range: Range {
9-
start: Position {
10-
line: 41,
11-
character: 23,
12-
},
13-
end: Position {
14-
line: 41,
15-
character: 28,
5+
[
6+
MappedRustDiagnostic {
7+
location: Location {
8+
uri: "file:///test/compiler/mir/tagset.rs",
9+
range: Range {
10+
start: Position {
11+
line: 41,
12+
character: 23,
13+
},
14+
end: Position {
15+
line: 41,
16+
character: 28,
17+
},
1618
},
1719
},
18-
},
19-
diagnostic: Diagnostic {
20-
range: Range {
21-
start: Position {
22-
line: 41,
23-
character: 23,
24-
},
25-
end: Position {
26-
line: 41,
27-
character: 28,
20+
diagnostic: Diagnostic {
21+
range: Range {
22+
start: Position {
23+
line: 41,
24+
character: 23,
25+
},
26+
end: Position {
27+
line: 41,
28+
character: 28,
29+
},
2830
},
29-
},
30-
severity: Some(
31-
Warning,
32-
),
33-
code: Some(
34-
String(
35-
"trivially_copy_pass_by_ref",
31+
severity: Some(
32+
Warning,
3633
),
37-
),
38-
source: Some(
39-
"clippy",
40-
),
41-
message: "this argument is passed by reference, but would be more efficient if passed by value\n#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\nfor further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref",
42-
related_information: Some(
43-
[
44-
DiagnosticRelatedInformation {
45-
location: Location {
46-
uri: "file:///test/compiler/lib.rs",
47-
range: Range {
48-
start: Position {
49-
line: 0,
50-
character: 8,
51-
},
52-
end: Position {
53-
line: 0,
54-
character: 19,
34+
code: Some(
35+
String(
36+
"trivially_copy_pass_by_ref",
37+
),
38+
),
39+
source: Some(
40+
"clippy",
41+
),
42+
message: "this argument is passed by reference, but would be more efficient if passed by value\n#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\nfor further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref",
43+
related_information: Some(
44+
[
45+
DiagnosticRelatedInformation {
46+
location: Location {
47+
uri: "file:///test/compiler/lib.rs",
48+
range: Range {
49+
start: Position {
50+
line: 0,
51+
character: 8,
52+
},
53+
end: Position {
54+
line: 0,
55+
character: 19,
56+
},
5557
},
5658
},
59+
message: "lint level defined here",
5760
},
58-
message: "lint level defined here",
59-
},
60-
],
61-
),
62-
tags: None,
63-
},
64-
fixes: [
65-
CodeAction {
66-
title: "consider passing by value instead",
67-
kind: Some(
68-
"quickfix",
61+
],
6962
),
70-
diagnostics: None,
71-
edit: Some(
72-
WorkspaceEdit {
73-
changes: Some(
74-
{
75-
"file:///test/compiler/mir/tagset.rs": [
76-
TextEdit {
77-
range: Range {
78-
start: Position {
79-
line: 41,
80-
character: 23,
81-
},
82-
end: Position {
83-
line: 41,
84-
character: 28,
63+
tags: None,
64+
},
65+
fixes: [
66+
CodeAction {
67+
title: "consider passing by value instead",
68+
kind: Some(
69+
"quickfix",
70+
),
71+
diagnostics: None,
72+
edit: Some(
73+
WorkspaceEdit {
74+
changes: Some(
75+
{
76+
"file:///test/compiler/mir/tagset.rs": [
77+
TextEdit {
78+
range: Range {
79+
start: Position {
80+
line: 41,
81+
character: 23,
82+
},
83+
end: Position {
84+
line: 41,
85+
character: 28,
86+
},
8587
},
88+
new_text: "self",
8689
},
87-
new_text: "self",
88-
},
89-
],
90-
},
91-
),
92-
document_changes: None,
93-
},
94-
),
95-
command: None,
96-
is_preferred: None,
97-
},
98-
],
99-
}
90+
],
91+
},
92+
),
93+
document_changes: None,
94+
},
95+
),
96+
command: None,
97+
is_preferred: None,
98+
},
99+
],
100+
},
101+
]

crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,47 @@
22
source: crates/ra_cargo_watch/src/conv/test.rs
33
expression: diag
44
---
5-
MappedRustDiagnostic {
6-
location: Location {
7-
uri: "file:///test/src/main.rs",
8-
range: Range {
9-
start: Position {
10-
line: 1,
11-
character: 4,
12-
},
13-
end: Position {
14-
line: 1,
15-
character: 26,
5+
[
6+
MappedRustDiagnostic {
7+
location: Location {
8+
uri: "file:///test/src/main.rs",
9+
range: Range {
10+
start: Position {
11+
line: 1,
12+
character: 4,
13+
},
14+
end: Position {
15+
line: 1,
16+
character: 26,
17+
},
1618
},
1719
},
18-
},
19-
diagnostic: Diagnostic {
20-
range: Range {
21-
start: Position {
22-
line: 1,
23-
character: 4,
20+
diagnostic: Diagnostic {
21+
range: Range {
22+
start: Position {
23+
line: 1,
24+
character: 4,
25+
},
26+
end: Position {
27+
line: 1,
28+
character: 26,
29+
},
2430
},
25-
end: Position {
26-
line: 1,
27-
character: 26,
28-
},
29-
},
30-
severity: Some(
31-
Error,
32-
),
33-
code: Some(
34-
String(
35-
"E0277",
31+
severity: Some(
32+
Error,
3633
),
37-
),
38-
source: Some(
39-
"rustc",
40-
),
41-
message: "can\'t compare `{integer}` with `&str`\nthe trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`",
42-
related_information: None,
43-
tags: None,
34+
code: Some(
35+
String(
36+
"E0277",
37+
),
38+
),
39+
source: Some(
40+
"rustc",
41+
),
42+
message: "can\'t compare `{integer}` with `&str`\nthe trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`",
43+
related_information: None,
44+
tags: None,
45+
},
46+
fixes: [],
4447
},
45-
fixes: [],
46-
}
48+
]

0 commit comments

Comments
 (0)