aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-03-12 14:46:42 +0000
committerGitHub <[email protected]>2020-03-12 14:46:42 +0000
commit7bbdca6182ca6ab562fe7644015b30b171c5748e (patch)
tree07104eb5418d633e4ec14251596dbeb9b0a15b91 /crates
parentafd64ef4f75844ff61bc5967406f40ec90047348 (diff)
parent98e8ad5e608b739d1d28a43c8c69358e77c1c1f0 (diff)
Merge #3564
3564: Better handling of a few kinds of cargo/clippy diagnostics r=matklad a=kiljacken This was initially supposed to just be a fix for #3433, but I caught a few things that ended up being useful as well. This PR primarily makes us handle multi-edit fix suggestions properly. Instead of just applying the first fix we apply all the parts of the fix in a single action. Second up, this PR handles diagnostics with multiple primary spans, f.x. the unused import diagnostic from rustc: ![image](https://user-images.githubusercontent.com/209321/76531793-03269480-6476-11ea-9180-41c0ea705553.png) The LSP doesn't handle this too well, as it only support a single complete range for each diagnostic, so we get duplicate messages in the problem panel of VSCode: ![image](https://user-images.githubusercontent.com/209321/76531901-29e4cb00-6476-11ea-9746-cd57f8974b85.png) However, I feel like the improved visual aspect in-editor outweighs the duplication in the problem panel. I'm open to not including the second commit if anybody really doesn't like the idea of duplicate diagnostics in the problem pane. Fixes #3433 Fixes #3257 Co-authored-by: Emil Lauridsen <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_cargo_watch/src/conv.rs128
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap172
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap76
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap102
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_multi_line_fix.snap114
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap76
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap76
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap148
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap108
-rw-r--r--crates/ra_cargo_watch/src/conv/test.rs148
-rw-r--r--crates/ra_cargo_watch/src/lib.rs32
11 files changed, 722 insertions, 458 deletions
diff --git a/crates/ra_cargo_watch/src/conv.rs b/crates/ra_cargo_watch/src/conv.rs
index 0246adfb5..c6f8ca329 100644
--- a/crates/ra_cargo_watch/src/conv.rs
+++ b/crates/ra_cargo_watch/src/conv.rs
@@ -8,6 +8,7 @@ use lsp_types::{
8 Location, NumberOrString, Position, Range, TextEdit, Url, WorkspaceEdit, 8 Location, NumberOrString, Position, Range, TextEdit, Url, WorkspaceEdit,
9}; 9};
10use std::{ 10use std::{
11 collections::HashMap,
11 fmt::Write, 12 fmt::Write,
12 path::{Component, Path, PathBuf, Prefix}, 13 path::{Component, Path, PathBuf, Prefix},
13 str::FromStr, 14 str::FromStr,
@@ -126,44 +127,34 @@ fn map_rust_child_diagnostic(
126 rd: &RustDiagnostic, 127 rd: &RustDiagnostic,
127 workspace_root: &PathBuf, 128 workspace_root: &PathBuf,
128) -> MappedRustChildDiagnostic { 129) -> MappedRustChildDiagnostic {
129 let span: &DiagnosticSpan = match rd.spans.iter().find(|s| s.is_primary) { 130 let spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect();
130 Some(span) => span, 131 if spans.is_empty() {
131 None => { 132 // `rustc` uses these spanless children as a way to print multi-line
132 // `rustc` uses these spanless children as a way to print multi-line 133 // messages
133 // messages 134 return MappedRustChildDiagnostic::MessageLine(rd.message.clone());
134 return MappedRustChildDiagnostic::MessageLine(rd.message.clone()); 135 }
136
137 let mut edit_map: HashMap<Url, Vec<TextEdit>> = HashMap::new();
138 for &span in &spans {
139 if let Some(suggested_replacement) = &span.suggested_replacement {
140 let location = map_span_to_location(span, workspace_root);
141 let edit = TextEdit::new(location.range, suggested_replacement.clone());
142 edit_map.entry(location.uri).or_default().push(edit);
135 } 143 }
136 }; 144 }
137
138 // If we have a primary span use its location, otherwise use the parent
139 let location = map_span_to_location(&span, workspace_root);
140
141 if let Some(suggested_replacement) = &span.suggested_replacement {
142 // Include our replacement in the title unless it's empty
143 let title = if !suggested_replacement.is_empty() {
144 format!("{}: '{}'", rd.message, suggested_replacement)
145 } else {
146 rd.message.clone()
147 };
148
149 let edit = {
150 let edits = vec![TextEdit::new(location.range, suggested_replacement.clone())];
151 let mut edit_map = std::collections::HashMap::new();
152 edit_map.insert(location.uri, edits);
153 WorkspaceEdit::new(edit_map)
154 };
155 145
146 if !edit_map.is_empty() {
156 MappedRustChildDiagnostic::SuggestedFix(CodeAction { 147 MappedRustChildDiagnostic::SuggestedFix(CodeAction {
157 title, 148 title: rd.message.clone(),
158 kind: Some("quickfix".to_string()), 149 kind: Some("quickfix".to_string()),
159 diagnostics: None, 150 diagnostics: None,
160 edit: Some(edit), 151 edit: Some(WorkspaceEdit::new(edit_map)),
161 command: None, 152 command: None,
162 is_preferred: None, 153 is_preferred: None,
163 }) 154 })
164 } else { 155 } else {
165 MappedRustChildDiagnostic::Related(DiagnosticRelatedInformation { 156 MappedRustChildDiagnostic::Related(DiagnosticRelatedInformation {
166 location, 157 location: map_span_to_location(spans[0], workspace_root),
167 message: rd.message.clone(), 158 message: rd.message.clone(),
168 }) 159 })
169 } 160 }
@@ -189,13 +180,13 @@ pub(crate) struct MappedRustDiagnostic {
189pub(crate) fn map_rust_diagnostic_to_lsp( 180pub(crate) fn map_rust_diagnostic_to_lsp(
190 rd: &RustDiagnostic, 181 rd: &RustDiagnostic,
191 workspace_root: &PathBuf, 182 workspace_root: &PathBuf,
192) -> Option<MappedRustDiagnostic> { 183) -> Vec<MappedRustDiagnostic> {
193 let primary_span = rd.spans.iter().find(|s| s.is_primary)?; 184 let primary_spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect();
194 185 if primary_spans.is_empty() {
195 let location = map_span_to_location(&primary_span, workspace_root); 186 return vec![];
187 }
196 188
197 let severity = map_level_to_severity(rd.level); 189 let severity = map_level_to_severity(rd.level);
198 let mut primary_span_label = primary_span.label.as_ref();
199 190
200 let mut source = String::from("rustc"); 191 let mut source = String::from("rustc");
201 let mut code = rd.code.as_ref().map(|c| c.code.clone()); 192 let mut code = rd.code.as_ref().map(|c| c.code.clone());
@@ -208,19 +199,10 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
208 } 199 }
209 } 200 }
210 201
202 let mut needs_primary_span_label = true;
211 let mut related_information = vec![]; 203 let mut related_information = vec![];
212 let mut tags = vec![]; 204 let mut tags = vec![];
213 205
214 // If error occurs from macro expansion, add related info pointing to
215 // where the error originated
216 if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() {
217 let def_loc = map_span_to_location_naive(&primary_span, workspace_root);
218 related_information.push(DiagnosticRelatedInformation {
219 location: def_loc,
220 message: "Error originated from macro here".to_string(),
221 });
222 }
223
224 for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) { 206 for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) {
225 let related = map_secondary_span_to_related(secondary_span, workspace_root); 207 let related = map_secondary_span_to_related(secondary_span, workspace_root);
226 if let Some(related) = related { 208 if let Some(related) = related {
@@ -240,15 +222,11 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
240 222
241 // These secondary messages usually duplicate the content of the 223 // These secondary messages usually duplicate the content of the
242 // primary span label. 224 // primary span label.
243 primary_span_label = None; 225 needs_primary_span_label = false;
244 } 226 }
245 } 227 }
246 } 228 }
247 229
248 if let Some(primary_span_label) = primary_span_label {
249 write!(&mut message, "\n{}", primary_span_label).unwrap();
250 }
251
252 if is_unused_or_unnecessary(rd) { 230 if is_unused_or_unnecessary(rd) {
253 tags.push(DiagnosticTag::Unnecessary); 231 tags.push(DiagnosticTag::Unnecessary);
254 } 232 }
@@ -257,21 +235,45 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
257 tags.push(DiagnosticTag::Deprecated); 235 tags.push(DiagnosticTag::Deprecated);
258 } 236 }
259 237
260 let diagnostic = Diagnostic { 238 primary_spans
261 range: location.range, 239 .iter()
262 severity, 240 .map(|primary_span| {
263 code: code.map(NumberOrString::String), 241 let location = map_span_to_location(&primary_span, workspace_root);
264 source: Some(source), 242
265 message, 243 let mut message = message.clone();
266 related_information: if !related_information.is_empty() { 244 if needs_primary_span_label {
267 Some(related_information) 245 if let Some(primary_span_label) = &primary_span.label {
268 } else { 246 write!(&mut message, "\n{}", primary_span_label).unwrap();
269 None 247 }
270 }, 248 }
271 tags: if !tags.is_empty() { Some(tags) } else { None }, 249
272 }; 250 // If error occurs from macro expansion, add related info pointing to
273 251 // where the error originated
274 Some(MappedRustDiagnostic { location, diagnostic, fixes }) 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()
275} 277}
276 278
277/// Returns a `Url` object from a given path, will lowercase drive letters if present. 279/// Returns a `Url` object from a given path, will lowercase drive letters if present.
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap
index 95ca163dc..9e8f4eff4 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap
@@ -2,98 +2,100 @@
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_cargo_watch/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5MappedRustDiagnostic { 5[
6 location: Location { 6 MappedRustDiagnostic {
7 uri: "file:///test/compiler/mir/tagset.rs", 7 location: Location {
8 range: Range { 8 uri: "file:///test/compiler/mir/tagset.rs",
9 start: Position { 9 range: Range {
10 line: 41, 10 start: Position {
11 character: 23, 11 line: 41,
12 }, 12 character: 23,
13 end: Position { 13 },
14 line: 41, 14 end: Position {
15 character: 28, 15 line: 41,
16 character: 28,
17 },
16 }, 18 },
17 }, 19 },
18 }, 20 diagnostic: Diagnostic {
19 diagnostic: Diagnostic { 21 range: Range {
20 range: Range { 22 start: Position {
21 start: Position { 23 line: 41,
22 line: 41, 24 character: 23,
23 character: 23, 25 },
24 }, 26 end: Position {
25 end: Position { 27 line: 41,
26 line: 41, 28 character: 28,
27 character: 28, 29 },
28 }, 30 },
29 }, 31 severity: Some(
30 severity: Some( 32 Warning,
31 Warning,
32 ),
33 code: Some(
34 String(
35 "trivially_copy_pass_by_ref",
36 ), 33 ),
37 ), 34 code: Some(
38 source: Some( 35 String(
39 "clippy", 36 "trivially_copy_pass_by_ref",
40 ), 37 ),
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", 38 ),
42 related_information: Some( 39 source: Some(
43 [ 40 "clippy",
44 DiagnosticRelatedInformation { 41 ),
45 location: Location { 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",
46 uri: "file:///test/compiler/lib.rs", 43 related_information: Some(
47 range: Range { 44 [
48 start: Position { 45 DiagnosticRelatedInformation {
49 line: 0, 46 location: Location {
50 character: 8, 47 uri: "file:///test/compiler/lib.rs",
51 }, 48 range: Range {
52 end: Position { 49 start: Position {
53 line: 0, 50 line: 0,
54 character: 19, 51 character: 8,
52 },
53 end: Position {
54 line: 0,
55 character: 19,
56 },
55 }, 57 },
56 }, 58 },
59 message: "lint level defined here",
57 }, 60 },
58 message: "lint level defined here", 61 ],
59 },
60 ],
61 ),
62 tags: None,
63 },
64 fixes: [
65 CodeAction {
66 title: "consider passing by value instead: \'self\'",
67 kind: Some(
68 "quickfix",
69 ), 62 ),
70 diagnostics: None, 63 tags: None,
71 edit: Some( 64 },
72 WorkspaceEdit { 65 fixes: [
73 changes: Some( 66 CodeAction {
74 { 67 title: "consider passing by value instead",
75 "file:///test/compiler/mir/tagset.rs": [ 68 kind: Some(
76 TextEdit { 69 "quickfix",
77 range: Range { 70 ),
78 start: Position { 71 diagnostics: None,
79 line: 41, 72 edit: Some(
80 character: 23, 73 WorkspaceEdit {
81 }, 74 changes: Some(
82 end: Position { 75 {
83 line: 41, 76 "file:///test/compiler/mir/tagset.rs": [
84 character: 28, 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 },
85 }, 87 },
88 new_text: "self",
86 }, 89 },
87 new_text: "self", 90 ],
88 }, 91 },
89 ], 92 ),
90 }, 93 document_changes: None,
91 ), 94 },
92 document_changes: None, 95 ),
93 }, 96 command: None,
94 ), 97 is_preferred: None,
95 command: None, 98 },
96 is_preferred: None, 99 ],
97 }, 100 },
98 ], 101]
99}
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap
index 12eb32df4..61ae0c9ae 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap
@@ -2,45 +2,47 @@
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_cargo_watch/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5MappedRustDiagnostic { 5[
6 location: Location { 6 MappedRustDiagnostic {
7 uri: "file:///test/src/main.rs", 7 location: Location {
8 range: Range { 8 uri: "file:///test/src/main.rs",
9 start: Position { 9 range: Range {
10 line: 1, 10 start: Position {
11 character: 4, 11 line: 1,
12 }, 12 character: 4,
13 end: Position { 13 },
14 line: 1, 14 end: Position {
15 character: 26, 15 line: 1,
16 character: 26,
17 },
16 }, 18 },
17 }, 19 },
18 }, 20 diagnostic: Diagnostic {
19 diagnostic: Diagnostic { 21 range: Range {
20 range: Range { 22 start: Position {
21 start: Position { 23 line: 1,
22 line: 1, 24 character: 4,
23 character: 4, 25 },
26 end: Position {
27 line: 1,
28 character: 26,
29 },
24 }, 30 },
25 end: Position { 31 severity: Some(
26 line: 1, 32 Error,
27 character: 26,
28 },
29 },
30 severity: Some(
31 Error,
32 ),
33 code: Some(
34 String(
35 "E0277",
36 ), 33 ),
37 ), 34 code: Some(
38 source: Some( 35 String(
39 "rustc", 36 "E0277",
40 ), 37 ),
41 message: "can\'t compare `{integer}` with `&str`\nthe trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`", 38 ),
42 related_information: None, 39 source: Some(
43 tags: None, 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: [],
44 }, 47 },
45 fixes: [], 48]
46}
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap
index 7b83a7cd0..641da1a58 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap
@@ -2,60 +2,62 @@
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_cargo_watch/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5MappedRustDiagnostic { 5[
6 location: Location { 6 MappedRustDiagnostic {
7 uri: "file:///test/crates/ra_hir_def/src/data.rs", 7 location: Location {
8 range: Range { 8 uri: "file:///test/crates/ra_hir_def/src/data.rs",
9 start: Position { 9 range: Range {
10 line: 79, 10 start: Position {
11 character: 15, 11 line: 79,
12 }, 12 character: 15,
13 end: Position { 13 },
14 line: 79, 14 end: Position {
15 character: 41, 15 line: 79,
16 character: 41,
17 },
16 }, 18 },
17 }, 19 },
18 }, 20 diagnostic: Diagnostic {
19 diagnostic: Diagnostic { 21 range: Range {
20 range: Range { 22 start: Position {
21 start: Position { 23 line: 79,
22 line: 79, 24 character: 15,
23 character: 15, 25 },
24 }, 26 end: Position {
25 end: Position { 27 line: 79,
26 line: 79, 28 character: 41,
27 character: 41, 29 },
28 }, 30 },
29 }, 31 severity: Some(
30 severity: Some( 32 Error,
31 Error, 33 ),
32 ), 34 code: None,
33 code: None, 35 source: Some(
34 source: Some( 36 "rustc",
35 "rustc", 37 ),
36 ), 38 message: "Please register your known path in the path module",
37 message: "Please register your known path in the path module", 39 related_information: Some(
38 related_information: Some( 40 [
39 [ 41 DiagnosticRelatedInformation {
40 DiagnosticRelatedInformation { 42 location: Location {
41 location: Location { 43 uri: "file:///test/crates/ra_hir_def/src/path.rs",
42 uri: "file:///test/crates/ra_hir_def/src/path.rs", 44 range: Range {
43 range: Range { 45 start: Position {
44 start: Position { 46 line: 264,
45 line: 264, 47 character: 8,
46 character: 8, 48 },
47 }, 49 end: Position {
48 end: Position { 50 line: 264,
49 line: 264, 51 character: 76,
50 character: 76, 52 },
51 }, 53 },
52 }, 54 },
55 message: "Error originated from macro here",
53 }, 56 },
54 message: "Error originated from macro here", 57 ],
55 }, 58 ),
56 ], 59 tags: None,
57 ), 60 },
58 tags: None, 61 fixes: [],
59 }, 62 },
60 fixes: [], 63]
61}
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_multi_line_fix.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_multi_line_fix.snap
new file mode 100644
index 000000000..0557a2e79
--- /dev/null
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_multi_line_fix.snap
@@ -0,0 +1,114 @@
1---
2source: crates/ra_cargo_watch/src/conv/test.rs
3expression: diag
4---
5[
6 MappedRustDiagnostic {
7 location: Location {
8 uri: "file:///test/src/main.rs",
9 range: Range {
10 start: Position {
11 line: 3,
12 character: 4,
13 },
14 end: Position {
15 line: 3,
16 character: 5,
17 },
18 },
19 },
20 diagnostic: Diagnostic {
21 range: Range {
22 start: Position {
23 line: 3,
24 character: 4,
25 },
26 end: Position {
27 line: 3,
28 character: 5,
29 },
30 },
31 severity: Some(
32 Warning,
33 ),
34 code: Some(
35 String(
36 "let_and_return",
37 ),
38 ),
39 source: Some(
40 "clippy",
41 ),
42 message: "returning the result of a let binding from a block\n`#[warn(clippy::let_and_return)]` on by default\nfor further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return",
43 related_information: Some(
44 [
45 DiagnosticRelatedInformation {
46 location: Location {
47 uri: "file:///test/src/main.rs",
48 range: Range {
49 start: Position {
50 line: 2,
51 character: 4,
52 },
53 end: Position {
54 line: 2,
55 character: 30,
56 },
57 },
58 },
59 message: "unnecessary let binding",
60 },
61 ],
62 ),
63 tags: None,
64 },
65 fixes: [
66 CodeAction {
67 title: "return the expression directly",
68 kind: Some(
69 "quickfix",
70 ),
71 diagnostics: None,
72 edit: Some(
73 WorkspaceEdit {
74 changes: Some(
75 {
76 "file:///test/src/main.rs": [
77 TextEdit {
78 range: Range {
79 start: Position {
80 line: 2,
81 character: 4,
82 },
83 end: Position {
84 line: 2,
85 character: 30,
86 },
87 },
88 new_text: "",
89 },
90 TextEdit {
91 range: Range {
92 start: Position {
93 line: 3,
94 character: 4,
95 },
96 end: Position {
97 line: 3,
98 character: 5,
99 },
100 },
101 new_text: "(0..10).collect()",
102 },
103 ],
104 },
105 ),
106 document_changes: None,
107 },
108 ),
109 command: None,
110 is_preferred: None,
111 },
112 ],
113 },
114]
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap
index 54679c5db..754bc33a4 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap
@@ -2,45 +2,47 @@
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_cargo_watch/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5MappedRustDiagnostic { 5[
6 location: Location { 6 MappedRustDiagnostic {
7 uri: "file:///test/compiler/ty/list_iter.rs", 7 location: Location {
8 range: Range { 8 uri: "file:///test/compiler/ty/list_iter.rs",
9 start: Position { 9 range: Range {
10 line: 51, 10 start: Position {
11 character: 4, 11 line: 51,
12 }, 12 character: 4,
13 end: Position { 13 },
14 line: 51, 14 end: Position {
15 character: 47, 15 line: 51,
16 character: 47,
17 },
16 }, 18 },
17 }, 19 },
18 }, 20 diagnostic: Diagnostic {
19 diagnostic: Diagnostic { 21 range: Range {
20 range: Range { 22 start: Position {
21 start: Position { 23 line: 51,
22 line: 51, 24 character: 4,
23 character: 4, 25 },
26 end: Position {
27 line: 51,
28 character: 47,
29 },
24 }, 30 },
25 end: Position { 31 severity: Some(
26 line: 51, 32 Error,
27 character: 47,
28 },
29 },
30 severity: Some(
31 Error,
32 ),
33 code: Some(
34 String(
35 "E0053",
36 ), 33 ),
37 ), 34 code: Some(
38 source: Some( 35 String(
39 "rustc", 36 "E0053",
40 ), 37 ),
41 message: "method `next` has an incompatible type for trait\nexpected type `fn(&mut ty::list_iter::ListIterator<\'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<\'list, M>) -> std::option::Option<&\'list ty::Ref<M>>`", 38 ),
42 related_information: None, 39 source: Some(
43 tags: None, 40 "rustc",
41 ),
42 message: "method `next` has an incompatible type for trait\nexpected type `fn(&mut ty::list_iter::ListIterator<\'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<\'list, M>) -> std::option::Option<&\'list ty::Ref<M>>`",
43 related_information: None,
44 tags: None,
45 },
46 fixes: [],
44 }, 47 },
45 fixes: [], 48]
46}
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap
index 57df4ceaf..78b7f7cc8 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap
@@ -2,45 +2,47 @@
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_cargo_watch/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5MappedRustDiagnostic { 5[
6 location: Location { 6 MappedRustDiagnostic {
7 uri: "file:///test/runtime/compiler_support.rs", 7 location: Location {
8 range: Range { 8 uri: "file:///test/runtime/compiler_support.rs",
9 start: Position { 9 range: Range {
10 line: 47, 10 start: Position {
11 character: 64, 11 line: 47,
12 }, 12 character: 64,
13 end: Position { 13 },
14 line: 47, 14 end: Position {
15 character: 69, 15 line: 47,
16 character: 69,
17 },
16 }, 18 },
17 }, 19 },
18 }, 20 diagnostic: Diagnostic {
19 diagnostic: Diagnostic { 21 range: Range {
20 range: Range { 22 start: Position {
21 start: Position { 23 line: 47,
22 line: 47, 24 character: 64,
23 character: 64, 25 },
26 end: Position {
27 line: 47,
28 character: 69,
29 },
24 }, 30 },
25 end: Position { 31 severity: Some(
26 line: 47, 32 Error,
27 character: 69,
28 },
29 },
30 severity: Some(
31 Error,
32 ),
33 code: Some(
34 String(
35 "E0308",
36 ), 33 ),
37 ), 34 code: Some(
38 source: Some( 35 String(
39 "rustc", 36 "E0308",
40 ), 37 ),
41 message: "mismatched types\nexpected usize, found u32", 38 ),
42 related_information: None, 39 source: Some(
43 tags: None, 40 "rustc",
41 ),
42 message: "mismatched types\nexpected usize, found u32",
43 related_information: None,
44 tags: None,
45 },
46 fixes: [],
44 }, 47 },
45 fixes: [], 48]
46}
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap
index 3e1fe736c..5989ed202 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap
@@ -2,83 +2,85 @@
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_cargo_watch/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5MappedRustDiagnostic { 5[
6 location: Location { 6 MappedRustDiagnostic {
7 uri: "file:///test/driver/subcommand/repl.rs", 7 location: Location {
8 range: Range { 8 uri: "file:///test/driver/subcommand/repl.rs",
9 start: Position { 9 range: Range {
10 line: 290, 10 start: Position {
11 character: 8, 11 line: 290,
12 }, 12 character: 8,
13 end: Position { 13 },
14 line: 290, 14 end: Position {
15 character: 11, 15 line: 290,
16 character: 11,
17 },
16 }, 18 },
17 }, 19 },
18 }, 20 diagnostic: Diagnostic {
19 diagnostic: Diagnostic { 21 range: Range {
20 range: Range { 22 start: Position {
21 start: Position { 23 line: 290,
22 line: 290, 24 character: 8,
23 character: 8, 25 },
24 }, 26 end: Position {
25 end: Position { 27 line: 290,
26 line: 290, 28 character: 11,
27 character: 11, 29 },
28 }, 30 },
29 }, 31 severity: Some(
30 severity: Some( 32 Warning,
31 Warning,
32 ),
33 code: Some(
34 String(
35 "unused_variables",
36 ), 33 ),
37 ), 34 code: Some(
38 source: Some( 35 String(
39 "rustc", 36 "unused_variables",
40 ), 37 ),
41 message: "unused variable: `foo`\n#[warn(unused_variables)] on by default",
42 related_information: None,
43 tags: Some(
44 [
45 Unnecessary,
46 ],
47 ),
48 },
49 fixes: [
50 CodeAction {
51 title: "consider prefixing with an underscore: \'_foo\'",
52 kind: Some(
53 "quickfix",
54 ), 38 ),
55 diagnostics: None, 39 source: Some(
56 edit: Some( 40 "rustc",
57 WorkspaceEdit { 41 ),
58 changes: Some( 42 message: "unused variable: `foo`\n#[warn(unused_variables)] on by default",
59 { 43 related_information: None,
60 "file:///test/driver/subcommand/repl.rs": [ 44 tags: Some(
61 TextEdit { 45 [
62 range: Range { 46 Unnecessary,
63 start: Position { 47 ],
64 line: 290,
65 character: 8,
66 },
67 end: Position {
68 line: 290,
69 character: 11,
70 },
71 },
72 new_text: "_foo",
73 },
74 ],
75 },
76 ),
77 document_changes: None,
78 },
79 ), 48 ),
80 command: None,
81 is_preferred: None,
82 }, 49 },
83 ], 50 fixes: [
84} 51 CodeAction {
52 title: "consider prefixing with an underscore",
53 kind: Some(
54 "quickfix",
55 ),
56 diagnostics: None,
57 edit: Some(
58 WorkspaceEdit {
59 changes: Some(
60 {
61 "file:///test/driver/subcommand/repl.rs": [
62 TextEdit {
63 range: Range {
64 start: Position {
65 line: 290,
66 character: 8,
67 },
68 end: Position {
69 line: 290,
70 character: 11,
71 },
72 },
73 new_text: "_foo",
74 },
75 ],
76 },
77 ),
78 document_changes: None,
79 },
80 ),
81 command: None,
82 is_preferred: None,
83 },
84 ],
85 },
86]
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap
index 69301078d..e34b546dc 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap
@@ -2,64 +2,66 @@
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_cargo_watch/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5MappedRustDiagnostic { 5[
6 location: Location { 6 MappedRustDiagnostic {
7 uri: "file:///test/compiler/ty/select.rs", 7 location: Location {
8 range: Range { 8 uri: "file:///test/compiler/ty/select.rs",
9 start: Position { 9 range: Range {
10 line: 103, 10 start: Position {
11 character: 17, 11 line: 103,
12 }, 12 character: 17,
13 end: Position { 13 },
14 line: 103, 14 end: Position {
15 character: 29, 15 line: 103,
16 character: 29,
17 },
16 }, 18 },
17 }, 19 },
18 }, 20 diagnostic: Diagnostic {
19 diagnostic: Diagnostic { 21 range: Range {
20 range: Range { 22 start: Position {
21 start: Position { 23 line: 103,
22 line: 103, 24 character: 17,
23 character: 17, 25 },
24 }, 26 end: Position {
25 end: Position { 27 line: 103,
26 line: 103, 28 character: 29,
27 character: 29, 29 },
28 }, 30 },
29 }, 31 severity: Some(
30 severity: Some( 32 Error,
31 Error,
32 ),
33 code: Some(
34 String(
35 "E0061",
36 ), 33 ),
37 ), 34 code: Some(
38 source: Some( 35 String(
39 "rustc", 36 "E0061",
40 ), 37 ),
41 message: "this function takes 2 parameters but 3 parameters were supplied\nexpected 2 parameters", 38 ),
42 related_information: Some( 39 source: Some(
43 [ 40 "rustc",
44 DiagnosticRelatedInformation { 41 ),
45 location: Location { 42 message: "this function takes 2 parameters but 3 parameters were supplied\nexpected 2 parameters",
46 uri: "file:///test/compiler/ty/select.rs", 43 related_information: Some(
47 range: Range { 44 [
48 start: Position { 45 DiagnosticRelatedInformation {
49 line: 218, 46 location: Location {
50 character: 4, 47 uri: "file:///test/compiler/ty/select.rs",
51 }, 48 range: Range {
52 end: Position { 49 start: Position {
53 line: 230, 50 line: 218,
54 character: 5, 51 character: 4,
52 },
53 end: Position {
54 line: 230,
55 character: 5,
56 },
55 }, 57 },
56 }, 58 },
59 message: "defined here",
57 }, 60 },
58 message: "defined here", 61 ],
59 }, 62 ),
60 ], 63 tags: None,
61 ), 64 },
62 tags: None, 65 fixes: [],
63 }, 66 },
64 fixes: [], 67]
65}
diff --git a/crates/ra_cargo_watch/src/conv/test.rs b/crates/ra_cargo_watch/src/conv/test.rs
index 6b86525b8..4e81455ca 100644
--- a/crates/ra_cargo_watch/src/conv/test.rs
+++ b/crates/ra_cargo_watch/src/conv/test.rs
@@ -58,7 +58,7 @@ fn snap_rustc_incompatible_type_for_trait() {
58 ); 58 );
59 59
60 let workspace_root = PathBuf::from("/test/"); 60 let workspace_root = PathBuf::from("/test/");
61 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); 61 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root);
62 insta::assert_debug_snapshot!(diag); 62 insta::assert_debug_snapshot!(diag);
63} 63}
64 64
@@ -141,7 +141,7 @@ fn snap_rustc_unused_variable() {
141 ); 141 );
142 142
143 let workspace_root = PathBuf::from("/test/"); 143 let workspace_root = PathBuf::from("/test/");
144 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); 144 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root);
145 insta::assert_debug_snapshot!(diag); 145 insta::assert_debug_snapshot!(diag);
146} 146}
147 147
@@ -266,7 +266,7 @@ fn snap_rustc_wrong_number_of_parameters() {
266 ); 266 );
267 267
268 let workspace_root = PathBuf::from("/test/"); 268 let workspace_root = PathBuf::from("/test/");
269 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); 269 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root);
270 insta::assert_debug_snapshot!(diag); 270 insta::assert_debug_snapshot!(diag);
271} 271}
272 272
@@ -387,7 +387,7 @@ fn snap_clippy_pass_by_ref() {
387 ); 387 );
388 388
389 let workspace_root = PathBuf::from("/test/"); 389 let workspace_root = PathBuf::from("/test/");
390 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); 390 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root);
391 insta::assert_debug_snapshot!(diag); 391 insta::assert_debug_snapshot!(diag);
392} 392}
393 393
@@ -431,7 +431,7 @@ fn snap_rustc_mismatched_type() {
431 ); 431 );
432 432
433 let workspace_root = PathBuf::from("/test/"); 433 let workspace_root = PathBuf::from("/test/");
434 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); 434 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root);
435 insta::assert_debug_snapshot!(diag); 435 insta::assert_debug_snapshot!(diag);
436} 436}
437 437
@@ -703,7 +703,7 @@ fn snap_handles_macro_location() {
703 ); 703 );
704 704
705 let workspace_root = PathBuf::from("/test/"); 705 let workspace_root = PathBuf::from("/test/");
706 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); 706 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root);
707 insta::assert_debug_snapshot!(diag); 707 insta::assert_debug_snapshot!(diag);
708} 708}
709 709
@@ -933,6 +933,140 @@ fn snap_macro_compiler_error() {
933 ); 933 );
934 934
935 let workspace_root = PathBuf::from("/test/"); 935 let workspace_root = PathBuf::from("/test/");
936 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); 936 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root);
937 insta::assert_debug_snapshot!(diag);
938}
939
940#[test]
941#[cfg(not(windows))]
942fn snap_multi_line_fix() {
943 let diag = parse_diagnostic(
944 r##"{
945 "rendered": "warning: returning the result of a let binding from a block\n --> src/main.rs:4:5\n |\n3 | let a = (0..10).collect();\n | -------------------------- unnecessary let binding\n4 | a\n | ^\n |\n = note: `#[warn(clippy::let_and_return)]` on by default\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return\nhelp: return the expression directly\n |\n3 | \n4 | (0..10).collect()\n |\n\n",
946 "children": [
947 {
948 "children": [],
949 "code": null,
950 "level": "note",
951 "message": "`#[warn(clippy::let_and_return)]` on by default",
952 "rendered": null,
953 "spans": []
954 },
955 {
956 "children": [],
957 "code": null,
958 "level": "help",
959 "message": "for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return",
960 "rendered": null,
961 "spans": []
962 },
963 {
964 "children": [],
965 "code": null,
966 "level": "help",
967 "message": "return the expression directly",
968 "rendered": null,
969 "spans": [
970 {
971 "byte_end": 55,
972 "byte_start": 29,
973 "column_end": 31,
974 "column_start": 5,
975 "expansion": null,
976 "file_name": "src/main.rs",
977 "is_primary": true,
978 "label": null,
979 "line_end": 3,
980 "line_start": 3,
981 "suggested_replacement": "",
982 "suggestion_applicability": "MachineApplicable",
983 "text": [
984 {
985 "highlight_end": 31,
986 "highlight_start": 5,
987 "text": " let a = (0..10).collect();"
988 }
989 ]
990 },
991 {
992 "byte_end": 61,
993 "byte_start": 60,
994 "column_end": 6,
995 "column_start": 5,
996 "expansion": null,
997 "file_name": "src/main.rs",
998 "is_primary": true,
999 "label": null,
1000 "line_end": 4,
1001 "line_start": 4,
1002 "suggested_replacement": "(0..10).collect()",
1003 "suggestion_applicability": "MachineApplicable",
1004 "text": [
1005 {
1006 "highlight_end": 6,
1007 "highlight_start": 5,
1008 "text": " a"
1009 }
1010 ]
1011 }
1012 ]
1013 }
1014 ],
1015 "code": {
1016 "code": "clippy::let_and_return",
1017 "explanation": null
1018 },
1019 "level": "warning",
1020 "message": "returning the result of a let binding from a block",
1021 "spans": [
1022 {
1023 "byte_end": 55,
1024 "byte_start": 29,
1025 "column_end": 31,
1026 "column_start": 5,
1027 "expansion": null,
1028 "file_name": "src/main.rs",
1029 "is_primary": false,
1030 "label": "unnecessary let binding",
1031 "line_end": 3,
1032 "line_start": 3,
1033 "suggested_replacement": null,
1034 "suggestion_applicability": null,
1035 "text": [
1036 {
1037 "highlight_end": 31,
1038 "highlight_start": 5,
1039 "text": " let a = (0..10).collect();"
1040 }
1041 ]
1042 },
1043 {
1044 "byte_end": 61,
1045 "byte_start": 60,
1046 "column_end": 6,
1047 "column_start": 5,
1048 "expansion": null,
1049 "file_name": "src/main.rs",
1050 "is_primary": true,
1051 "label": null,
1052 "line_end": 4,
1053 "line_start": 4,
1054 "suggested_replacement": null,
1055 "suggestion_applicability": null,
1056 "text": [
1057 {
1058 "highlight_end": 6,
1059 "highlight_start": 5,
1060 "text": " a"
1061 }
1062 ]
1063 }
1064 ]
1065 }
1066 "##,
1067 );
1068
1069 let workspace_root = PathBuf::from("/test/");
1070 let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root);
937 insta::assert_debug_snapshot!(diag); 1071 insta::assert_debug_snapshot!(diag);
938} 1072}
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs
index f07c34549..94b9c03d0 100644
--- a/crates/ra_cargo_watch/src/lib.rs
+++ b/crates/ra_cargo_watch/src/lib.rs
@@ -197,23 +197,23 @@ impl CheckWatcherThread {
197 } 197 }
198 198
199 CheckEvent::Msg(Message::CompilerMessage(msg)) => { 199 CheckEvent::Msg(Message::CompilerMessage(msg)) => {
200 let map_result = 200 let map_result = map_rust_diagnostic_to_lsp(&msg.message, &self.workspace_root);
201 match map_rust_diagnostic_to_lsp(&msg.message, &self.workspace_root) { 201 if map_result.is_empty() {
202 Some(map_result) => map_result, 202 return;
203 None => return, 203 }
204 };
205
206 let MappedRustDiagnostic { location, diagnostic, fixes } = map_result;
207 let fixes = fixes
208 .into_iter()
209 .map(|fix| {
210 CodeAction { diagnostics: Some(vec![diagnostic.clone()]), ..fix }.into()
211 })
212 .collect();
213 204
214 task_send 205 for MappedRustDiagnostic { location, diagnostic, fixes } in map_result {
215 .send(CheckTask::AddDiagnostic { url: location.uri, diagnostic, fixes }) 206 let fixes = fixes
216 .unwrap(); 207 .into_iter()
208 .map(|fix| {
209 CodeAction { diagnostics: Some(vec![diagnostic.clone()]), ..fix }.into()
210 })
211 .collect();
212
213 task_send
214 .send(CheckTask::AddDiagnostic { url: location.uri, diagnostic, fixes })
215 .unwrap();
216 }
217 } 217 }
218 218
219 CheckEvent::Msg(Message::BuildScriptExecuted(_msg)) => {} 219 CheckEvent::Msg(Message::BuildScriptExecuted(_msg)) => {}