From 637c795b3c9a56795977ade0cedbc7a9fb7dc453 Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Thu, 12 Mar 2020 15:01:53 +0100 Subject: Correctly handle multi-line fixes from cargo/clippy --- crates/ra_cargo_watch/src/conv.rs | 47 ++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 28 deletions(-) (limited to 'crates/ra_cargo_watch/src/conv.rs') diff --git a/crates/ra_cargo_watch/src/conv.rs b/crates/ra_cargo_watch/src/conv.rs index 0246adfb5..a3f05bede 100644 --- a/crates/ra_cargo_watch/src/conv.rs +++ b/crates/ra_cargo_watch/src/conv.rs @@ -8,6 +8,7 @@ use lsp_types::{ Location, NumberOrString, Position, Range, TextEdit, Url, WorkspaceEdit, }; use std::{ + collections::HashMap, fmt::Write, path::{Component, Path, PathBuf, Prefix}, str::FromStr, @@ -126,44 +127,34 @@ fn map_rust_child_diagnostic( rd: &RustDiagnostic, workspace_root: &PathBuf, ) -> MappedRustChildDiagnostic { - let span: &DiagnosticSpan = match rd.spans.iter().find(|s| s.is_primary) { - Some(span) => span, - None => { - // `rustc` uses these spanless children as a way to print multi-line - // messages - return MappedRustChildDiagnostic::MessageLine(rd.message.clone()); - } - }; - - // If we have a primary span use its location, otherwise use the parent - let location = map_span_to_location(&span, workspace_root); - - if let Some(suggested_replacement) = &span.suggested_replacement { - // Include our replacement in the title unless it's empty - let title = if !suggested_replacement.is_empty() { - format!("{}: '{}'", rd.message, suggested_replacement) - } else { - rd.message.clone() - }; + let spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect(); + if spans.is_empty() { + // `rustc` uses these spanless children as a way to print multi-line + // messages + return MappedRustChildDiagnostic::MessageLine(rd.message.clone()); + } - let edit = { - let edits = vec![TextEdit::new(location.range, suggested_replacement.clone())]; - let mut edit_map = std::collections::HashMap::new(); - edit_map.insert(location.uri, edits); - WorkspaceEdit::new(edit_map) - }; + let mut edit_map: HashMap> = HashMap::new(); + for &span in &spans { + if let Some(suggested_replacement) = &span.suggested_replacement { + let location = map_span_to_location(span, workspace_root); + let edit = TextEdit::new(location.range, suggested_replacement.clone()); + edit_map.entry(location.uri).or_default().push(edit); + } + } + if !edit_map.is_empty() { MappedRustChildDiagnostic::SuggestedFix(CodeAction { - title, + title: rd.message.clone(), kind: Some("quickfix".to_string()), diagnostics: None, - edit: Some(edit), + edit: Some(WorkspaceEdit::new(edit_map)), command: None, is_preferred: None, }) } else { MappedRustChildDiagnostic::Related(DiagnosticRelatedInformation { - location, + location: map_span_to_location(spans[0], workspace_root), message: rd.message.clone(), }) } -- cgit v1.2.3 From 98e8ad5e608b739d1d28a43c8c69358e77c1c1f0 Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Thu, 12 Mar 2020 15:24:20 +0100 Subject: Handle diagnostics with multiple primary spans --- crates/ra_cargo_watch/src/conv.rs | 81 ++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 35 deletions(-) (limited to 'crates/ra_cargo_watch/src/conv.rs') diff --git a/crates/ra_cargo_watch/src/conv.rs b/crates/ra_cargo_watch/src/conv.rs index a3f05bede..c6f8ca329 100644 --- a/crates/ra_cargo_watch/src/conv.rs +++ b/crates/ra_cargo_watch/src/conv.rs @@ -180,13 +180,13 @@ pub(crate) struct MappedRustDiagnostic { pub(crate) fn map_rust_diagnostic_to_lsp( rd: &RustDiagnostic, workspace_root: &PathBuf, -) -> Option { - let primary_span = rd.spans.iter().find(|s| s.is_primary)?; - - let location = map_span_to_location(&primary_span, workspace_root); +) -> Vec { + let primary_spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect(); + if primary_spans.is_empty() { + return vec![]; + } let severity = map_level_to_severity(rd.level); - let mut primary_span_label = primary_span.label.as_ref(); let mut source = String::from("rustc"); let mut code = rd.code.as_ref().map(|c| c.code.clone()); @@ -199,19 +199,10 @@ pub(crate) fn map_rust_diagnostic_to_lsp( } } + let mut needs_primary_span_label = true; let mut related_information = vec![]; let mut tags = vec![]; - // If error occurs from macro expansion, add related info pointing to - // where the error originated - if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() { - let def_loc = map_span_to_location_naive(&primary_span, workspace_root); - related_information.push(DiagnosticRelatedInformation { - location: def_loc, - message: "Error originated from macro here".to_string(), - }); - } - for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) { let related = map_secondary_span_to_related(secondary_span, workspace_root); if let Some(related) = related { @@ -231,15 +222,11 @@ pub(crate) fn map_rust_diagnostic_to_lsp( // These secondary messages usually duplicate the content of the // primary span label. - primary_span_label = None; + needs_primary_span_label = false; } } } - if let Some(primary_span_label) = primary_span_label { - write!(&mut message, "\n{}", primary_span_label).unwrap(); - } - if is_unused_or_unnecessary(rd) { tags.push(DiagnosticTag::Unnecessary); } @@ -248,21 +235,45 @@ pub(crate) fn map_rust_diagnostic_to_lsp( tags.push(DiagnosticTag::Deprecated); } - let diagnostic = Diagnostic { - range: location.range, - severity, - code: code.map(NumberOrString::String), - source: Some(source), - message, - related_information: if !related_information.is_empty() { - Some(related_information) - } else { - None - }, - tags: if !tags.is_empty() { Some(tags) } else { None }, - }; - - Some(MappedRustDiagnostic { location, diagnostic, fixes }) + primary_spans + .iter() + .map(|primary_span| { + let location = map_span_to_location(&primary_span, workspace_root); + + let mut message = message.clone(); + if needs_primary_span_label { + if let Some(primary_span_label) = &primary_span.label { + write!(&mut message, "\n{}", primary_span_label).unwrap(); + } + } + + // If error occurs from macro expansion, add related info pointing to + // where the error originated + if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() { + let def_loc = map_span_to_location_naive(&primary_span, workspace_root); + related_information.push(DiagnosticRelatedInformation { + location: def_loc, + message: "Error originated from macro here".to_string(), + }); + } + + let diagnostic = Diagnostic { + range: location.range, + severity, + code: code.clone().map(NumberOrString::String), + source: Some(source.clone()), + message, + related_information: if !related_information.is_empty() { + Some(related_information.clone()) + } else { + None + }, + tags: if !tags.is_empty() { Some(tags.clone()) } else { None }, + }; + + MappedRustDiagnostic { location, diagnostic, fixes: fixes.clone() } + }) + .collect() } /// Returns a `Url` object from a given path, will lowercase drive letters if present. -- cgit v1.2.3