Warnings as hint or info

This commit is contained in:
Gabriel Valfridsson 2020-06-16 22:26:33 +02:00
parent 5d7974e5fb
commit 656e95211e
7 changed files with 402 additions and 13 deletions

View file

@ -9,6 +9,7 @@
use std::{ffi::OsString, path::PathBuf}; use std::{ffi::OsString, path::PathBuf};
use crate::diagnostics::DiagnosticsConfig;
use lsp_types::ClientCapabilities; use lsp_types::ClientCapabilities;
use ra_flycheck::FlycheckConfig; use ra_flycheck::FlycheckConfig;
use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig}; use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig};
@ -20,6 +21,7 @@ pub struct Config {
pub client_caps: ClientCapsConfig, pub client_caps: ClientCapsConfig,
pub publish_diagnostics: bool, pub publish_diagnostics: bool,
pub diagnostics: DiagnosticsConfig,
pub lru_capacity: Option<usize>, pub lru_capacity: Option<usize>,
pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>, pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>,
pub files: FilesConfig, pub files: FilesConfig,
@ -136,6 +138,7 @@ impl Default for Config {
with_sysroot: true, with_sysroot: true,
publish_diagnostics: true, publish_diagnostics: true,
diagnostics: DiagnosticsConfig::default(),
lru_capacity: None, lru_capacity: None,
proc_macro_srv: None, proc_macro_srv: None,
files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() }, files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() },
@ -184,6 +187,8 @@ impl Config {
set(value, "/withSysroot", &mut self.with_sysroot); set(value, "/withSysroot", &mut self.with_sysroot);
set(value, "/diagnostics/enable", &mut self.publish_diagnostics); set(value, "/diagnostics/enable", &mut self.publish_diagnostics);
set(value, "/diagnostics/warningsAsInfo", &mut self.diagnostics.warnings_as_info);
set(value, "/diagnostics/warningsAsHint", &mut self.diagnostics.warnings_as_hint);
set(value, "/lruCapacity", &mut self.lru_capacity); set(value, "/lruCapacity", &mut self.lru_capacity);
self.files.watcher = match get(value, "/files/watcher") { self.files.watcher = match get(value, "/files/watcher") {
Some("client") => FilesWatcher::Client, Some("client") => FilesWatcher::Client,

View file

@ -10,6 +10,12 @@ use crate::lsp_ext;
pub type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>; pub type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>;
#[derive(Debug, Default, Clone)]
pub struct DiagnosticsConfig {
pub warnings_as_info: Vec<String>,
pub warnings_as_hint: Vec<String>,
}
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct DiagnosticCollection { pub struct DiagnosticCollection {
pub native: HashMap<FileId, Vec<Diagnostic>>, pub native: HashMap<FileId, Vec<Diagnostic>>,

View file

@ -0,0 +1,86 @@
---
source: crates/rust-analyzer/src/diagnostics/to_proto.rs
expression: diag
---
[
MappedRustDiagnostic {
location: Location {
uri: "file:///test/driver/subcommand/repl.rs",
range: Range {
start: Position {
line: 290,
character: 8,
},
end: Position {
line: 290,
character: 11,
},
},
},
diagnostic: Diagnostic {
range: Range {
start: Position {
line: 290,
character: 8,
},
end: Position {
line: 290,
character: 11,
},
},
severity: Some(
Hint,
),
code: Some(
String(
"unused_variables",
),
),
source: Some(
"rustc",
),
message: "unused variable: `foo`\n#[warn(unused_variables)] on by default",
related_information: None,
tags: Some(
[
Unnecessary,
],
),
},
fixes: [
CodeAction {
title: "consider prefixing with an underscore",
id: None,
group: None,
kind: Some(
"quickfix",
),
command: None,
edit: Some(
SnippetWorkspaceEdit {
changes: Some(
{
"file:///test/driver/subcommand/repl.rs": [
TextEdit {
range: Range {
start: Position {
line: 290,
character: 8,
},
end: Position {
line: 290,
character: 11,
},
},
new_text: "_foo",
},
],
},
),
document_changes: None,
},
),
},
],
},
]

View file

@ -0,0 +1,86 @@
---
source: crates/rust-analyzer/src/diagnostics/to_proto.rs
expression: diag
---
[
MappedRustDiagnostic {
location: Location {
uri: "file:///test/driver/subcommand/repl.rs",
range: Range {
start: Position {
line: 290,
character: 8,
},
end: Position {
line: 290,
character: 11,
},
},
},
diagnostic: Diagnostic {
range: Range {
start: Position {
line: 290,
character: 8,
},
end: Position {
line: 290,
character: 11,
},
},
severity: Some(
Information,
),
code: Some(
String(
"unused_variables",
),
),
source: Some(
"rustc",
),
message: "unused variable: `foo`\n#[warn(unused_variables)] on by default",
related_information: None,
tags: Some(
[
Unnecessary,
],
),
},
fixes: [
CodeAction {
title: "consider prefixing with an underscore",
id: None,
group: None,
kind: Some(
"quickfix",
),
command: None,
edit: Some(
SnippetWorkspaceEdit {
changes: Some(
{
"file:///test/driver/subcommand/repl.rs": [
TextEdit {
range: Range {
start: Position {
line: 290,
character: 8,
},
end: Position {
line: 290,
character: 11,
},
},
new_text: "_foo",
},
],
},
),
document_changes: None,
},
),
},
],
},
]

View file

@ -9,14 +9,24 @@ use lsp_types::{
use ra_flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion}; use ra_flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion};
use stdx::format_to; use stdx::format_to;
use super::DiagnosticsConfig;
use crate::{lsp_ext, to_proto::url_from_abs_path}; use crate::{lsp_ext, to_proto::url_from_abs_path};
/// Converts a Rust level string to a LSP severity /// Determines the LSP severity from a diagnostic
fn map_level_to_severity(val: DiagnosticLevel) -> Option<DiagnosticSeverity> { fn map_diagnostic_to_severity(
let res = match val { config: &DiagnosticsConfig,
val: &ra_flycheck::Diagnostic,
) -> Option<DiagnosticSeverity> {
let res = match val.level {
DiagnosticLevel::Ice => DiagnosticSeverity::Error, DiagnosticLevel::Ice => DiagnosticSeverity::Error,
DiagnosticLevel::Error => DiagnosticSeverity::Error, DiagnosticLevel::Error => DiagnosticSeverity::Error,
DiagnosticLevel::Warning => DiagnosticSeverity::Warning, DiagnosticLevel::Warning => match &val.code {
Some(code) if config.warnings_as_hint.contains(&code.code) => DiagnosticSeverity::Hint,
Some(code) if config.warnings_as_info.contains(&code.code) => {
DiagnosticSeverity::Information
}
_ => DiagnosticSeverity::Warning,
},
DiagnosticLevel::Note => DiagnosticSeverity::Information, DiagnosticLevel::Note => DiagnosticSeverity::Information,
DiagnosticLevel::Help => DiagnosticSeverity::Hint, DiagnosticLevel::Help => DiagnosticSeverity::Hint,
DiagnosticLevel::Unknown => return None, DiagnosticLevel::Unknown => return None,
@ -172,6 +182,7 @@ pub(crate) struct MappedRustDiagnostic {
/// ///
/// If the diagnostic has no primary span this will return `None` /// If the diagnostic has no primary span this will return `None`
pub(crate) fn map_rust_diagnostic_to_lsp( pub(crate) fn map_rust_diagnostic_to_lsp(
config: &DiagnosticsConfig,
rd: &ra_flycheck::Diagnostic, rd: &ra_flycheck::Diagnostic,
workspace_root: &Path, workspace_root: &Path,
) -> Vec<MappedRustDiagnostic> { ) -> Vec<MappedRustDiagnostic> {
@ -180,7 +191,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
return Vec::new(); return Vec::new();
} }
let severity = map_level_to_severity(rd.level); let severity = map_diagnostic_to_severity(config, rd);
let mut source = String::from("rustc"); let mut source = String::from("rustc");
let mut code = rd.code.as_ref().map(|c| c.code.clone()); let mut code = rd.code.as_ref().map(|c| c.code.clone());
@ -328,7 +339,7 @@ mod tests {
); );
let workspace_root = Path::new("/test/"); let workspace_root = Path::new("/test/");
let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
insta::assert_debug_snapshot!(diag); insta::assert_debug_snapshot!(diag);
} }
@ -410,7 +421,183 @@ mod tests {
); );
let workspace_root = Path::new("/test/"); let workspace_root = Path::new("/test/");
let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
insta::assert_debug_snapshot!(diag);
}
#[test]
#[cfg(not(windows))]
fn snap_rustc_unused_variable_as_info() {
let diag = parse_diagnostic(
r##"{
"message": "unused variable: `foo`",
"code": {
"code": "unused_variables",
"explanation": null
},
"level": "warning",
"spans": [
{
"file_name": "driver/subcommand/repl.rs",
"byte_start": 9228,
"byte_end": 9231,
"line_start": 291,
"line_end": 291,
"column_start": 9,
"column_end": 12,
"is_primary": true,
"text": [
{
"text": " let foo = 42;",
"highlight_start": 9,
"highlight_end": 12
}
],
"label": null,
"suggested_replacement": null,
"suggestion_applicability": null,
"expansion": null
}
],
"children": [
{
"message": "#[warn(unused_variables)] on by default",
"code": null,
"level": "note",
"spans": [],
"children": [],
"rendered": null
},
{
"message": "consider prefixing with an underscore",
"code": null,
"level": "help",
"spans": [
{
"file_name": "driver/subcommand/repl.rs",
"byte_start": 9228,
"byte_end": 9231,
"line_start": 291,
"line_end": 291,
"column_start": 9,
"column_end": 12,
"is_primary": true,
"text": [
{
"text": " let foo = 42;",
"highlight_start": 9,
"highlight_end": 12
}
],
"label": null,
"suggested_replacement": "_foo",
"suggestion_applicability": "MachineApplicable",
"expansion": null
}
],
"children": [],
"rendered": null
}
],
"rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n"
}"##,
);
let config = DiagnosticsConfig {
warnings_as_info: vec!["unused_variables".to_string()],
..DiagnosticsConfig::default()
};
let workspace_root = Path::new("/test/");
let diag = map_rust_diagnostic_to_lsp(&config, &diag, workspace_root);
insta::assert_debug_snapshot!(diag);
}
#[test]
#[cfg(not(windows))]
fn snap_rustc_unused_variable_as_hint() {
let diag = parse_diagnostic(
r##"{
"message": "unused variable: `foo`",
"code": {
"code": "unused_variables",
"explanation": null
},
"level": "warning",
"spans": [
{
"file_name": "driver/subcommand/repl.rs",
"byte_start": 9228,
"byte_end": 9231,
"line_start": 291,
"line_end": 291,
"column_start": 9,
"column_end": 12,
"is_primary": true,
"text": [
{
"text": " let foo = 42;",
"highlight_start": 9,
"highlight_end": 12
}
],
"label": null,
"suggested_replacement": null,
"suggestion_applicability": null,
"expansion": null
}
],
"children": [
{
"message": "#[warn(unused_variables)] on by default",
"code": null,
"level": "note",
"spans": [],
"children": [],
"rendered": null
},
{
"message": "consider prefixing with an underscore",
"code": null,
"level": "help",
"spans": [
{
"file_name": "driver/subcommand/repl.rs",
"byte_start": 9228,
"byte_end": 9231,
"line_start": 291,
"line_end": 291,
"column_start": 9,
"column_end": 12,
"is_primary": true,
"text": [
{
"text": " let foo = 42;",
"highlight_start": 9,
"highlight_end": 12
}
],
"label": null,
"suggested_replacement": "_foo",
"suggestion_applicability": "MachineApplicable",
"expansion": null
}
],
"children": [],
"rendered": null
}
],
"rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n"
}"##,
);
let config = DiagnosticsConfig {
warnings_as_hint: vec!["unused_variables".to_string()],
..DiagnosticsConfig::default()
};
let workspace_root = Path::new("/test/");
let diag = map_rust_diagnostic_to_lsp(&config, &diag, workspace_root);
insta::assert_debug_snapshot!(diag); insta::assert_debug_snapshot!(diag);
} }
@ -534,7 +721,7 @@ mod tests {
); );
let workspace_root = Path::new("/test/"); let workspace_root = Path::new("/test/");
let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
insta::assert_debug_snapshot!(diag); insta::assert_debug_snapshot!(diag);
} }
@ -654,7 +841,7 @@ mod tests {
); );
let workspace_root = Path::new("/test/"); let workspace_root = Path::new("/test/");
let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
insta::assert_debug_snapshot!(diag); insta::assert_debug_snapshot!(diag);
} }
@ -697,7 +884,7 @@ mod tests {
); );
let workspace_root = Path::new("/test/"); let workspace_root = Path::new("/test/");
let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
insta::assert_debug_snapshot!(diag); insta::assert_debug_snapshot!(diag);
} }
@ -968,7 +1155,7 @@ mod tests {
); );
let workspace_root = Path::new("/test/"); let workspace_root = Path::new("/test/");
let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
insta::assert_debug_snapshot!(diag); insta::assert_debug_snapshot!(diag);
} }
@ -1197,7 +1384,7 @@ mod tests {
); );
let workspace_root = Path::new("/test/"); let workspace_root = Path::new("/test/");
let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
insta::assert_debug_snapshot!(diag); insta::assert_debug_snapshot!(diag);
} }
@ -1330,7 +1517,7 @@ mod tests {
); );
let workspace_root = Path::new("/test/"); let workspace_root = Path::new("/test/");
let diag = map_rust_diagnostic_to_lsp(&diag, workspace_root); let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
insta::assert_debug_snapshot!(diag); insta::assert_debug_snapshot!(diag);
} }
} }

View file

@ -734,6 +734,7 @@ fn on_check_task(
CheckTask::AddDiagnostic { workspace_root, diagnostic } => { CheckTask::AddDiagnostic { workspace_root, diagnostic } => {
let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
&global_state.config.diagnostics,
&diagnostic, &diagnostic,
&workspace_root, &workspace_root,
); );

View file

@ -525,6 +525,24 @@
"markdownDescription": "Internal config for debugging, disables loading of sysroot crates", "markdownDescription": "Internal config for debugging, disables loading of sysroot crates",
"type": "boolean", "type": "boolean",
"default": true "default": true
},
"rust-analyzer.diagnostics.warningsAsInfo": {
"type": "array",
"uniqueItems": true,
"items": {
"type": "string"
},
"description": "List of warnings that should be displayed with info severity.\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the problems panel.",
"default": []
},
"rust-analyzer.diagnostics.warningsAsHint": {
"type": "array",
"uniqueItems": true,
"items": {
"type": "string"
},
"description": "List of warnings warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in te problems panel.",
"default": []
} }
} }
}, },