5956: Highlight errors in macros r=jonas-schievink a=popzxc

Resolves #4924 

This PR makes rust-analyzer highlight not only the source place when error originates in macro, but also the exact places in macro which caused an error.

This is done by creating an inverse diagnostic, which points to the macro and cross-references the source place.

![изображение](https://user-images.githubusercontent.com/12111581/92319594-b71e6c00-f022-11ea-94c1-f412905269dd.png)


Co-authored-by: Igor Aleksanov <popzxc@yandex.ru>
This commit is contained in:
bors[bot] 2020-09-10 20:55:06 +00:00 committed by GitHub
commit 868f4b5756
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 7 deletions

View File

@ -44,4 +44,49 @@
},
fixes: [],
},
MappedRustDiagnostic {
url: "file:///test/crates/hir_def/src/path.rs",
diagnostic: Diagnostic {
range: Range {
start: Position {
line: 264,
character: 8,
},
end: Position {
line: 264,
character: 76,
},
},
severity: Some(
Error,
),
code: None,
source: Some(
"rustc",
),
message: "Please register your known path in the path module",
related_information: Some(
[
DiagnosticRelatedInformation {
location: Location {
uri: "file:///test/crates/hir_def/src/data.rs",
range: Range {
start: Position {
line: 79,
character: 15,
},
end: Position {
line: 79,
character: 41,
},
},
},
message: "Exact error occured here",
},
],
),
tags: None,
},
fixes: [],
},
]

View File

@ -225,12 +225,43 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
// 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() {
related_information.push(lsp_types::DiagnosticRelatedInformation {
location: location_naive(workspace_root, &primary_span),
message: "Error originated from macro here".to_string(),
});
}
// Also, we would generate an additional diagnostic, so that exact place of macro
// will be highlighted in the error origin place.
let additional_diagnostic =
if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() {
let in_macro_location = location_naive(workspace_root, &primary_span);
// Add related information for the main disagnostic.
related_information.push(lsp_types::DiagnosticRelatedInformation {
location: in_macro_location.clone(),
message: "Error originated from macro here".to_string(),
});
// For the additional in-macro diagnostic we add the inverse message pointing to the error location in code.
let information_for_additional_diagnostic =
vec![lsp_types::DiagnosticRelatedInformation {
location: location.clone(),
message: "Exact error occured here".to_string(),
}];
let diagnostic = lsp_types::Diagnostic {
range: in_macro_location.range,
severity,
code: code.clone().map(lsp_types::NumberOrString::String),
source: Some(source.clone()),
message: message.clone(),
related_information: Some(information_for_additional_diagnostic),
tags: if tags.is_empty() { None } else { Some(tags.clone()) },
};
Some(MappedRustDiagnostic {
url: in_macro_location.uri,
diagnostic,
fixes: fixes.clone(),
})
} else {
None
};
let diagnostic = lsp_types::Diagnostic {
range: location.range,
@ -246,8 +277,14 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
tags: if tags.is_empty() { None } else { Some(tags.clone()) },
};
MappedRustDiagnostic { url: location.uri, diagnostic, fixes: fixes.clone() }
let main_diagnostic =
MappedRustDiagnostic { url: location.uri, diagnostic, fixes: fixes.clone() };
match additional_diagnostic {
None => vec![main_diagnostic],
Some(additional_diagnostic) => vec![main_diagnostic, additional_diagnostic],
}
})
.flatten()
.collect()
}