diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-12-06 13:26:54 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-12-06 13:26:54 +0000 |
commit | 1403ddf029a6a4ced904146ac7b475c923f6129f (patch) | |
tree | 5de8d09fea220460bf49657f086d3130c79eb491 | |
parent | 8d5aa08712e782f22f04525f291ec74dae183568 (diff) | |
parent | 45b8b3d57fd1a38a0ccce8516cbebbd09184d59a (diff) |
Merge #6734
6734: Emit additional diagnostics for hints/help/etc r=lnicola a=jonas-schievink
This makes rust-analyzer diagnostics match native rustc diagnostics in the terminal more closely. Unfortunately all of this is a bodge, since we already provide this information to the client in the form of `DiagnosticRelatedInformation`, but at least VS Code chooses such a poor UI for these that they don't help much, as evidenced [here](https://twitter.com/yaahc_/status/1335297260444250112) and in https://github.com/rust-lang/rust/issues/79741.
This PR papers over these client UI problems by taking the `DiagnosticRelatedInformation` and turning each one into its own hint-level diagnostic, which makes it show up in the source code. Quick fixes are attached to all resulting diagnostics, which makes them more discoverable.
### Example: "Consider removing this semicolon"
![screenshot-2020-12-06-01:27:29](https://user-images.githubusercontent.com/1786438/101268366-46423980-3762-11eb-9a69-1ff0b1806c2f.png)
![screenshot-2020-12-06-01:27:39](https://user-images.githubusercontent.com/1786438/101268367-46dad000-3762-11eb-81fa-afd234d44f17.png)
![screenshot-2020-12-06-01:27:46](https://user-images.githubusercontent.com/1786438/101268368-46dad000-3762-11eb-9205-4b9bd9f4406d.png)
### Example: "Value used after move"
![screenshot-2020-12-06-01:33:00](https://user-images.githubusercontent.com/1786438/101268447-22332800-3763-11eb-85ce-8c742927a2c8.png)
![screenshot-2020-12-06-01:33:07](https://user-images.githubusercontent.com/1786438/101268448-22cbbe80-3763-11eb-8f16-0590895d8bc6.png)
Co-authored-by: Jonas Schievink <[email protected]>
8 files changed, 1093 insertions, 119 deletions
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt index 72f6c5725..7576097b3 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt | |||
@@ -104,4 +104,168 @@ | |||
104 | }, | 104 | }, |
105 | fixes: [], | 105 | fixes: [], |
106 | }, | 106 | }, |
107 | MappedRustDiagnostic { | ||
108 | url: Url { | ||
109 | scheme: "file", | ||
110 | host: None, | ||
111 | port: None, | ||
112 | path: "/test/compiler/lib.rs", | ||
113 | query: None, | ||
114 | fragment: None, | ||
115 | }, | ||
116 | diagnostic: Diagnostic { | ||
117 | range: Range { | ||
118 | start: Position { | ||
119 | line: 0, | ||
120 | character: 8, | ||
121 | }, | ||
122 | end: Position { | ||
123 | line: 0, | ||
124 | character: 19, | ||
125 | }, | ||
126 | }, | ||
127 | severity: Some( | ||
128 | Hint, | ||
129 | ), | ||
130 | code: Some( | ||
131 | String( | ||
132 | "trivially_copy_pass_by_ref", | ||
133 | ), | ||
134 | ), | ||
135 | code_description: Some( | ||
136 | CodeDescription { | ||
137 | href: Url { | ||
138 | scheme: "https", | ||
139 | host: Some( | ||
140 | Domain( | ||
141 | "rust-lang.github.io", | ||
142 | ), | ||
143 | ), | ||
144 | port: None, | ||
145 | path: "/rust-clippy/master/index.html", | ||
146 | query: None, | ||
147 | fragment: Some( | ||
148 | "trivially_copy_pass_by_ref", | ||
149 | ), | ||
150 | }, | ||
151 | }, | ||
152 | ), | ||
153 | source: Some( | ||
154 | "clippy", | ||
155 | ), | ||
156 | message: "lint level defined here", | ||
157 | related_information: Some( | ||
158 | [ | ||
159 | DiagnosticRelatedInformation { | ||
160 | location: Location { | ||
161 | uri: Url { | ||
162 | scheme: "file", | ||
163 | host: None, | ||
164 | port: None, | ||
165 | path: "/test/compiler/mir/tagset.rs", | ||
166 | query: None, | ||
167 | fragment: None, | ||
168 | }, | ||
169 | range: Range { | ||
170 | start: Position { | ||
171 | line: 41, | ||
172 | character: 23, | ||
173 | }, | ||
174 | end: Position { | ||
175 | line: 41, | ||
176 | character: 28, | ||
177 | }, | ||
178 | }, | ||
179 | }, | ||
180 | message: "original diagnostic", | ||
181 | }, | ||
182 | ], | ||
183 | ), | ||
184 | tags: None, | ||
185 | data: None, | ||
186 | }, | ||
187 | fixes: [], | ||
188 | }, | ||
189 | MappedRustDiagnostic { | ||
190 | url: Url { | ||
191 | scheme: "file", | ||
192 | host: None, | ||
193 | port: None, | ||
194 | path: "/test/compiler/mir/tagset.rs", | ||
195 | query: None, | ||
196 | fragment: None, | ||
197 | }, | ||
198 | diagnostic: Diagnostic { | ||
199 | range: Range { | ||
200 | start: Position { | ||
201 | line: 41, | ||
202 | character: 23, | ||
203 | }, | ||
204 | end: Position { | ||
205 | line: 41, | ||
206 | character: 28, | ||
207 | }, | ||
208 | }, | ||
209 | severity: Some( | ||
210 | Hint, | ||
211 | ), | ||
212 | code: Some( | ||
213 | String( | ||
214 | "trivially_copy_pass_by_ref", | ||
215 | ), | ||
216 | ), | ||
217 | code_description: Some( | ||
218 | CodeDescription { | ||
219 | href: Url { | ||
220 | scheme: "https", | ||
221 | host: Some( | ||
222 | Domain( | ||
223 | "rust-lang.github.io", | ||
224 | ), | ||
225 | ), | ||
226 | port: None, | ||
227 | path: "/rust-clippy/master/index.html", | ||
228 | query: None, | ||
229 | fragment: Some( | ||
230 | "trivially_copy_pass_by_ref", | ||
231 | ), | ||
232 | }, | ||
233 | }, | ||
234 | ), | ||
235 | source: Some( | ||
236 | "clippy", | ||
237 | ), | ||
238 | message: "consider passing by value instead", | ||
239 | related_information: Some( | ||
240 | [ | ||
241 | DiagnosticRelatedInformation { | ||
242 | location: Location { | ||
243 | uri: Url { | ||
244 | scheme: "file", | ||
245 | host: None, | ||
246 | port: None, | ||
247 | path: "/test/compiler/mir/tagset.rs", | ||
248 | query: None, | ||
249 | fragment: None, | ||
250 | }, | ||
251 | range: Range { | ||
252 | start: Position { | ||
253 | line: 41, | ||
254 | character: 23, | ||
255 | }, | ||
256 | end: Position { | ||
257 | line: 41, | ||
258 | character: 28, | ||
259 | }, | ||
260 | }, | ||
261 | }, | ||
262 | message: "original diagnostic", | ||
263 | }, | ||
264 | ], | ||
265 | ), | ||
266 | tags: None, | ||
267 | data: None, | ||
268 | }, | ||
269 | fixes: [], | ||
270 | }, | ||
107 | ] | 271 | ] |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt index bbec6a796..bdcf2a38f 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt | |||
@@ -4,19 +4,19 @@ | |||
4 | scheme: "file", | 4 | scheme: "file", |
5 | host: None, | 5 | host: None, |
6 | port: None, | 6 | port: None, |
7 | path: "/test/crates/hir_def/src/data.rs", | 7 | path: "/test/crates/hir_def/src/path.rs", |
8 | query: None, | 8 | query: None, |
9 | fragment: None, | 9 | fragment: None, |
10 | }, | 10 | }, |
11 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
12 | range: Range { | 12 | range: Range { |
13 | start: Position { | 13 | start: Position { |
14 | line: 79, | 14 | line: 264, |
15 | character: 15, | 15 | character: 8, |
16 | }, | 16 | }, |
17 | end: Position { | 17 | end: Position { |
18 | line: 79, | 18 | line: 264, |
19 | character: 41, | 19 | character: 76, |
20 | }, | 20 | }, |
21 | }, | 21 | }, |
22 | severity: Some( | 22 | severity: Some( |
@@ -36,22 +36,22 @@ | |||
36 | scheme: "file", | 36 | scheme: "file", |
37 | host: None, | 37 | host: None, |
38 | port: None, | 38 | port: None, |
39 | path: "/test/crates/hir_def/src/path.rs", | 39 | path: "/test/crates/hir_def/src/data.rs", |
40 | query: None, | 40 | query: None, |
41 | fragment: None, | 41 | fragment: None, |
42 | }, | 42 | }, |
43 | range: Range { | 43 | range: Range { |
44 | start: Position { | 44 | start: Position { |
45 | line: 264, | 45 | line: 79, |
46 | character: 8, | 46 | character: 15, |
47 | }, | 47 | }, |
48 | end: Position { | 48 | end: Position { |
49 | line: 264, | 49 | line: 79, |
50 | character: 76, | 50 | character: 41, |
51 | }, | 51 | }, |
52 | }, | 52 | }, |
53 | }, | 53 | }, |
54 | message: "Error originated from macro here", | 54 | message: "Exact error occurred here", |
55 | }, | 55 | }, |
56 | ], | 56 | ], |
57 | ), | 57 | ), |
@@ -65,19 +65,19 @@ | |||
65 | scheme: "file", | 65 | scheme: "file", |
66 | host: None, | 66 | host: None, |
67 | port: None, | 67 | port: None, |
68 | path: "/test/crates/hir_def/src/path.rs", | 68 | path: "/test/crates/hir_def/src/data.rs", |
69 | query: None, | 69 | query: None, |
70 | fragment: None, | 70 | fragment: None, |
71 | }, | 71 | }, |
72 | diagnostic: Diagnostic { | 72 | diagnostic: Diagnostic { |
73 | range: Range { | 73 | range: Range { |
74 | start: Position { | 74 | start: Position { |
75 | line: 264, | 75 | line: 79, |
76 | character: 8, | 76 | character: 15, |
77 | }, | 77 | }, |
78 | end: Position { | 78 | end: Position { |
79 | line: 264, | 79 | line: 79, |
80 | character: 76, | 80 | character: 41, |
81 | }, | 81 | }, |
82 | }, | 82 | }, |
83 | severity: Some( | 83 | severity: Some( |
@@ -89,33 +89,7 @@ | |||
89 | "rustc", | 89 | "rustc", |
90 | ), | 90 | ), |
91 | message: "Please register your known path in the path module", | 91 | message: "Please register your known path in the path module", |
92 | related_information: Some( | 92 | related_information: None, |
93 | [ | ||
94 | DiagnosticRelatedInformation { | ||
95 | location: Location { | ||
96 | uri: Url { | ||
97 | scheme: "file", | ||
98 | host: None, | ||
99 | port: None, | ||
100 | path: "/test/crates/hir_def/src/data.rs", | ||
101 | query: None, | ||
102 | fragment: None, | ||
103 | }, | ||
104 | range: Range { | ||
105 | start: Position { | ||
106 | line: 79, | ||
107 | character: 15, | ||
108 | }, | ||
109 | end: Position { | ||
110 | line: 79, | ||
111 | character: 41, | ||
112 | }, | ||
113 | }, | ||
114 | }, | ||
115 | message: "Exact error occured here", | ||
116 | }, | ||
117 | ], | ||
118 | ), | ||
119 | tags: None, | 93 | tags: None, |
120 | data: None, | 94 | data: None, |
121 | }, | 95 | }, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt index c709de95f..23d42b4d0 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt | |||
@@ -32,7 +32,33 @@ | |||
32 | "rustc", | 32 | "rustc", |
33 | ), | 33 | ), |
34 | message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", | 34 | message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", |
35 | related_information: None, | 35 | related_information: Some( |
36 | [ | ||
37 | DiagnosticRelatedInformation { | ||
38 | location: Location { | ||
39 | uri: Url { | ||
40 | scheme: "file", | ||
41 | host: None, | ||
42 | port: None, | ||
43 | path: "/test/driver/subcommand/repl.rs", | ||
44 | query: None, | ||
45 | fragment: None, | ||
46 | }, | ||
47 | range: Range { | ||
48 | start: Position { | ||
49 | line: 290, | ||
50 | character: 8, | ||
51 | }, | ||
52 | end: Position { | ||
53 | line: 290, | ||
54 | character: 11, | ||
55 | }, | ||
56 | }, | ||
57 | }, | ||
58 | message: "consider prefixing with an underscore", | ||
59 | }, | ||
60 | ], | ||
61 | ), | ||
36 | tags: Some( | 62 | tags: Some( |
37 | [ | 63 | [ |
38 | Unnecessary, | 64 | Unnecessary, |
@@ -87,4 +113,114 @@ | |||
87 | }, | 113 | }, |
88 | ], | 114 | ], |
89 | }, | 115 | }, |
116 | MappedRustDiagnostic { | ||
117 | url: Url { | ||
118 | scheme: "file", | ||
119 | host: None, | ||
120 | port: None, | ||
121 | path: "/test/driver/subcommand/repl.rs", | ||
122 | query: None, | ||
123 | fragment: None, | ||
124 | }, | ||
125 | diagnostic: Diagnostic { | ||
126 | range: Range { | ||
127 | start: Position { | ||
128 | line: 290, | ||
129 | character: 8, | ||
130 | }, | ||
131 | end: Position { | ||
132 | line: 290, | ||
133 | character: 11, | ||
134 | }, | ||
135 | }, | ||
136 | severity: Some( | ||
137 | Hint, | ||
138 | ), | ||
139 | code: Some( | ||
140 | String( | ||
141 | "unused_variables", | ||
142 | ), | ||
143 | ), | ||
144 | code_description: None, | ||
145 | source: Some( | ||
146 | "rustc", | ||
147 | ), | ||
148 | message: "consider prefixing with an underscore", | ||
149 | related_information: Some( | ||
150 | [ | ||
151 | DiagnosticRelatedInformation { | ||
152 | location: Location { | ||
153 | uri: Url { | ||
154 | scheme: "file", | ||
155 | host: None, | ||
156 | port: None, | ||
157 | path: "/test/driver/subcommand/repl.rs", | ||
158 | query: None, | ||
159 | fragment: None, | ||
160 | }, | ||
161 | range: Range { | ||
162 | start: Position { | ||
163 | line: 290, | ||
164 | character: 8, | ||
165 | }, | ||
166 | end: Position { | ||
167 | line: 290, | ||
168 | character: 11, | ||
169 | }, | ||
170 | }, | ||
171 | }, | ||
172 | message: "original diagnostic", | ||
173 | }, | ||
174 | ], | ||
175 | ), | ||
176 | tags: None, | ||
177 | data: None, | ||
178 | }, | ||
179 | fixes: [ | ||
180 | CodeAction { | ||
181 | title: "consider prefixing with an underscore", | ||
182 | group: None, | ||
183 | kind: Some( | ||
184 | CodeActionKind( | ||
185 | "quickfix", | ||
186 | ), | ||
187 | ), | ||
188 | edit: Some( | ||
189 | SnippetWorkspaceEdit { | ||
190 | changes: Some( | ||
191 | { | ||
192 | Url { | ||
193 | scheme: "file", | ||
194 | host: None, | ||
195 | port: None, | ||
196 | path: "/test/driver/subcommand/repl.rs", | ||
197 | query: None, | ||
198 | fragment: None, | ||
199 | }: [ | ||
200 | TextEdit { | ||
201 | range: Range { | ||
202 | start: Position { | ||
203 | line: 290, | ||
204 | character: 8, | ||
205 | }, | ||
206 | end: Position { | ||
207 | line: 290, | ||
208 | character: 11, | ||
209 | }, | ||
210 | }, | ||
211 | new_text: "_foo", | ||
212 | }, | ||
213 | ], | ||
214 | }, | ||
215 | ), | ||
216 | document_changes: None, | ||
217 | }, | ||
218 | ), | ||
219 | is_preferred: Some( | ||
220 | true, | ||
221 | ), | ||
222 | data: None, | ||
223 | }, | ||
224 | ], | ||
225 | }, | ||
90 | ] | 226 | ] |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt index 632f438d7..4e428bedc 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt | |||
@@ -32,7 +32,33 @@ | |||
32 | "rustc", | 32 | "rustc", |
33 | ), | 33 | ), |
34 | message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", | 34 | message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", |
35 | related_information: None, | 35 | related_information: Some( |
36 | [ | ||
37 | DiagnosticRelatedInformation { | ||
38 | location: Location { | ||
39 | uri: Url { | ||
40 | scheme: "file", | ||
41 | host: None, | ||
42 | port: None, | ||
43 | path: "/test/driver/subcommand/repl.rs", | ||
44 | query: None, | ||
45 | fragment: None, | ||
46 | }, | ||
47 | range: Range { | ||
48 | start: Position { | ||
49 | line: 290, | ||
50 | character: 8, | ||
51 | }, | ||
52 | end: Position { | ||
53 | line: 290, | ||
54 | character: 11, | ||
55 | }, | ||
56 | }, | ||
57 | }, | ||
58 | message: "consider prefixing with an underscore", | ||
59 | }, | ||
60 | ], | ||
61 | ), | ||
36 | tags: Some( | 62 | tags: Some( |
37 | [ | 63 | [ |
38 | Unnecessary, | 64 | Unnecessary, |
@@ -87,4 +113,114 @@ | |||
87 | }, | 113 | }, |
88 | ], | 114 | ], |
89 | }, | 115 | }, |
116 | MappedRustDiagnostic { | ||
117 | url: Url { | ||
118 | scheme: "file", | ||
119 | host: None, | ||
120 | port: None, | ||
121 | path: "/test/driver/subcommand/repl.rs", | ||
122 | query: None, | ||
123 | fragment: None, | ||
124 | }, | ||
125 | diagnostic: Diagnostic { | ||
126 | range: Range { | ||
127 | start: Position { | ||
128 | line: 290, | ||
129 | character: 8, | ||
130 | }, | ||
131 | end: Position { | ||
132 | line: 290, | ||
133 | character: 11, | ||
134 | }, | ||
135 | }, | ||
136 | severity: Some( | ||
137 | Hint, | ||
138 | ), | ||
139 | code: Some( | ||
140 | String( | ||
141 | "unused_variables", | ||
142 | ), | ||
143 | ), | ||
144 | code_description: None, | ||
145 | source: Some( | ||
146 | "rustc", | ||
147 | ), | ||
148 | message: "consider prefixing with an underscore", | ||
149 | related_information: Some( | ||
150 | [ | ||
151 | DiagnosticRelatedInformation { | ||
152 | location: Location { | ||
153 | uri: Url { | ||
154 | scheme: "file", | ||
155 | host: None, | ||
156 | port: None, | ||
157 | path: "/test/driver/subcommand/repl.rs", | ||
158 | query: None, | ||
159 | fragment: None, | ||
160 | }, | ||
161 | range: Range { | ||
162 | start: Position { | ||
163 | line: 290, | ||
164 | character: 8, | ||
165 | }, | ||
166 | end: Position { | ||
167 | line: 290, | ||
168 | character: 11, | ||
169 | }, | ||
170 | }, | ||
171 | }, | ||
172 | message: "original diagnostic", | ||
173 | }, | ||
174 | ], | ||
175 | ), | ||
176 | tags: None, | ||
177 | data: None, | ||
178 | }, | ||
179 | fixes: [ | ||
180 | CodeAction { | ||
181 | title: "consider prefixing with an underscore", | ||
182 | group: None, | ||
183 | kind: Some( | ||
184 | CodeActionKind( | ||
185 | "quickfix", | ||
186 | ), | ||
187 | ), | ||
188 | edit: Some( | ||
189 | SnippetWorkspaceEdit { | ||
190 | changes: Some( | ||
191 | { | ||
192 | Url { | ||
193 | scheme: "file", | ||
194 | host: None, | ||
195 | port: None, | ||
196 | path: "/test/driver/subcommand/repl.rs", | ||
197 | query: None, | ||
198 | fragment: None, | ||
199 | }: [ | ||
200 | TextEdit { | ||
201 | range: Range { | ||
202 | start: Position { | ||
203 | line: 290, | ||
204 | character: 8, | ||
205 | }, | ||
206 | end: Position { | ||
207 | line: 290, | ||
208 | character: 11, | ||
209 | }, | ||
210 | }, | ||
211 | new_text: "_foo", | ||
212 | }, | ||
213 | ], | ||
214 | }, | ||
215 | ), | ||
216 | document_changes: None, | ||
217 | }, | ||
218 | ), | ||
219 | is_preferred: Some( | ||
220 | true, | ||
221 | ), | ||
222 | data: None, | ||
223 | }, | ||
224 | ], | ||
225 | }, | ||
90 | ] | 226 | ] |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt index c0b79428d..4ddd7efae 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt | |||
@@ -32,7 +32,33 @@ | |||
32 | "rustc", | 32 | "rustc", |
33 | ), | 33 | ), |
34 | message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", | 34 | message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", |
35 | related_information: None, | 35 | related_information: Some( |
36 | [ | ||
37 | DiagnosticRelatedInformation { | ||
38 | location: Location { | ||
39 | uri: Url { | ||
40 | scheme: "file", | ||
41 | host: None, | ||
42 | port: None, | ||
43 | path: "/test/driver/subcommand/repl.rs", | ||
44 | query: None, | ||
45 | fragment: None, | ||
46 | }, | ||
47 | range: Range { | ||
48 | start: Position { | ||
49 | line: 290, | ||
50 | character: 8, | ||
51 | }, | ||
52 | end: Position { | ||
53 | line: 290, | ||
54 | character: 11, | ||
55 | }, | ||
56 | }, | ||
57 | }, | ||
58 | message: "consider prefixing with an underscore", | ||
59 | }, | ||
60 | ], | ||
61 | ), | ||
36 | tags: Some( | 62 | tags: Some( |
37 | [ | 63 | [ |
38 | Unnecessary, | 64 | Unnecessary, |
@@ -87,4 +113,114 @@ | |||
87 | }, | 113 | }, |
88 | ], | 114 | ], |
89 | }, | 115 | }, |
116 | MappedRustDiagnostic { | ||
117 | url: Url { | ||
118 | scheme: "file", | ||
119 | host: None, | ||
120 | port: None, | ||
121 | path: "/test/driver/subcommand/repl.rs", | ||
122 | query: None, | ||
123 | fragment: None, | ||
124 | }, | ||
125 | diagnostic: Diagnostic { | ||
126 | range: Range { | ||
127 | start: Position { | ||
128 | line: 290, | ||
129 | character: 8, | ||
130 | }, | ||
131 | end: Position { | ||
132 | line: 290, | ||
133 | character: 11, | ||
134 | }, | ||
135 | }, | ||
136 | severity: Some( | ||
137 | Hint, | ||
138 | ), | ||
139 | code: Some( | ||
140 | String( | ||
141 | "unused_variables", | ||
142 | ), | ||
143 | ), | ||
144 | code_description: None, | ||
145 | source: Some( | ||
146 | "rustc", | ||
147 | ), | ||
148 | message: "consider prefixing with an underscore", | ||
149 | related_information: Some( | ||
150 | [ | ||
151 | DiagnosticRelatedInformation { | ||
152 | location: Location { | ||
153 | uri: Url { | ||
154 | scheme: "file", | ||
155 | host: None, | ||
156 | port: None, | ||
157 | path: "/test/driver/subcommand/repl.rs", | ||
158 | query: None, | ||
159 | fragment: None, | ||
160 | }, | ||
161 | range: Range { | ||
162 | start: Position { | ||
163 | line: 290, | ||
164 | character: 8, | ||
165 | }, | ||
166 | end: Position { | ||
167 | line: 290, | ||
168 | character: 11, | ||
169 | }, | ||
170 | }, | ||
171 | }, | ||
172 | message: "original diagnostic", | ||
173 | }, | ||
174 | ], | ||
175 | ), | ||
176 | tags: None, | ||
177 | data: None, | ||
178 | }, | ||
179 | fixes: [ | ||
180 | CodeAction { | ||
181 | title: "consider prefixing with an underscore", | ||
182 | group: None, | ||
183 | kind: Some( | ||
184 | CodeActionKind( | ||
185 | "quickfix", | ||
186 | ), | ||
187 | ), | ||
188 | edit: Some( | ||
189 | SnippetWorkspaceEdit { | ||
190 | changes: Some( | ||
191 | { | ||
192 | Url { | ||
193 | scheme: "file", | ||
194 | host: None, | ||
195 | port: None, | ||
196 | path: "/test/driver/subcommand/repl.rs", | ||
197 | query: None, | ||
198 | fragment: None, | ||
199 | }: [ | ||
200 | TextEdit { | ||
201 | range: Range { | ||
202 | start: Position { | ||
203 | line: 290, | ||
204 | character: 8, | ||
205 | }, | ||
206 | end: Position { | ||
207 | line: 290, | ||
208 | character: 11, | ||
209 | }, | ||
210 | }, | ||
211 | new_text: "_foo", | ||
212 | }, | ||
213 | ], | ||
214 | }, | ||
215 | ), | ||
216 | document_changes: None, | ||
217 | }, | ||
218 | ), | ||
219 | is_preferred: Some( | ||
220 | true, | ||
221 | ), | ||
222 | data: None, | ||
223 | }, | ||
224 | ], | ||
225 | }, | ||
90 | ] | 226 | ] |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt index b9650f3e4..f455cf25e 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt | |||
@@ -81,4 +81,86 @@ | |||
81 | }, | 81 | }, |
82 | fixes: [], | 82 | fixes: [], |
83 | }, | 83 | }, |
84 | MappedRustDiagnostic { | ||
85 | url: Url { | ||
86 | scheme: "file", | ||
87 | host: None, | ||
88 | port: None, | ||
89 | path: "/test/compiler/ty/select.rs", | ||
90 | query: None, | ||
91 | fragment: None, | ||
92 | }, | ||
93 | diagnostic: Diagnostic { | ||
94 | range: Range { | ||
95 | start: Position { | ||
96 | line: 218, | ||
97 | character: 4, | ||
98 | }, | ||
99 | end: Position { | ||
100 | line: 230, | ||
101 | character: 5, | ||
102 | }, | ||
103 | }, | ||
104 | severity: Some( | ||
105 | Hint, | ||
106 | ), | ||
107 | code: Some( | ||
108 | String( | ||
109 | "E0061", | ||
110 | ), | ||
111 | ), | ||
112 | code_description: Some( | ||
113 | CodeDescription { | ||
114 | href: Url { | ||
115 | scheme: "https", | ||
116 | host: Some( | ||
117 | Domain( | ||
118 | "doc.rust-lang.org", | ||
119 | ), | ||
120 | ), | ||
121 | port: None, | ||
122 | path: "/error-index.html", | ||
123 | query: None, | ||
124 | fragment: Some( | ||
125 | "E0061", | ||
126 | ), | ||
127 | }, | ||
128 | }, | ||
129 | ), | ||
130 | source: Some( | ||
131 | "rustc", | ||
132 | ), | ||
133 | message: "defined here", | ||
134 | related_information: Some( | ||
135 | [ | ||
136 | DiagnosticRelatedInformation { | ||
137 | location: Location { | ||
138 | uri: Url { | ||
139 | scheme: "file", | ||
140 | host: None, | ||
141 | port: None, | ||
142 | path: "/test/compiler/ty/select.rs", | ||
143 | query: None, | ||
144 | fragment: None, | ||
145 | }, | ||
146 | range: Range { | ||
147 | start: Position { | ||
148 | line: 103, | ||
149 | character: 17, | ||
150 | }, | ||
151 | end: Position { | ||
152 | line: 103, | ||
153 | character: 29, | ||
154 | }, | ||
155 | }, | ||
156 | }, | ||
157 | message: "original diagnostic", | ||
158 | }, | ||
159 | ], | ||
160 | ), | ||
161 | tags: None, | ||
162 | data: None, | ||
163 | }, | ||
164 | fixes: [], | ||
165 | }, | ||
84 | ] | 166 | ] |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt index c45f68a91..4cbdb3b92 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt | |||
@@ -74,6 +74,309 @@ | |||
74 | }, | 74 | }, |
75 | message: "unnecessary let binding", | 75 | message: "unnecessary let binding", |
76 | }, | 76 | }, |
77 | DiagnosticRelatedInformation { | ||
78 | location: Location { | ||
79 | uri: Url { | ||
80 | scheme: "file", | ||
81 | host: None, | ||
82 | port: None, | ||
83 | path: "/test/src/main.rs", | ||
84 | query: None, | ||
85 | fragment: None, | ||
86 | }, | ||
87 | range: Range { | ||
88 | start: Position { | ||
89 | line: 2, | ||
90 | character: 4, | ||
91 | }, | ||
92 | end: Position { | ||
93 | line: 2, | ||
94 | character: 30, | ||
95 | }, | ||
96 | }, | ||
97 | }, | ||
98 | message: "return the expression directly", | ||
99 | }, | ||
100 | ], | ||
101 | ), | ||
102 | tags: None, | ||
103 | data: None, | ||
104 | }, | ||
105 | fixes: [ | ||
106 | CodeAction { | ||
107 | title: "return the expression directly", | ||
108 | group: None, | ||
109 | kind: Some( | ||
110 | CodeActionKind( | ||
111 | "quickfix", | ||
112 | ), | ||
113 | ), | ||
114 | edit: Some( | ||
115 | SnippetWorkspaceEdit { | ||
116 | changes: Some( | ||
117 | { | ||
118 | Url { | ||
119 | scheme: "file", | ||
120 | host: None, | ||
121 | port: None, | ||
122 | path: "/test/src/main.rs", | ||
123 | query: None, | ||
124 | fragment: None, | ||
125 | }: [ | ||
126 | TextEdit { | ||
127 | range: Range { | ||
128 | start: Position { | ||
129 | line: 2, | ||
130 | character: 4, | ||
131 | }, | ||
132 | end: Position { | ||
133 | line: 2, | ||
134 | character: 30, | ||
135 | }, | ||
136 | }, | ||
137 | new_text: "", | ||
138 | }, | ||
139 | TextEdit { | ||
140 | range: Range { | ||
141 | start: Position { | ||
142 | line: 3, | ||
143 | character: 4, | ||
144 | }, | ||
145 | end: Position { | ||
146 | line: 3, | ||
147 | character: 5, | ||
148 | }, | ||
149 | }, | ||
150 | new_text: "(0..10).collect()", | ||
151 | }, | ||
152 | ], | ||
153 | }, | ||
154 | ), | ||
155 | document_changes: None, | ||
156 | }, | ||
157 | ), | ||
158 | is_preferred: Some( | ||
159 | true, | ||
160 | ), | ||
161 | data: None, | ||
162 | }, | ||
163 | ], | ||
164 | }, | ||
165 | MappedRustDiagnostic { | ||
166 | url: Url { | ||
167 | scheme: "file", | ||
168 | host: None, | ||
169 | port: None, | ||
170 | path: "/test/src/main.rs", | ||
171 | query: None, | ||
172 | fragment: None, | ||
173 | }, | ||
174 | diagnostic: Diagnostic { | ||
175 | range: Range { | ||
176 | start: Position { | ||
177 | line: 2, | ||
178 | character: 4, | ||
179 | }, | ||
180 | end: Position { | ||
181 | line: 2, | ||
182 | character: 30, | ||
183 | }, | ||
184 | }, | ||
185 | severity: Some( | ||
186 | Hint, | ||
187 | ), | ||
188 | code: Some( | ||
189 | String( | ||
190 | "let_and_return", | ||
191 | ), | ||
192 | ), | ||
193 | code_description: Some( | ||
194 | CodeDescription { | ||
195 | href: Url { | ||
196 | scheme: "https", | ||
197 | host: Some( | ||
198 | Domain( | ||
199 | "rust-lang.github.io", | ||
200 | ), | ||
201 | ), | ||
202 | port: None, | ||
203 | path: "/rust-clippy/master/index.html", | ||
204 | query: None, | ||
205 | fragment: Some( | ||
206 | "let_and_return", | ||
207 | ), | ||
208 | }, | ||
209 | }, | ||
210 | ), | ||
211 | source: Some( | ||
212 | "clippy", | ||
213 | ), | ||
214 | message: "unnecessary let binding", | ||
215 | related_information: Some( | ||
216 | [ | ||
217 | DiagnosticRelatedInformation { | ||
218 | location: Location { | ||
219 | uri: Url { | ||
220 | scheme: "file", | ||
221 | host: None, | ||
222 | port: None, | ||
223 | path: "/test/src/main.rs", | ||
224 | query: None, | ||
225 | fragment: None, | ||
226 | }, | ||
227 | range: Range { | ||
228 | start: Position { | ||
229 | line: 3, | ||
230 | character: 4, | ||
231 | }, | ||
232 | end: Position { | ||
233 | line: 3, | ||
234 | character: 5, | ||
235 | }, | ||
236 | }, | ||
237 | }, | ||
238 | message: "original diagnostic", | ||
239 | }, | ||
240 | ], | ||
241 | ), | ||
242 | tags: None, | ||
243 | data: None, | ||
244 | }, | ||
245 | fixes: [ | ||
246 | CodeAction { | ||
247 | title: "return the expression directly", | ||
248 | group: None, | ||
249 | kind: Some( | ||
250 | CodeActionKind( | ||
251 | "quickfix", | ||
252 | ), | ||
253 | ), | ||
254 | edit: Some( | ||
255 | SnippetWorkspaceEdit { | ||
256 | changes: Some( | ||
257 | { | ||
258 | Url { | ||
259 | scheme: "file", | ||
260 | host: None, | ||
261 | port: None, | ||
262 | path: "/test/src/main.rs", | ||
263 | query: None, | ||
264 | fragment: None, | ||
265 | }: [ | ||
266 | TextEdit { | ||
267 | range: Range { | ||
268 | start: Position { | ||
269 | line: 2, | ||
270 | character: 4, | ||
271 | }, | ||
272 | end: Position { | ||
273 | line: 2, | ||
274 | character: 30, | ||
275 | }, | ||
276 | }, | ||
277 | new_text: "", | ||
278 | }, | ||
279 | TextEdit { | ||
280 | range: Range { | ||
281 | start: Position { | ||
282 | line: 3, | ||
283 | character: 4, | ||
284 | }, | ||
285 | end: Position { | ||
286 | line: 3, | ||
287 | character: 5, | ||
288 | }, | ||
289 | }, | ||
290 | new_text: "(0..10).collect()", | ||
291 | }, | ||
292 | ], | ||
293 | }, | ||
294 | ), | ||
295 | document_changes: None, | ||
296 | }, | ||
297 | ), | ||
298 | is_preferred: Some( | ||
299 | true, | ||
300 | ), | ||
301 | data: None, | ||
302 | }, | ||
303 | ], | ||
304 | }, | ||
305 | MappedRustDiagnostic { | ||
306 | url: Url { | ||
307 | scheme: "file", | ||
308 | host: None, | ||
309 | port: None, | ||
310 | path: "/test/src/main.rs", | ||
311 | query: None, | ||
312 | fragment: None, | ||
313 | }, | ||
314 | diagnostic: Diagnostic { | ||
315 | range: Range { | ||
316 | start: Position { | ||
317 | line: 2, | ||
318 | character: 4, | ||
319 | }, | ||
320 | end: Position { | ||
321 | line: 2, | ||
322 | character: 30, | ||
323 | }, | ||
324 | }, | ||
325 | severity: Some( | ||
326 | Hint, | ||
327 | ), | ||
328 | code: Some( | ||
329 | String( | ||
330 | "let_and_return", | ||
331 | ), | ||
332 | ), | ||
333 | code_description: Some( | ||
334 | CodeDescription { | ||
335 | href: Url { | ||
336 | scheme: "https", | ||
337 | host: Some( | ||
338 | Domain( | ||
339 | "rust-lang.github.io", | ||
340 | ), | ||
341 | ), | ||
342 | port: None, | ||
343 | path: "/rust-clippy/master/index.html", | ||
344 | query: None, | ||
345 | fragment: Some( | ||
346 | "let_and_return", | ||
347 | ), | ||
348 | }, | ||
349 | }, | ||
350 | ), | ||
351 | source: Some( | ||
352 | "clippy", | ||
353 | ), | ||
354 | message: "return the expression directly", | ||
355 | related_information: Some( | ||
356 | [ | ||
357 | DiagnosticRelatedInformation { | ||
358 | location: Location { | ||
359 | uri: Url { | ||
360 | scheme: "file", | ||
361 | host: None, | ||
362 | port: None, | ||
363 | path: "/test/src/main.rs", | ||
364 | query: None, | ||
365 | fragment: None, | ||
366 | }, | ||
367 | range: Range { | ||
368 | start: Position { | ||
369 | line: 3, | ||
370 | character: 4, | ||
371 | }, | ||
372 | end: Position { | ||
373 | line: 3, | ||
374 | character: 5, | ||
375 | }, | ||
376 | }, | ||
377 | }, | ||
378 | message: "original diagnostic", | ||
379 | }, | ||
77 | ], | 380 | ], |
78 | ), | 381 | ), |
79 | tags: None, | 382 | tags: None, |
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index 324019614..f16f97131 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -75,8 +75,10 @@ fn diagnostic_related_information( | |||
75 | } | 75 | } |
76 | 76 | ||
77 | enum MappedRustChildDiagnostic { | 77 | enum MappedRustChildDiagnostic { |
78 | Related(lsp_types::DiagnosticRelatedInformation), | 78 | Related { |
79 | SuggestedFix(lsp_ext::CodeAction), | 79 | related: lsp_types::DiagnosticRelatedInformation, |
80 | suggested_fix: Option<lsp_ext::CodeAction>, | ||
81 | }, | ||
80 | MessageLine(String), | 82 | MessageLine(String), |
81 | } | 83 | } |
82 | 84 | ||
@@ -103,23 +105,32 @@ fn map_rust_child_diagnostic( | |||
103 | } | 105 | } |
104 | 106 | ||
105 | if edit_map.is_empty() { | 107 | if edit_map.is_empty() { |
106 | MappedRustChildDiagnostic::Related(lsp_types::DiagnosticRelatedInformation { | 108 | MappedRustChildDiagnostic::Related { |
107 | location: location(workspace_root, spans[0]), | 109 | related: lsp_types::DiagnosticRelatedInformation { |
108 | message: rd.message.clone(), | 110 | location: location(workspace_root, spans[0]), |
109 | }) | 111 | message: rd.message.clone(), |
112 | }, | ||
113 | suggested_fix: None, | ||
114 | } | ||
110 | } else { | 115 | } else { |
111 | MappedRustChildDiagnostic::SuggestedFix(lsp_ext::CodeAction { | 116 | MappedRustChildDiagnostic::Related { |
112 | title: rd.message.clone(), | 117 | related: lsp_types::DiagnosticRelatedInformation { |
113 | group: None, | 118 | location: location(workspace_root, spans[0]), |
114 | kind: Some(lsp_types::CodeActionKind::QUICKFIX), | 119 | message: rd.message.clone(), |
115 | edit: Some(lsp_ext::SnippetWorkspaceEdit { | 120 | }, |
116 | // FIXME: there's no good reason to use edit_map here.... | 121 | suggested_fix: Some(lsp_ext::CodeAction { |
117 | changes: Some(edit_map), | 122 | title: rd.message.clone(), |
118 | document_changes: None, | 123 | group: None, |
124 | kind: Some(lsp_types::CodeActionKind::QUICKFIX), | ||
125 | edit: Some(lsp_ext::SnippetWorkspaceEdit { | ||
126 | // FIXME: there's no good reason to use edit_map here.... | ||
127 | changes: Some(edit_map), | ||
128 | document_changes: None, | ||
129 | }), | ||
130 | is_preferred: Some(true), | ||
131 | data: None, | ||
119 | }), | 132 | }), |
120 | is_preferred: Some(true), | 133 | } |
121 | data: None, | ||
122 | }) | ||
123 | } | 134 | } |
124 | } | 135 | } |
125 | 136 | ||
@@ -179,8 +190,12 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
179 | for child in &rd.children { | 190 | for child in &rd.children { |
180 | let child = map_rust_child_diagnostic(workspace_root, &child); | 191 | let child = map_rust_child_diagnostic(workspace_root, &child); |
181 | match child { | 192 | match child { |
182 | MappedRustChildDiagnostic::Related(related) => related_information.push(related), | 193 | MappedRustChildDiagnostic::Related { related, suggested_fix } => { |
183 | MappedRustChildDiagnostic::SuggestedFix(code_action) => fixes.push(code_action), | 194 | related_information.push(related); |
195 | if let Some(code_action) = suggested_fix { | ||
196 | fixes.push(code_action); | ||
197 | } | ||
198 | } | ||
184 | MappedRustChildDiagnostic::MessageLine(message_line) => { | 199 | MappedRustChildDiagnostic::MessageLine(message_line) => { |
185 | format_to!(message, "\n{}", message_line); | 200 | format_to!(message, "\n{}", message_line); |
186 | 201 | ||
@@ -219,7 +234,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
219 | 234 | ||
220 | primary_spans | 235 | primary_spans |
221 | .iter() | 236 | .iter() |
222 | .map(|primary_span| { | 237 | .flat_map(|primary_span| { |
223 | let location = location(workspace_root, &primary_span); | 238 | let location = location(workspace_root, &primary_span); |
224 | 239 | ||
225 | let mut message = message.clone(); | 240 | let mut message = message.clone(); |
@@ -229,72 +244,100 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
229 | } | 244 | } |
230 | } | 245 | } |
231 | 246 | ||
247 | // Each primary diagnostic span may result in multiple LSP diagnostics. | ||
248 | let mut diagnostics = Vec::new(); | ||
249 | |||
250 | let mut related_macro_info = None; | ||
251 | |||
232 | // If error occurs from macro expansion, add related info pointing to | 252 | // If error occurs from macro expansion, add related info pointing to |
233 | // where the error originated | 253 | // where the error originated |
234 | // Also, we would generate an additional diagnostic, so that exact place of macro | 254 | // Also, we would generate an additional diagnostic, so that exact place of macro |
235 | // will be highlighted in the error origin place. | 255 | // will be highlighted in the error origin place. |
236 | let additional_diagnostic = | 256 | if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() { |
237 | if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() { | 257 | let in_macro_location = location_naive(workspace_root, &primary_span); |
238 | let in_macro_location = location_naive(workspace_root, &primary_span); | ||
239 | 258 | ||
240 | // Add related information for the main disagnostic. | 259 | // Add related information for the main disagnostic. |
241 | related_information.push(lsp_types::DiagnosticRelatedInformation { | 260 | related_macro_info = Some(lsp_types::DiagnosticRelatedInformation { |
242 | location: in_macro_location.clone(), | 261 | location: in_macro_location.clone(), |
243 | message: "Error originated from macro here".to_string(), | 262 | message: "Error originated from macro here".to_string(), |
244 | }); | 263 | }); |
245 | 264 | ||
246 | // For the additional in-macro diagnostic we add the inverse message pointing to the error location in code. | 265 | // For the additional in-macro diagnostic we add the inverse message pointing to the error location in code. |
247 | let information_for_additional_diagnostic = | 266 | let information_for_additional_diagnostic = |
248 | vec![lsp_types::DiagnosticRelatedInformation { | 267 | vec![lsp_types::DiagnosticRelatedInformation { |
249 | location: location.clone(), | 268 | location: location.clone(), |
250 | message: "Exact error occured here".to_string(), | 269 | message: "Exact error occurred here".to_string(), |
251 | }]; | 270 | }]; |
252 | 271 | ||
253 | let diagnostic = lsp_types::Diagnostic { | 272 | let diagnostic = lsp_types::Diagnostic { |
254 | range: in_macro_location.range, | 273 | range: in_macro_location.range, |
255 | severity, | 274 | severity, |
256 | code: code.clone().map(lsp_types::NumberOrString::String), | 275 | code: code.clone().map(lsp_types::NumberOrString::String), |
257 | code_description: code_description.clone(), | 276 | code_description: code_description.clone(), |
258 | source: Some(source.clone()), | 277 | source: Some(source.clone()), |
259 | message: message.clone(), | 278 | message: message.clone(), |
260 | related_information: Some(information_for_additional_diagnostic), | 279 | related_information: Some(information_for_additional_diagnostic), |
261 | tags: if tags.is_empty() { None } else { Some(tags.clone()) }, | 280 | tags: if tags.is_empty() { None } else { Some(tags.clone()) }, |
262 | data: None, | 281 | data: None, |
263 | }; | ||
264 | |||
265 | Some(MappedRustDiagnostic { | ||
266 | url: in_macro_location.uri, | ||
267 | diagnostic, | ||
268 | fixes: fixes.clone(), | ||
269 | }) | ||
270 | } else { | ||
271 | None | ||
272 | }; | 282 | }; |
273 | 283 | ||
274 | let diagnostic = lsp_types::Diagnostic { | 284 | diagnostics.push(MappedRustDiagnostic { |
275 | range: location.range, | 285 | url: in_macro_location.uri, |
276 | severity, | 286 | diagnostic, |
277 | code: code.clone().map(lsp_types::NumberOrString::String), | 287 | fixes: fixes.clone(), |
278 | code_description: code_description.clone(), | 288 | }); |
279 | source: Some(source.clone()), | 289 | } |
280 | message, | 290 | |
281 | related_information: if related_information.is_empty() { | 291 | // Emit the primary diagnostic. |
282 | None | 292 | diagnostics.push(MappedRustDiagnostic { |
283 | } else { | 293 | url: location.uri.clone(), |
284 | Some(related_information.clone()) | 294 | diagnostic: lsp_types::Diagnostic { |
295 | range: location.range, | ||
296 | severity, | ||
297 | code: code.clone().map(lsp_types::NumberOrString::String), | ||
298 | code_description: code_description.clone(), | ||
299 | source: Some(source.clone()), | ||
300 | message, | ||
301 | related_information: if related_information.is_empty() { | ||
302 | None | ||
303 | } else { | ||
304 | let mut related = related_information.clone(); | ||
305 | related.extend(related_macro_info); | ||
306 | Some(related) | ||
307 | }, | ||
308 | tags: if tags.is_empty() { None } else { Some(tags.clone()) }, | ||
309 | data: None, | ||
285 | }, | 310 | }, |
286 | tags: if tags.is_empty() { None } else { Some(tags.clone()) }, | 311 | fixes: fixes.clone(), |
287 | data: None, | 312 | }); |
288 | }; | ||
289 | 313 | ||
290 | let main_diagnostic = | 314 | // Emit hint-level diagnostics for all `related_information` entries such as "help"s. |
291 | MappedRustDiagnostic { url: location.uri, diagnostic, fixes: fixes.clone() }; | 315 | // This is useful because they will show up in the user's editor, unlike |
292 | match additional_diagnostic { | 316 | // `related_information`, which just produces hard-to-read links, at least in VS Code. |
293 | None => vec![main_diagnostic], | 317 | let back_ref = lsp_types::DiagnosticRelatedInformation { |
294 | Some(additional_diagnostic) => vec![main_diagnostic, additional_diagnostic], | 318 | location, |
319 | message: "original diagnostic".to_string(), | ||
320 | }; | ||
321 | for info in &related_information { | ||
322 | diagnostics.push(MappedRustDiagnostic { | ||
323 | url: info.location.uri.clone(), | ||
324 | fixes: fixes.clone(), // share fixes to make them easier to apply | ||
325 | diagnostic: lsp_types::Diagnostic { | ||
326 | range: info.location.range, | ||
327 | severity: Some(lsp_types::DiagnosticSeverity::Hint), | ||
328 | code: code.clone().map(lsp_types::NumberOrString::String), | ||
329 | code_description: code_description.clone(), | ||
330 | source: Some(source.clone()), | ||
331 | message: info.message.clone(), | ||
332 | related_information: Some(vec![back_ref.clone()]), | ||
333 | tags: None, // don't apply modifiers again | ||
334 | data: None, | ||
335 | }, | ||
336 | }); | ||
295 | } | 337 | } |
338 | |||
339 | diagnostics | ||
296 | }) | 340 | }) |
297 | .flatten() | ||
298 | .collect() | 341 | .collect() |
299 | } | 342 | } |
300 | 343 | ||