aboutsummaryrefslogtreecommitdiff
path: root/crates/rust-analyzer/src/diagnostics
diff options
context:
space:
mode:
authorJames Leitch <[email protected]>2021-04-21 04:03:35 +0100
committerJames Leitch <[email protected]>2021-04-21 23:10:53 +0100
commit9fcad829807a0306fbf4eb2ebc1603a11a6df182 (patch)
treea91162aed471e8b8bb8d80ed2dfcb7aaeb64acfd /crates/rust-analyzer/src/diagnostics
parent60841f42769b154864252b04d622494a9ddfc696 (diff)
Diagnostic Remap Path Prefixes added.
Diffstat (limited to 'crates/rust-analyzer/src/diagnostics')
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs67
1 files changed, 32 insertions, 35 deletions
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs
index 8b01a7e5d..08303a781 100644
--- a/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -44,8 +44,12 @@ fn is_dummy_macro_file(file_name: &str) -> bool {
44} 44}
45 45
46/// Converts a Rust span to a LSP location 46/// Converts a Rust span to a LSP location
47fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location { 47fn location(
48 let file_name = resolve_path(workspace_root, &span.file_name); 48 config: &DiagnosticsMapConfig,
49 workspace_root: &Path,
50 span: &DiagnosticSpan,
51) -> lsp_types::Location {
52 let file_name = resolve_path(config, workspace_root, &span.file_name);
49 let uri = url_from_abs_path(&file_name); 53 let uri = url_from_abs_path(&file_name);
50 54
51 // FIXME: this doesn't handle UTF16 offsets correctly 55 // FIXME: this doesn't handle UTF16 offsets correctly
@@ -61,54 +65,46 @@ fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location
61/// 65///
62/// This takes locations pointing into the standard library, or generally outside the current 66/// This takes locations pointing into the standard library, or generally outside the current
63/// workspace into account and tries to avoid those, in case macros are involved. 67/// workspace into account and tries to avoid those, in case macros are involved.
64fn primary_location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location { 68fn primary_location(
69 config: &DiagnosticsMapConfig,
70 workspace_root: &Path,
71 span: &DiagnosticSpan,
72) -> lsp_types::Location {
65 let span_stack = std::iter::successors(Some(span), |span| Some(&span.expansion.as_ref()?.span)); 73 let span_stack = std::iter::successors(Some(span), |span| Some(&span.expansion.as_ref()?.span));
66 for span in span_stack.clone() { 74 for span in span_stack.clone() {
67 let abs_path = resolve_path(workspace_root, &span.file_name); 75 let abs_path = resolve_path(config, workspace_root, &span.file_name);
68 if !is_dummy_macro_file(&span.file_name) && abs_path.starts_with(workspace_root) { 76 if !is_dummy_macro_file(&span.file_name) && abs_path.starts_with(workspace_root) {
69 return location(workspace_root, span); 77 return location(config, workspace_root, span);
70 } 78 }
71 } 79 }
72 80
73 // Fall back to the outermost macro invocation if no suitable span comes up. 81 // Fall back to the outermost macro invocation if no suitable span comes up.
74 let last_span = span_stack.last().unwrap(); 82 let last_span = span_stack.last().unwrap();
75 location(workspace_root, last_span) 83 location(config, workspace_root, last_span)
76} 84}
77 85
78/// Converts a secondary Rust span to a LSP related information 86/// Converts a secondary Rust span to a LSP related information
79/// 87///
80/// If the span is unlabelled this will return `None`. 88/// If the span is unlabelled this will return `None`.
81fn diagnostic_related_information( 89fn diagnostic_related_information(
90 config: &DiagnosticsMapConfig,
82 workspace_root: &Path, 91 workspace_root: &Path,
83 span: &DiagnosticSpan, 92 span: &DiagnosticSpan,
84) -> Option<lsp_types::DiagnosticRelatedInformation> { 93) -> Option<lsp_types::DiagnosticRelatedInformation> {
85 let message = span.label.clone()?; 94 let message = span.label.clone()?;
86 let location = location(workspace_root, span); 95 let location = location(config, workspace_root, span);
87 Some(lsp_types::DiagnosticRelatedInformation { location, message }) 96 Some(lsp_types::DiagnosticRelatedInformation { location, message })
88} 97}
89 98
90/// Resolves paths mimicking VSCode's behavior when `file_name` starts 99/// Resolves paths applying any matching path prefix remappings, and then
91/// with the root directory component, which does not discard the base 100/// joining the path to the workspace root.
92/// path. If this relative path exists, use it, otherwise fall back 101fn resolve_path(config: &DiagnosticsMapConfig, workspace_root: &Path, file_name: &str) -> PathBuf {
93/// to the existing Rust behavior of path joining. 102 match config.remap_path_prefixes.iter().find(|(from, _)| file_name.starts_with(*from)) {
94fn resolve_path(workspace_root: &Path, file_name: &str) -> PathBuf { 103 Some((from, to)) => {
95 let file_name = Path::new(file_name); 104 workspace_root.join(format!("{}{}", to, file_name.strip_prefix(from).unwrap()))
96 105 }
97 // Test path with VSCode's path join behavior. 106 None => workspace_root.join(file_name),
98 let vscode_path = {
99 let mut result = PathBuf::from(workspace_root);
100 result.extend(file_name.components().skip_while(|component| match component {
101 std::path::Component::RootDir => true,
102 _ => false,
103 }));
104 result
105 };
106 if vscode_path.exists() {
107 return vscode_path;
108 } 107 }
109
110 // Default to Rust's path join behavior.
111 workspace_root.join(file_name)
112} 108}
113 109
114struct SubDiagnostic { 110struct SubDiagnostic {
@@ -122,6 +118,7 @@ enum MappedRustChildDiagnostic {
122} 118}
123 119
124fn map_rust_child_diagnostic( 120fn map_rust_child_diagnostic(
121 config: &DiagnosticsMapConfig,
125 workspace_root: &Path, 122 workspace_root: &Path,
126 rd: &flycheck::Diagnostic, 123 rd: &flycheck::Diagnostic,
127) -> MappedRustChildDiagnostic { 124) -> MappedRustChildDiagnostic {
@@ -135,7 +132,7 @@ fn map_rust_child_diagnostic(
135 let mut edit_map: HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>> = HashMap::new(); 132 let mut edit_map: HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>> = HashMap::new();
136 for &span in &spans { 133 for &span in &spans {
137 if let Some(suggested_replacement) = &span.suggested_replacement { 134 if let Some(suggested_replacement) = &span.suggested_replacement {
138 let location = location(workspace_root, span); 135 let location = location(config, workspace_root, span);
139 let edit = lsp_types::TextEdit::new(location.range, suggested_replacement.clone()); 136 let edit = lsp_types::TextEdit::new(location.range, suggested_replacement.clone());
140 edit_map.entry(location.uri).or_default().push(edit); 137 edit_map.entry(location.uri).or_default().push(edit);
141 } 138 }
@@ -144,7 +141,7 @@ fn map_rust_child_diagnostic(
144 if edit_map.is_empty() { 141 if edit_map.is_empty() {
145 MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic { 142 MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic {
146 related: lsp_types::DiagnosticRelatedInformation { 143 related: lsp_types::DiagnosticRelatedInformation {
147 location: location(workspace_root, spans[0]), 144 location: location(config, workspace_root, spans[0]),
148 message: rd.message.clone(), 145 message: rd.message.clone(),
149 }, 146 },
150 suggested_fix: None, 147 suggested_fix: None,
@@ -152,7 +149,7 @@ fn map_rust_child_diagnostic(
152 } else { 149 } else {
153 MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic { 150 MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic {
154 related: lsp_types::DiagnosticRelatedInformation { 151 related: lsp_types::DiagnosticRelatedInformation {
155 location: location(workspace_root, spans[0]), 152 location: location(config, workspace_root, spans[0]),
156 message: rd.message.clone(), 153 message: rd.message.clone(),
157 }, 154 },
158 suggested_fix: Some(lsp_ext::CodeAction { 155 suggested_fix: Some(lsp_ext::CodeAction {
@@ -217,7 +214,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
217 let mut tags = Vec::new(); 214 let mut tags = Vec::new();
218 215
219 for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) { 216 for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) {
220 let related = diagnostic_related_information(workspace_root, secondary_span); 217 let related = diagnostic_related_information(config, workspace_root, secondary_span);
221 if let Some(related) = related { 218 if let Some(related) = related {
222 subdiagnostics.push(SubDiagnostic { related, suggested_fix: None }); 219 subdiagnostics.push(SubDiagnostic { related, suggested_fix: None });
223 } 220 }
@@ -225,7 +222,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
225 222
226 let mut message = rd.message.clone(); 223 let mut message = rd.message.clone();
227 for child in &rd.children { 224 for child in &rd.children {
228 let child = map_rust_child_diagnostic(workspace_root, &child); 225 let child = map_rust_child_diagnostic(config, workspace_root, &child);
229 match child { 226 match child {
230 MappedRustChildDiagnostic::SubDiagnostic(sub) => { 227 MappedRustChildDiagnostic::SubDiagnostic(sub) => {
231 subdiagnostics.push(sub); 228 subdiagnostics.push(sub);
@@ -269,7 +266,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
269 primary_spans 266 primary_spans
270 .iter() 267 .iter()
271 .flat_map(|primary_span| { 268 .flat_map(|primary_span| {
272 let primary_location = primary_location(workspace_root, &primary_span); 269 let primary_location = primary_location(config, workspace_root, &primary_span);
273 270
274 let mut message = message.clone(); 271 let mut message = message.clone();
275 if needs_primary_span_label { 272 if needs_primary_span_label {
@@ -299,7 +296,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
299 // generated that code. 296 // generated that code.
300 let is_in_macro_call = i != 0; 297 let is_in_macro_call = i != 0;
301 298
302 let secondary_location = location(workspace_root, &span); 299 let secondary_location = location(config, workspace_root, &span);
303 if secondary_location == primary_location { 300 if secondary_location == primary_location {
304 continue; 301 continue;
305 } 302 }