From 656e95211edf26bd82bd66f53ca3bcdfb7296e81 Mon Sep 17 00:00:00 2001 From: Gabriel Valfridsson Date: Tue, 16 Jun 2020 22:26:33 +0200 Subject: [PATCH] Warnings as hint or info --- crates/rust-analyzer/src/config.rs | 5 + crates/rust-analyzer/src/diagnostics.rs | 6 + ...s__snap_rustc_unused_variable_as_hint.snap | 86 +++++++ ...s__snap_rustc_unused_variable_as_info.snap | 86 +++++++ .../rust-analyzer/src/diagnostics/to_proto.rs | 213 ++++++++++++++++-- crates/rust-analyzer/src/main_loop.rs | 1 + editors/code/package.json | 18 ++ 7 files changed, 402 insertions(+), 13 deletions(-) create mode 100644 crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_hint.snap create mode 100644 crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_info.snap diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 0e7a937a07..0df7427cb9 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -9,6 +9,7 @@ use std::{ffi::OsString, path::PathBuf}; +use crate::diagnostics::DiagnosticsConfig; use lsp_types::ClientCapabilities; use ra_flycheck::FlycheckConfig; use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig}; @@ -20,6 +21,7 @@ pub struct Config { pub client_caps: ClientCapsConfig, pub publish_diagnostics: bool, + pub diagnostics: DiagnosticsConfig, pub lru_capacity: Option, pub proc_macro_srv: Option<(PathBuf, Vec)>, pub files: FilesConfig, @@ -136,6 +138,7 @@ impl Default for Config { with_sysroot: true, publish_diagnostics: true, + diagnostics: DiagnosticsConfig::default(), lru_capacity: None, proc_macro_srv: None, files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() }, @@ -184,6 +187,8 @@ impl Config { set(value, "/withSysroot", &mut self.with_sysroot); 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); self.files.watcher = match get(value, "/files/watcher") { Some("client") => FilesWatcher::Client, diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs index 25856c5436..290609e7f9 100644 --- a/crates/rust-analyzer/src/diagnostics.rs +++ b/crates/rust-analyzer/src/diagnostics.rs @@ -10,6 +10,12 @@ use crate::lsp_ext; pub type CheckFixes = Arc>>; +#[derive(Debug, Default, Clone)] +pub struct DiagnosticsConfig { + pub warnings_as_info: Vec, + pub warnings_as_hint: Vec, +} + #[derive(Debug, Default, Clone)] pub struct DiagnosticCollection { pub native: HashMap>, diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_hint.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_hint.snap new file mode 100644 index 0000000000..f0273315e9 --- /dev/null +++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_hint.snap @@ -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, + }, + ), + }, + ], + }, +] diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_info.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_info.snap new file mode 100644 index 0000000000..85fd050fd7 --- /dev/null +++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_info.snap @@ -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, + }, + ), + }, + ], + }, +] diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index 24ff9b280a..ba74f15f3c 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -9,14 +9,24 @@ use lsp_types::{ use ra_flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion}; use stdx::format_to; +use super::DiagnosticsConfig; use crate::{lsp_ext, to_proto::url_from_abs_path}; -/// Converts a Rust level string to a LSP severity -fn map_level_to_severity(val: DiagnosticLevel) -> Option { - let res = match val { +/// Determines the LSP severity from a diagnostic +fn map_diagnostic_to_severity( + config: &DiagnosticsConfig, + val: &ra_flycheck::Diagnostic, +) -> Option { + let res = match val.level { DiagnosticLevel::Ice => 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::Help => DiagnosticSeverity::Hint, DiagnosticLevel::Unknown => return None, @@ -172,6 +182,7 @@ pub(crate) struct MappedRustDiagnostic { /// /// If the diagnostic has no primary span this will return `None` pub(crate) fn map_rust_diagnostic_to_lsp( + config: &DiagnosticsConfig, rd: &ra_flycheck::Diagnostic, workspace_root: &Path, ) -> Vec { @@ -180,7 +191,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( 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 code = rd.code.as_ref().map(|c| c.code.clone()); @@ -328,7 +339,7 @@ mod tests { ); 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); } @@ -410,7 +421,183 @@ mod tests { ); 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); } @@ -534,7 +721,7 @@ mod tests { ); 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); } @@ -654,7 +841,7 @@ mod tests { ); 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); } @@ -697,7 +884,7 @@ mod tests { ); 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); } @@ -968,7 +1155,7 @@ mod tests { ); 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); } @@ -1197,7 +1384,7 @@ mod tests { ); 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); } @@ -1330,7 +1517,7 @@ mod tests { ); 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); } } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index cc9bb1726e..534d9f2231 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -734,6 +734,7 @@ fn on_check_task( CheckTask::AddDiagnostic { workspace_root, diagnostic } => { let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( + &global_state.config.diagnostics, &diagnostic, &workspace_root, ); diff --git a/editors/code/package.json b/editors/code/package.json index e2027970db..3acc375f67 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -525,6 +525,24 @@ "markdownDescription": "Internal config for debugging, disables loading of sysroot crates", "type": "boolean", "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": [] } } },