aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_cargo_watch/src/conv.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_cargo_watch/src/conv.rs')
-rw-r--r--crates/ra_cargo_watch/src/conv.rs128
1 files changed, 65 insertions, 63 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.